Merge "Pass through some input-related layout flags for windowless surfaces"

This commit is contained in:
Evan Rosky
2020-02-04 00:23:58 +00:00
committed by Android (Google) Code Review
7 changed files with 144 additions and 46 deletions

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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 */