Merge changes from topic "windowInfo_transferFocus" into udc-dev

* changes:
  Add focusTransferTarget in WindowInfo
  Ensure each SCVH child window has a unique focus token.
This commit is contained in:
Chavi Weingarten
2023-03-31 17:20:22 +00:00
committed by Android (Google) Code Review
9 changed files with 111 additions and 114 deletions

View File

@@ -158,6 +158,14 @@ public final class InputWindowHandle {
*/
public Matrix transform;
/**
* The input token for the window to which focus should be transferred when this input window
* can be successfully focused. If null, this input window will not transfer its focus to
* any other window.
*/
@Nullable
public IBinder focusTransferTarget;
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle, int displayId) {
@@ -195,6 +203,7 @@ public final class InputWindowHandle {
transform = new Matrix();
transform.set(other.transform);
}
focusTransferTarget = other.focusTransferTarget;
}
@Override

View File

@@ -265,7 +265,7 @@ public final class SurfaceControl implements Parcelable {
int transformHint);
private static native void nativeRemoveCurrentInputFocus(long nativeObject, int displayId);
private static native void nativeSetFocusedWindow(long transactionObj, IBinder toToken,
String windowName, IBinder focusedToken, String focusedWindowName, int displayId);
String windowName, int displayId);
private static native void nativeSetFrameTimelineVsync(long transactionObj,
long frameTimelineVsyncId);
private static native void nativeAddJankDataListener(long nativeListener,
@@ -3604,28 +3604,7 @@ public final class SurfaceControl implements Parcelable {
*/
public Transaction setFocusedWindow(@NonNull IBinder token, String windowName,
int displayId) {
nativeSetFocusedWindow(mNativeObject, token, windowName,
null /* focusedToken */, null /* focusedWindowName */, displayId);
return this;
}
/**
* Set focus on the window identified by the input {@code token} if the window identified by
* the input {@code focusedToken} is currently focused. If the {@code focusedToken} does not
* have focus, the request is dropped.
*
* This is used by forward focus transfer requests from clients that host embedded windows,
* and want to transfer focus to/from them.
*
* @hide
*/
public Transaction requestFocusTransfer(@NonNull IBinder token,
String windowName,
@NonNull IBinder focusedToken,
String focusedWindowName,
int displayId) {
nativeSetFocusedWindow(mNativeObject, token, windowName, focusedToken,
focusedWindowName, displayId);
nativeSetFocusedWindow(mNativeObject, token, windowName, displayId);
return this;
}

View File

@@ -57,18 +57,16 @@ public class WindowlessWindowManager implements IWindowSession {
SurfaceControl mLeash;
Rect mFrame;
Rect mAttachedFrame;
IBinder mFocusGrantToken;
State(SurfaceControl sc, WindowManager.LayoutParams p,
int displayId, IBinder inputChannelToken, IWindow client, SurfaceControl leash,
Rect frame, Rect attachedFrame) {
State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, IWindow client,
SurfaceControl leash, Rect frame) {
mSurfaceControl = sc;
mParams.copyFrom(p);
mDisplayId = displayId;
mInputChannelToken = inputChannelToken;
mClient = client;
mLeash = leash;
mFrame = frame;
mAttachedFrame = attachedFrame;
}
};
@@ -182,45 +180,53 @@ public class WindowlessWindowManager implements IWindowSession {
.setParent(leash)
.build();
final State state = new State(sc, attrs, displayId, window, leash, /* frame= */ new Rect());
synchronized (this) {
State parentState = mStateForWindow.get(attrs.token);
if (parentState != null) {
state.mAttachedFrame = parentState.mFrame;
}
// Give the first window the mFocusGrantToken since that's the token the host can use
// to give focus to the embedded.
if (mStateForWindow.isEmpty()) {
state.mFocusGrantToken = mFocusGrantToken;
} else {
state.mFocusGrantToken = new Binder();
}
mStateForWindow.put(window.asBinder(), state);
}
if (state.mAttachedFrame == null) {
outAttachedFrame.set(0, 0, -1, -1);
} else {
outAttachedFrame.set(state.mAttachedFrame);
}
outSizeCompatScale[0] = 1f;
if (((attrs.inputFeatures &
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
if (mRealWm instanceof IWindowSession.Stub) {
mRealWm.grantInputChannel(displayId,
new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"),
window, mHostInputToken,
attrs.flags, attrs.privateFlags, attrs.inputFeatures, attrs.type,
attrs.token, mFocusGrantToken, attrs.getTitle().toString(),
window, mHostInputToken, attrs.flags, attrs.privateFlags,
attrs.inputFeatures, attrs.type,
attrs.token, state.mFocusGrantToken, attrs.getTitle().toString(),
outInputChannel);
} else {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
attrs.privateFlags, attrs.inputFeatures, attrs.type, attrs.token,
mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
state.mFocusGrantToken, attrs.getTitle().toString(), outInputChannel);
}
state.mInputChannelToken =
outInputChannel != null ? outInputChannel.getToken() : null;
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
}
}
final State state = new State(sc, attrs, displayId,
outInputChannel != null ? outInputChannel.getToken() : null, window,
leash, /* frame= */ new Rect(), /* attachedFrame= */ null);
Rect parentFrame = null;
synchronized (this) {
State parentState = mStateForWindow.get(attrs.token);
if (parentState != null) {
parentFrame = parentState.mFrame;
}
mStateForWindow.put(window.asBinder(), state);
}
state.mAttachedFrame = parentFrame;
if (parentFrame == null) {
outAttachedFrame.set(0, 0, -1, -1);
} else {
outAttachedFrame.set(parentFrame);
}
outSizeCompatScale[0] = 1f;
final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
WindowManagerGlobal.ADD_FLAG_USE_BLAST;

View File

@@ -74,6 +74,7 @@ static struct {
WeakRefHandleField touchableRegionSurfaceControl;
jfieldID transform;
jfieldID windowToken;
jfieldID focusTransferTarget;
} gInputWindowHandleClassInfo;
static struct {
@@ -216,6 +217,17 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.windowToken.clear();
}
ScopedLocalRef<jobject>
focusTransferTargetObj(env,
env->GetObjectField(obj,
gInputWindowHandleClassInfo
.focusTransferTarget));
if (focusTransferTargetObj.get()) {
mInfo.focusTransferTarget = ibinderForJavaObject(env, focusTransferTargetObj.get());
} else {
mInfo.focusTransferTarget.clear();
}
env->DeleteLocalRef(obj);
return true;
}
@@ -433,6 +445,9 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.windowToken, clazz, "windowToken",
"Landroid/os/IBinder;");
GET_FIELD_ID(gInputWindowHandleClassInfo.focusTransferTarget, clazz, "focusTransferTarget",
"Landroid/os/IBinder;");
jclass weakRefClazz;
FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");

View File

@@ -1820,17 +1820,11 @@ static void nativeRemoveCurrentInputFocus(JNIEnv* env, jclass clazz, jlong trans
}
static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionObj,
jobject toTokenObj, jstring windowNameJstr,
jobject focusedTokenObj, jstring focusedWindowNameJstr,
jint displayId) {
jobject toTokenObj, jstring windowNameJstr, jint displayId) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
if (toTokenObj == NULL) return;
sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
sp<IBinder> focusedToken;
if (focusedTokenObj != NULL) {
focusedToken = ibinderForJavaObject(env, focusedTokenObj);
}
FocusRequest request;
request.token = toToken;
@@ -1839,11 +1833,6 @@ static void nativeSetFocusedWindow(JNIEnv* env, jclass clazz, jlong transactionO
request.windowName = windowName.c_str();
}
request.focusedToken = focusedToken;
if (focusedWindowNameJstr != NULL) {
ScopedUtfChars focusedWindowName(env, focusedWindowNameJstr);
request.focusedWindowName = focusedWindowName.c_str();
}
request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
request.displayId = displayId;
transaction->setFocusedWindow(request);
@@ -2236,7 +2225,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeGetHandle },
{"nativeSetFixedTransformHint", "(JJI)V",
(void*)nativeSetFixedTransformHint},
{"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I)V",
{"nativeSetFocusedWindow", "(JLandroid/os/IBinder;Ljava/lang/String;I)V",
(void*)nativeSetFocusedWindow},
{"nativeRemoveCurrentInputFocus", "(JI)V",
(void*)nativeRemoveCurrentInputFocus},

View File

@@ -99,23 +99,6 @@ class EmbeddedWindowController {
}
}
WindowState getHostWindow(IBinder inputToken) {
EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
return embeddedWindow != null ? embeddedWindow.mHostWindowState : null;
}
boolean isOverlay(IBinder inputToken) {
EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
return embeddedWindow != null ? embeddedWindow.getIsOverlay() : false;
}
void setIsOverlay(IBinder focusGrantToken) {
EmbeddedWindow embeddedWindow = mWindowsByFocusToken.get(focusGrantToken);
if (embeddedWindow != null) {
embeddedWindow.setIsOverlay();
}
}
void remove(IWindow client) {
for (int i = mWindows.size() - 1; i >= 0; i--) {
EmbeddedWindow ew = mWindows.valueAt(i);
@@ -176,14 +159,15 @@ class EmbeddedWindowController {
public Session mSession;
InputChannel mInputChannel;
final int mWindowType;
// Track whether the EmbeddedWindow is a system hosted overlay via
// {@link OverlayHost}. In the case of client hosted overlays, the client
// view hierarchy will take care of invoking requestEmbeddedWindowFocus
// but for system hosted overlays we have to do this via tapOutsideDetection
// and this variable is mostly used for tracking that.
boolean mIsOverlay = false;
private IBinder mFocusGrantToken;
/**
* A unique token associated with the embedded window that can be used by the host window
* to request focus transfer to the embedded. This is not the input token since we don't
* want to give clients access to each others input token.
*/
private final IBinder mFocusGrantToken;
private boolean mIsFocusable;
/**
* @param session calling session to check ownership of the window
@@ -199,7 +183,8 @@ class EmbeddedWindowController {
*/
EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken,
WindowState hostWindowState, int ownerUid, int ownerPid, int windowType,
int displayId, IBinder focusGrantToken, String inputHandleName) {
int displayId, IBinder focusGrantToken, String inputHandleName,
boolean isFocusable) {
mSession = session;
mWmService = service;
mClient = clientToken;
@@ -214,6 +199,7 @@ class EmbeddedWindowController {
final String hostWindowName =
(mHostWindowState != null) ? "-" + mHostWindowState.getWindowTag().toString()
: "";
mIsFocusable = isFocusable;
mName = "Embedded{" + inputHandleName + hostWindowName + "}";
}
@@ -279,13 +265,6 @@ class EmbeddedWindowController {
return mOwnerUid;
}
void setIsOverlay() {
mIsOverlay = true;
}
boolean getIsOverlay() {
return mIsOverlay;
}
IBinder getFocusGrantToken() {
return mFocusGrantToken;
}
@@ -297,20 +276,33 @@ class EmbeddedWindowController {
return null;
}
void setIsFocusable(boolean isFocusable) {
mIsFocusable = isFocusable;
}
/**
* System hosted overlays need the WM to invoke grantEmbeddedWindowFocus and
* so we need to participate inside handlePointerDownOutsideFocus logic
* however client hosted overlays will rely on the hosting view hierarchy
* to grant and revoke focus, and so the server side logic is not needed.
* When an embedded window is touched when it's not currently focus, we need to switch
* focus to that embedded window unless the embedded window was marked as not focusable.
*/
@Override
public boolean receiveFocusFromTapOutside() {
return mIsOverlay;
return mIsFocusable;
}
private void handleTap(boolean grantFocus) {
if (mInputChannel != null) {
mWmService.grantEmbeddedWindowFocus(mSession, mFocusGrantToken, grantFocus);
if (mHostWindowState != null) {
mWmService.grantEmbeddedWindowFocus(mSession, mHostWindowState.mClient,
mFocusGrantToken, grantFocus);
if (grantFocus) {
// If granting focus to the embedded when tapped, we need to ensure the host
// gains focus as well or the transfer won't take effect since it requires
// the host to transfer the focus to the embedded.
mHostWindowState.handleTapOutsideFocusInsideSelf();
}
} else {
mWmService.grantEmbeddedWindowFocus(mSession, mFocusGrantToken, grantFocus);
}
}
}

View File

@@ -289,6 +289,14 @@ class InputWindowHandleWrapper {
mChanged = true;
}
void setFocusTransferTarget(IBinder toToken) {
if (mHandle.focusTransferTarget == toToken) {
return;
}
mHandle.focusTransferTarget = toToken;
mChanged = true;
}
@Override
public String toString() {
return mHandle + ", changed=" + mChanged;

View File

@@ -90,8 +90,6 @@ class TrustedOverlayHost {
requireOverlaySurfaceControl();
mOverlays.add(p);
mWmService.mEmbeddedWindowController.setIsOverlay(p.getInputToken());
SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
t.reparent(p.getSurfaceControl(), mSurfaceControl)
.show(p.getSurfaceControl());

View File

@@ -8624,7 +8624,8 @@ public class WindowManagerService extends IWindowManager.Stub
EmbeddedWindowController.EmbeddedWindow win =
new EmbeddedWindowController.EmbeddedWindow(session, this, window,
mInputToWindowMap.get(hostInputToken), callingUid, callingPid,
sanitizedType, displayId, focusGrantToken, inputHandleName);
sanitizedType, displayId, focusGrantToken, inputHandleName,
(flags & FLAG_NOT_FOCUSABLE) == 0);
clientChannel = win.openInputChannel();
mEmbeddedWindowController.add(clientChannel.getToken(), win);
applicationHandle = win.getApplicationHandle();
@@ -8745,6 +8746,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
name = win.toString();
applicationHandle = win.getApplicationHandle();
win.setIsFocusable((flags & FLAG_NOT_FOCUSABLE) == 0);
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
@@ -9022,24 +9024,23 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.e(TAG, "Embedded window does not belong to the host");
return;
}
SurfaceControl.Transaction t = mTransactionFactory.get();
if (grantFocus) {
t.requestFocusTransfer(embeddedWindow.getInputChannelToken(), embeddedWindow.toString(),
hostWindow.mInputChannel.getToken(),
hostWindow.getName(),
hostWindow.getDisplayId()).apply();
hostWindow.mInputWindowHandle.setFocusTransferTarget(
embeddedWindow.getInputChannelToken());
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + embeddedWindow,
"reason=grantEmbeddedWindowFocus(true)");
} else {
t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), hostWindow.getName(),
embeddedWindow.getInputChannelToken(),
embeddedWindow.toString(),
hostWindow.getDisplayId()).apply();
hostWindow.mInputWindowHandle.setFocusTransferTarget(null);
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + hostWindow,
"reason=grantEmbeddedWindowFocus(false)");
}
DisplayContent dc = mRoot.getDisplayContent(hostWindow.getDisplayId());
if (dc != null) {
dc.getInputMonitor().updateInputWindowsLw(true);
}
ProtoLog.v(WM_DEBUG_FOCUS, "grantEmbeddedWindowFocus win=%s grantFocus=%s",
embeddedWindow, grantFocus);
}