From 716ac1c2a93970c96bbff7d067abf74c465b89ea Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Mon, 10 Oct 2022 23:15:49 +0000 Subject: [PATCH] SurfaceControlViewHost: Expose transferTouchGesture API. A key feature of SurfaceControlViewHost is that touches are given directly to the embedded View hierarchy, however in some cases this can interfere with the seamlessness of embedding. For example if we are not clicking on an embedded element but in fact intending to scroll its container. Allowing transferring the current touch gesture to the host provides a way to solve this problem. We expose this through a SurfaceControlViewHost specific API in order to restrict scope and avoid sharing of any new tokens. Bug: 256993188 Change-Id: If94dbe4b862b6a159f2c0baee55dcb8c82c22e37 --- core/java/android/view/IWindowSession.aidl | 2 ++ .../android/view/SurfaceControlViewHost.java | 25 +++++++++++++-- .../android/view/WindowlessWindowManager.java | 7 ++++ .../java/com/android/server/wm/Session.java | 16 ++++++++++ .../server/wm/WindowManagerService.java | 32 +++++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index e4d878a59c118..6672db6e90182 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -353,4 +353,6 @@ interface IWindowSession { * Returns whether this window needs to cancel draw and retry later. */ boolean cancelDraw(IWindow window); + + boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow); } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 50ce7b634e99c..134625e18f7b0 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -194,7 +194,7 @@ public class SurfaceControlViewHost { * is more akin to a PopupWindow in that the size is user specified * independent of configuration width and height. * - * In order to receive the configuration change via + * In order to receive the configuration change via * {@link View#onConfigurationChanged}, the context used with the * SurfaceControlViewHost and it's embedded view hierarchy must * be a WindowContext obtained from {@link Context#createWindowContext}. @@ -460,5 +460,26 @@ public class SurfaceControlViewHost { (WindowManagerImpl) mViewRoot.mContext.getSystemService(Context.WINDOW_SERVICE); attrs.token = wm.getDefaultToken(); } -} + /** + * Transfer the currently in progress touch gesture to the parent + * (if any) of this SurfaceControlViewHost. This requires that the + * SurfaceControlViewHost was created with an associated hostInputToken. + * + * @return Whether the touch stream was transferred. + * @hide + */ + public boolean transferTouchGestureToHost() { + if (mViewRoot == null) { + return false; + } + + final IWindowSession realWm = WindowManagerGlobal.getWindowSession(); + try { + return realWm.transferEmbeddedTouchFocusToHost(mViewRoot.mWindow); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + return false; + } +} diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 4c95728548c53..0258f5ae84b99 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -561,4 +561,11 @@ public class WindowlessWindowManager implements IWindowSession { public boolean cancelDraw(IWindow window) { return false; } + + @Override + public boolean transferEmbeddedTouchFocusToHost(IWindow window) { + Log.e(TAG, "Received request to transferEmbeddedTouch focus on WindowlessWindowManager" + + " we shouldn't get here!"); + return false; + } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 17b463febc13a..cf02dfa730360 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -909,6 +909,22 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } } + @Override + public boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) { + if (embeddedWindow == null) { + return false; + } + + final long identity = Binder.clearCallingIdentity(); + boolean didTransfer = false; + try { + didTransfer = mService.transferEmbeddedTouchFocusToHost(embeddedWindow); + } finally { + Binder.restoreCallingIdentity(identity); + } + return didTransfer; + } + @Override public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 70bedc71b9003..753e369e577de 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8669,6 +8669,38 @@ public class WindowManagerService extends IWindowManager.Stub clientChannel.copyTo(outInputChannel); } + boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow) { + final IBinder windowBinder = embeddedWindow.asBinder(); + final IBinder hostInputChannel, embeddedInputChannel; + synchronized (mGlobalLock) { + final EmbeddedWindowController.EmbeddedWindow ew = + mEmbeddedWindowController.getByWindowToken(windowBinder); + if (ew == null) { + Slog.w(TAG, "Attempt to transfer touch focus from non-existent embedded window"); + return false; + } + final WindowState hostWindowState = ew.getWindowState(); + if (hostWindowState == null) { + Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no" + + " associated host"); + return false; + } + embeddedInputChannel = ew.getInputChannelToken(); + if (embeddedInputChannel == null) { + Slog.w(TAG, "Attempt to transfer touch focus from embedded window with no input" + + " channel"); + return false; + } + hostInputChannel = hostWindowState.mInputChannelToken; + if (hostInputChannel == null) { + Slog.w(TAG, "Attempt to transfer touch focus to a host window with no" + + " input channel"); + return false; + } + return mInputManager.transferTouchFocus(embeddedInputChannel, hostInputChannel); + } + } + private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid, int displayId, SurfaceControl surface, String name, InputApplicationHandle applicationHandle, int flags,