Fix WindowContext cannot add window with sub window type

Bug: 184717383
Test: atest WindowManagerServiceTests
Test: atest WindowContextTest

Change-Id: Ie523902a8ec1a1de96b961da1204bf7c923052be
This commit is contained in:
Charles Chen
2021-04-06 18:05:27 +08:00
parent ac8d924dc3
commit 4ca1b87fdb
3 changed files with 84 additions and 2 deletions

View File

@@ -17,6 +17,7 @@
package android.window;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -209,6 +210,38 @@ public class WindowContextTest {
mWms.removeWindowToken(existingToken, DEFAULT_DISPLAY);
}
@Test
public void testWindowContextAddViewWithSubWindowType_NotCrash() throws Throwable {
final WindowContext windowContext = createWindowContext(TYPE_INPUT_METHOD);
final WindowManager wm = windowContext.getSystemService(WindowManager.class);
// Create a WindowToken with system window type.
final IBinder existingToken = new Binder();
mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId(),
null /* options */);
final WindowManager.LayoutParams params =
new WindowManager.LayoutParams(TYPE_INPUT_METHOD);
params.token = existingToken;
final View parentWindow = new View(windowContext);
final AttachStateListener listener = new AttachStateListener();
parentWindow.addOnAttachStateChangeListener(listener);
// Add the parent window
mInstrumentation.runOnMainSync(() -> wm.addView(parentWindow, params));
assertTrue(listener.mLatch.await(4, TimeUnit.SECONDS));
final WindowManager.LayoutParams subWindowAttrs =
new WindowManager.LayoutParams(TYPE_APPLICATION_ATTACHED_DIALOG);
subWindowAttrs.token = parentWindow.getWindowToken();
final View subWindow = new View(windowContext);
// Add a window with sub-window type.
mInstrumentation.runOnMainSync(() -> wm.addView(subWindow, subWindowAttrs));
}
private WindowContext createWindowContext() {
return createWindowContext(TYPE_APPLICATION_OVERLAY);
}
@@ -219,4 +252,16 @@ public class WindowContextTest {
.getDisplay(DEFAULT_DISPLAY);
return (WindowContext) instContext.createWindowContext(display, type, null /* options */);
}
private static class AttachStateListener implements View.OnAttachStateChangeListener {
final CountDownLatch mLatch = new CountDownLatch(1);
@Override
public void onViewAttachedToWindow(View v) {
mLatch.countDown();
}
@Override
public void onViewDetachedFromWindow(View v) {}
}
}

View File

@@ -1740,8 +1740,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
// Switch to listen to the {@link WindowToken token}'s configuration changes when
// adding a window to the window context.
if (mWindowContextListenerController.hasListener(windowContextToken)) {
// adding a window to the window context. Filter sub window type here because the sub
// window must be attached to the parent window, which is attached to the window context
// created window token.
if (!win.isChildWindow()
&& mWindowContextListenerController.hasListener(windowContextToken)) {
final int windowContextType = mWindowContextListenerController
.getWindowType(windowContextToken);
if (type != windowContextType) {

View File

@@ -23,6 +23,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -50,7 +51,13 @@ import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.View;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -250,4 +257,31 @@ public class WindowManagerServiceTests extends WindowTestsBase {
eq(clientToken), eq(windowToken), anyInt(), eq(TYPE_INPUT_METHOD),
eq(windowToken.mOptions));
}
@Test
public void testAddWindowWithSubWindowTypeByWindowContext() {
spyOn(mWm.mWindowContextListenerController);
final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay);
final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float v) throws RemoteException {}
});
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
TYPE_APPLICATION_ATTACHED_DIALOG);
params.token = windowToken.token;
final IBinder windowContextToken = new Binder();
params.setWindowContextToken(windowContextToken);
doReturn(true).when(mWm.mWindowContextListenerController)
.hasListener(eq(windowContextToken));
doReturn(TYPE_INPUT_METHOD).when(mWm.mWindowContextListenerController)
.getWindowType(eq(windowContextToken));
mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY,
UserHandle.USER_SYSTEM, new InsetsState(), null, new InsetsState(),
new InsetsSourceControl[0]);
verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
any(), anyInt(), anyInt(), any());
}
}