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:
committed by
Android (Google) Code Review
commit
7a6c7ba69b
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user