diff --git a/api/test-current.txt b/api/test-current.txt index df21368c2a493..c8d746b44a156 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4979,6 +4979,11 @@ package android.view { method public abstract String asyncImpl() default ""; } + public class SurfaceControlViewHost { + method public void addView(@NonNull android.view.View, android.view.WindowManager.LayoutParams); + method public void relayout(android.view.WindowManager.LayoutParams); + } + @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback { method public android.view.View getTooltipView(); method public boolean isAutofilled(); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 1677357dedbe5..91000a93b17c9 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -318,5 +318,11 @@ interface IWindowSession { * an input channel where the client can receive input. */ void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window, - in IBinder hostInputToken, out InputChannel outInputChannel); + in IBinder hostInputToken, int flags, out InputChannel outInputChannel); + + /** + * Update the flags on an input channel associated with a particular surface. + */ + void updateInputChannel(in IBinder channelToken, int displayId, in SurfaceControl surface, + int flags); } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 71cf051a4e086..bf848196454d9 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -138,6 +138,7 @@ public class SurfaceControlViewHost { /** * @hide */ + @TestApi public void addView(@NonNull View view, WindowManager.LayoutParams attrs) { mViewRoot.setView(view, attrs, null); } @@ -161,6 +162,7 @@ public class SurfaceControlViewHost { /** * @hide */ + @TestApi public void relayout(WindowManager.LayoutParams attrs) { mViewRoot.setLayoutParams(attrs, false); mViewRoot.setReportNextDraw(); diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 91778aaf51fda..62f3fa4f6ed4e 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -41,9 +41,14 @@ public class WindowlessWindowManager implements IWindowSession { private class State { SurfaceControl mSurfaceControl; WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); - State(SurfaceControl sc, WindowManager.LayoutParams p) { + int mDisplayId; + IBinder mInputChannelToken; + State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, + IBinder inputChannelToken) { mSurfaceControl = sc; mParams.copyFrom(p); + mDisplayId = displayId; + mInputChannelToken = inputChannelToken; } }; @@ -105,19 +110,23 @@ public class WindowlessWindowManager implements IWindowSession { .setFormat(attrs.format) .setName(attrs.getTitle().toString()); final SurfaceControl sc = b.build(); - synchronized (this) { - mStateForWindow.put(window.asBinder(), new State(sc, attrs)); - } if (((attrs.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) { try { - mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, outInputChannel); + mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, + outInputChannel); } catch (RemoteException e) { - Log.e(TAG, "Failed to bless surface: " + e); + Log.e(TAG, "Failed to grant input to surface: ", e); } } + final State state = new State(sc, attrs, displayId, + outInputChannel != null ? outInputChannel.getToken() : null); + synchronized (this) { + mStateForWindow.put(window.asBinder(), state); + } + return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } @@ -162,7 +171,7 @@ public class WindowlessWindowManager implements IWindowSession { DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { - State state = null; + final State state; synchronized (this) { state = mStateForWindow.get(window.asBinder()); } @@ -173,8 +182,9 @@ public class WindowlessWindowManager implements IWindowSession { SurfaceControl sc = state.mSurfaceControl; SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + int attrChanges = 0; if (inAttrs != null) { - state.mParams.copyFrom(inAttrs); + attrChanges = state.mParams.copyFrom(inAttrs); } WindowManager.LayoutParams attrs = state.mParams; @@ -197,6 +207,16 @@ public class WindowlessWindowManager implements IWindowSession { mergedConfiguration.setConfiguration(mConfiguration, mConfiguration); + if ((attrChanges & WindowManager.LayoutParams.FLAGS_CHANGED) != 0 + && state.mInputChannelToken != null) { + try { + mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc, + attrs.flags); + } catch (RemoteException e) { + Log.e(TAG, "Failed to update surface input channel: ", e); + } + } + return 0; } @@ -353,7 +373,12 @@ public class WindowlessWindowManager implements IWindowSession { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, - IBinder hostInputToken, InputChannel outInputChannel) { + IBinder hostInputToken, int flags, InputChannel outInputChannel) { + } + + @Override + public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { } @Override diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 0291017cd039b..884f7694d6486 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -20,8 +20,10 @@ package com.android.server.wm; import android.annotation.Nullable; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.view.IWindow; +import android.view.InputApplicationHandle; /** * Keeps track of embedded windows. @@ -44,21 +46,12 @@ class EmbeddedWindowController { * * @param inputToken input channel token passed in by the embedding process when it requests * the server to add an input channel to the embedded surface. - * @param window client token used to clean up the map if the embedding process dies - * @param hostWindowState input channel token belonging to the host window. This is needed to - * handle input callbacks to wm. It's used when raising ANR and when - * the user taps out side of the focused region on screen. This can be - * null if there is no host window. - * @param ownerUid calling uid - * @param ownerPid calling pid used for anr blaming + * @param embeddedWindow An {@link EmbeddedWindow} object to add to this controller. */ - void add(IBinder inputToken, IWindow window, @Nullable WindowState hostWindowState, - int ownerUid, int ownerPid) { - EmbeddedWindow embeddedWindow = new EmbeddedWindow(window, hostWindowState, ownerUid, - ownerPid); + void add(IBinder inputToken, EmbeddedWindow embeddedWindow) { try { mWindows.put(inputToken, embeddedWindow); - window.asBinder().linkToDeath(()-> { + embeddedWindow.mClient.asBinder().linkToDeath(()-> { synchronized (mWmLock) { mWindows.remove(inputToken); } @@ -101,6 +94,15 @@ class EmbeddedWindowController { final int mOwnerUid; final int mOwnerPid; + /** + * @param clientToken client token used to clean up the map if the embedding process dies + * @param hostWindowState input channel token belonging to the host window. This is needed + * to handle input callbacks to wm. It's used when raising ANR and + * when the user taps out side of the focused region on screen. This + * can be null if there is no host window. + * @param ownerUid calling uid + * @param ownerPid calling pid used for anr blaming + */ EmbeddedWindow(IWindow clientToken, WindowState hostWindowState, int ownerUid, int ownerPid) { mClient = clientToken; @@ -108,5 +110,21 @@ class EmbeddedWindowController { mOwnerUid = ownerUid; mOwnerPid = ownerPid; } + + String getName() { + final String hostWindowName = (mHostWindowState != null) + ? mHostWindowState.getWindowTag().toString() : "Internal"; + return "EmbeddedWindow{ u" + UserHandle.getUserId(mOwnerUid) + " " + hostWindowName + + "}"; + } + + InputApplicationHandle getApplicationHandle() { + if (mHostWindowState == null + || mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) { + return null; + } + return new InputApplicationHandle( + mHostWindowState.mInputWindowHandle.inputApplicationHandle); + } } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index ab1f34adbeeb1..9df42486580b4 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -622,7 +622,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void grantInputChannel(int displayId, SurfaceControl surface, - IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { + IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) { if (hostInputToken == null && !mCanAddInternalSystemWindow) { // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to // embedded windows without providing a host window input token @@ -631,8 +631,19 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final long identity = Binder.clearCallingIdentity(); try { - mService.grantInputChannel(mUid, mPid, displayId, surface, window, - hostInputToken, outInputChannel); + mService.grantInputChannel(mUid, mPid, displayId, surface, window, hostInputToken, + flags, outInputChannel); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { + final long identity = Binder.clearCallingIdentity(); + try { + mService.updateInputChannel(channelToken, displayId, surface, flags); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 98c584fc743a3..a5b99b0a26a3f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7814,40 +7814,52 @@ public class WindowManagerService extends IWindowManager.Stub * views. */ void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface, - IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { - InputApplicationHandle applicationHandle = null; + IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) { + final InputApplicationHandle applicationHandle; final String name; final InputChannel[] inputChannels; final InputChannel clientChannel; final InputChannel serverChannel; synchronized (mGlobalLock) { - final WindowState hostWindow = mInputToWindowMap.get(hostInputToken); - final String hostWindowName = (hostWindow != null) - ? hostWindow.getWindowTag().toString() : "Internal"; - name = "EmbeddedWindow{ u" + UserHandle.getUserId(callingUid) - + " " + hostWindowName + "}"; + EmbeddedWindowController.EmbeddedWindow win = + new EmbeddedWindowController.EmbeddedWindow(window, + mInputToWindowMap.get(hostInputToken), callingUid, callingPid); + name = win.getName(); inputChannels = InputChannel.openInputChannelPair(name); serverChannel = inputChannels[0]; clientChannel = inputChannels[1]; mInputManager.registerInputChannel(serverChannel); - mEmbeddedWindowController.add(serverChannel.getToken(), window, hostWindow, callingUid, - callingPid); - - if (hostWindow != null - && hostWindow.mInputWindowHandle.inputApplicationHandle != null) { - applicationHandle = new InputApplicationHandle( - hostWindow.mInputWindowHandle.inputApplicationHandle); + mEmbeddedWindowController.add(clientChannel.getToken(), win); + if (serverChannel.getToken() != clientChannel.getToken()) { + throw new IllegalStateException("Client and Server channel are expected to" + + "be the same"); } + + applicationHandle = win.getApplicationHandle(); } + updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface, + name, applicationHandle, flags); + clientChannel.transferTo(outInputChannel); clientChannel.dispose(); + // Prevent the java finalizer from breaking the input channel. But we won't + // do any further management so we just release the java ref and let the + // InputDispatcher hold the last ref. + serverChannel.release(); + } + private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid, + int displayId, SurfaceControl surface, String name, + InputApplicationHandle applicationHandle, int flags) { InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId); - h.token = serverChannel.getToken(); + h.token = channelToken; h.name = name; - h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + + final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE + | LayoutParams.FLAG_SLIPPERY); + h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags; h.layoutParamsType = 0; h.dispatchingTimeoutNanos = -1; h.canReceiveKeys = false; @@ -7862,15 +7874,34 @@ public class WindowManagerService extends IWindowManager.Stub h.replaceTouchableRegionWithCrop(null); - SurfaceSession s = new SurfaceSession(); SurfaceControl.Transaction t = mTransactionFactory.get(); t.setInputWindowInfo(surface, h); t.apply(); + t.close(); + } - // Prevent the java finalizer from breaking the input channel. But we won't - // do any further management so we just release the java ref and let the - // InputDispatcher hold the last ref. - serverChannel.release(); + /** + * Updates the flags on an existing surface's input channel. This assumes the surface provided + * is the one associated with the provided input-channel. If this isn't the case, behavior + * is undefined. + */ + void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, + int flags) { + final InputApplicationHandle applicationHandle; + final String name; + final EmbeddedWindowController.EmbeddedWindow win; + synchronized (mGlobalLock) { + win = mEmbeddedWindowController.get(channelToken); + if (win == null) { + Slog.e(TAG, "Couldn't find window for provided channelToken."); + return; + } + name = win.getName(); + applicationHandle = win.getApplicationHandle(); + } + + updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name, + applicationHandle, flags); } /** Return whether layer tracing is enabled */