Return the existing display ids when registering a display window listener

- This ensures that the caller can synchronously initialize the existing
  displays without waiting for the onDisplayAdded() callback, which can
  happen asynchronously (since the callback is oneway).

Bug: 196186963
Test: atest WMShellUnitTests
Test: atest ActivityTaskManagerServiceTests
Change-Id: I0a8d5f9b4ede7b487a8de14bdb6eaacae7d03d9f
This commit is contained in:
Winson Chung
2021-08-31 16:45:48 -07:00
parent f9387616af
commit 851f1df2f1
8 changed files with 34 additions and 32 deletions

View File

@@ -32,7 +32,8 @@ import android.content.res.Configuration;
oneway interface IDisplayWindowListener {
/**
* Called when a display is added to the WM hierarchy.
* Called when a new display is added to the WM hierarchy. The existing display ids are returned
* when this listener is registered with WM via {@link #registerDisplayWindowListener}.
*/
void onDisplayAdded(int displayId);

View File

@@ -521,9 +521,10 @@ interface IWindowManager
void unregisterDisplayFoldListener(IDisplayFoldListener listener);
/**
* Registers an IDisplayContainerListener
* Registers an IDisplayContainerListener, and returns the set of existing display ids. The
* listener's onDisplayAdded() will not be called for the displays returned.
*/
void registerDisplayWindowListener(IDisplayWindowListener listener);
int[] registerDisplayWindowListener(IDisplayWindowListener listener);
/**
* Unregisters an IDisplayContainerListener.

View File

@@ -67,7 +67,10 @@ public class DisplayController {
*/
public void initialize() {
try {
mWmService.registerDisplayWindowListener(mDisplayContainerListener);
int[] displayIds = mWmService.registerDisplayWindowListener(mDisplayContainerListener);
for (int i = 0; i < displayIds.length; i++) {
onDisplayAdded(displayIds[i]);
}
} catch (RemoteException e) {
throw new RuntimeException("Unable to register display controller");
}

View File

@@ -731,24 +731,12 @@ public class ShellTransitionTests {
IWindowManager mockWM = mock(IWindowManager.class);
final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
try {
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) {
displayListener[0] = invocation.getArgument(0);
return null;
}
}).when(mockWM).registerDisplayWindowListener(any());
doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
} catch (RemoteException e) {
// No remote stuff happening, so this can't be hit
}
DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
out.initialize();
try {
displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
mMainExecutor.flushAll();
} catch (RemoteException e) {
// Again, no remote stuff
}
return out;
}

View File

@@ -692,8 +692,11 @@ public class CameraServiceProxy extends SystemService
}
try {
WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
mDisplayWindowListener);
int[] displayIds = WindowManagerGlobal.getWindowManagerService()
.registerDisplayWindowListener(mDisplayWindowListener);
for (int i = 0; i < displayIds.length; i++) {
mDisplayWindowListener.onDisplayAdded(displayIds[i]);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to register display window listener!");
}

View File

@@ -19,6 +19,7 @@ package com.android.server.wm;
import android.content.res.Configuration;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.IntArray;
import android.view.IDisplayWindowListener;
/**
@@ -28,23 +29,20 @@ import android.view.IDisplayWindowListener;
class DisplayWindowListenerController {
RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>();
// private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>();
private final WindowManagerService mService;
DisplayWindowListenerController(WindowManagerService service) {
mService = service;
}
void registerListener(IDisplayWindowListener listener) {
int[] registerListener(IDisplayWindowListener listener) {
synchronized (mService.mGlobalLock) {
mDisplayListeners.register(listener);
try {
for (int i = 0; i < mService.mAtmService.mRootWindowContainer.getChildCount();
++i) {
DisplayContent d = mService.mAtmService.mRootWindowContainer.getChildAt(i);
listener.onDisplayAdded(d.mDisplayId);
}
} catch (RemoteException e) { }
final IntArray displayIds = new IntArray();
mService.mAtmService.mRootWindowContainer.forAllDisplays((displayContent) -> {
displayIds.add(displayContent.mDisplayId);
});
return displayIds.toArray();
}
}

View File

@@ -4340,13 +4340,18 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
/** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */
/**
* Registers a hierarchy listener that gets callbacks when the hierarchy changes. The listener's
* onDisplayAdded() will not be called for the displays returned.
*
* @return the displayIds for the existing displays
*/
@Override
public void registerDisplayWindowListener(IDisplayWindowListener listener) {
public int[] registerDisplayWindowListener(IDisplayWindowListener listener) {
mAtmService.enforceTaskPermission("registerDisplayWindowListener");
final long ident = Binder.clearCallingIdentity();
try {
mDisplayNotificationController.registerListener(listener);
return mDisplayNotificationController.registerListener(listener);
} finally {
Binder.restoreCallingIdentity(ident);
}

View File

@@ -173,7 +173,10 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
@Override
public void onFixedRotationFinished(int displayId) {}
};
mAtm.mWindowManager.registerDisplayWindowListener(listener);
int[] displayIds = mAtm.mWindowManager.registerDisplayWindowListener(listener);
for (int i = 0; i < displayIds.length; i++) {
added.add(displayIds[i]);
}
// Check that existing displays call added
assertEquals(mRootWindowContainer.getChildCount(), added.size());
assertEquals(0, changed.size());