Reduce unnecessary invocation of setInputWindowInfo
Usually most fields of InputWindowHandle don't change frequently.
Therefore, only the changed instances need to be updated. That
reduces the overhead of JNI invocation (especially
NativeInputWindowHandle::updateInfo which may be called from
setInputWindowInfo).
There should be no behavior change.
- Add a InputWindowHandle.ChangeDetectionWrapper to wrap the original
handle. So the changes of its fields can be tracked.
- Make InputApplicationHandle java side immutable. Its content should
be rarely changed. Then it is easier to compare by instance. This
might also reduces the race condition of accessing its field from
InputDispatcher because the instance is different.
- Move some fields that won't change of InputWindowHandle to the
constructor of WindowState to reduce unnecessary updates.
- When a window cannot receive input, reuse the per-window input
window handle to populate the disabled info, so there won't be a
shared instance that its fields always need to be updated.
- Reduce unnecessary Region#translate if the offsets are zero.
- For a simple activity launch, the invocation amount of
setInputWindowInfo is reduced 90% (from 126 to 11).
- The metrics updateInputWindows_mean of WmPerfTests is reduced 50%+
(from 0.89ms to 0.38ms on an old mid-end device).
Bug: 168008622
Test: WindowStateTests#testUpdateInputWindowHandle
WindowInputTests InternalWindowOperationPerfTest
Change-Id: Ief84bbe6e6fa4da5309912059904932ccf775b75
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
@@ -31,17 +32,20 @@ public final class InputApplicationHandle {
|
||||
private long ptr;
|
||||
|
||||
// Application name.
|
||||
public String name;
|
||||
public final @NonNull String name;
|
||||
|
||||
// Dispatching timeout.
|
||||
public long dispatchingTimeoutMillis;
|
||||
public final long dispatchingTimeoutMillis;
|
||||
|
||||
public final IBinder token;
|
||||
public final @NonNull IBinder token;
|
||||
|
||||
private native void nativeDispose();
|
||||
|
||||
public InputApplicationHandle(IBinder token) {
|
||||
public InputApplicationHandle(@NonNull IBinder token, @NonNull String name,
|
||||
long dispatchingTimeoutMillis) {
|
||||
this.token = token;
|
||||
this.name = name;
|
||||
this.dispatchingTimeoutMillis = dispatchingTimeoutMillis;
|
||||
}
|
||||
|
||||
public InputApplicationHandle(InputApplicationHandle handle) {
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class InputWindowHandle {
|
||||
private long ptr;
|
||||
|
||||
// The input application handle.
|
||||
public final InputApplicationHandle inputApplicationHandle;
|
||||
public InputApplicationHandle inputApplicationHandle;
|
||||
|
||||
// The token associates input data with a window and its input channel. The client input
|
||||
// channel and the server input channel will both contain this token.
|
||||
|
||||
@@ -54,26 +54,28 @@ jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEn
|
||||
|
||||
bool NativeInputApplicationHandle::updateInfo() {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
jobject obj = env->NewLocalRef(mObjWeak);
|
||||
if (!obj) {
|
||||
ScopedLocalRef<jobject> obj(env, env->NewLocalRef(mObjWeak));
|
||||
if (!obj.get()) {
|
||||
return false;
|
||||
}
|
||||
if (mInfo.token.get() != nullptr) {
|
||||
// The java fields are immutable, so it doesn't need to update again.
|
||||
return true;
|
||||
}
|
||||
|
||||
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
|
||||
mInfo.name = getStringField(env, obj.get(), gInputApplicationHandleClassInfo.name, "<null>");
|
||||
|
||||
mInfo.dispatchingTimeoutMillis =
|
||||
env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
|
||||
env->GetLongField(obj.get(), gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
|
||||
|
||||
jobject tokenObj = env->GetObjectField(obj,
|
||||
gInputApplicationHandleClassInfo.token);
|
||||
if (tokenObj) {
|
||||
mInfo.token = ibinderForJavaObject(env, tokenObj);
|
||||
env->DeleteLocalRef(tokenObj);
|
||||
ScopedLocalRef<jobject> tokenObj(env, env->GetObjectField(obj.get(),
|
||||
gInputApplicationHandleClassInfo.token));
|
||||
if (tokenObj.get()) {
|
||||
mInfo.token = ibinderForJavaObject(env, tokenObj.get());
|
||||
} else {
|
||||
mInfo.token.clear();
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(obj);
|
||||
return mInfo.token.get() != nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -417,7 +417,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// mOccludesParent field.
|
||||
final boolean hasWallpaper;
|
||||
// Input application handle used by the input dispatcher.
|
||||
final InputApplicationHandle mInputApplicationHandle;
|
||||
private InputApplicationHandle mInputApplicationHandle;
|
||||
|
||||
final int launchedFromPid; // always the pid who started the activity.
|
||||
final int launchedFromUid; // always the uid who started the activity.
|
||||
@@ -1506,7 +1506,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
info = aInfo;
|
||||
mUserId = UserHandle.getUserId(info.applicationInfo.uid);
|
||||
packageName = info.applicationInfo.packageName;
|
||||
mInputApplicationHandle = new InputApplicationHandle(appToken);
|
||||
intent = _intent;
|
||||
|
||||
// If the class name in the intent doesn't match that of the target, this is probably an
|
||||
@@ -1693,6 +1692,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return lockTaskLaunchMode;
|
||||
}
|
||||
|
||||
@NonNull InputApplicationHandle getInputApplicationHandle(boolean update) {
|
||||
if (mInputApplicationHandle == null) {
|
||||
mInputApplicationHandle = new InputApplicationHandle(appToken, toString(),
|
||||
mInputDispatchingTimeoutMillis);
|
||||
} else if (update) {
|
||||
final String name = toString();
|
||||
if (mInputDispatchingTimeoutMillis != mInputApplicationHandle.dispatchingTimeoutMillis
|
||||
|| !name.equals(mInputApplicationHandle.name)) {
|
||||
mInputApplicationHandle = new InputApplicationHandle(appToken, name,
|
||||
mInputDispatchingTimeoutMillis);
|
||||
}
|
||||
}
|
||||
return mInputApplicationHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
ActivityRecord asActivityRecord() {
|
||||
// I am an activity record!
|
||||
|
||||
@@ -277,9 +277,8 @@ class DragState {
|
||||
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
|
||||
mService.mH.getLooper(), mDragDropController);
|
||||
|
||||
mDragApplicationHandle = new InputApplicationHandle(new Binder());
|
||||
mDragApplicationHandle.name = "drag";
|
||||
mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
|
||||
mDragApplicationHandle = new InputApplicationHandle(new Binder(), "drag",
|
||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
|
||||
|
||||
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
|
||||
display.getDisplayId());
|
||||
|
||||
@@ -175,11 +175,11 @@ class EmbeddedWindowController {
|
||||
|
||||
InputApplicationHandle getApplicationHandle() {
|
||||
if (mHostWindowState == null
|
||||
|| mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) {
|
||||
|| mHostWindowState.mInputWindowHandle.getInputApplicationHandle() == null) {
|
||||
return null;
|
||||
}
|
||||
return new InputApplicationHandle(
|
||||
mHostWindowState.mInputWindowHandle.inputApplicationHandle);
|
||||
mHostWindowState.mInputWindowHandle.getInputApplicationHandle());
|
||||
}
|
||||
|
||||
InputChannel openInputChannel() {
|
||||
|
||||
@@ -63,9 +63,8 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
|
||||
mClientChannel.copyTo(inputChannel);
|
||||
}
|
||||
|
||||
mApplicationHandle = new InputApplicationHandle(new Binder());
|
||||
mApplicationHandle.name = name;
|
||||
mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
|
||||
mApplicationHandle = new InputApplicationHandle(new Binder(), name,
|
||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
|
||||
|
||||
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
|
||||
mWindowHandle.name = name;
|
||||
@@ -160,9 +159,11 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
|
||||
public void binderDied() {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
// Clean up the input consumer
|
||||
final InputMonitor inputMonitor =
|
||||
mService.mRoot.getDisplayContent(mWindowHandle.displayId).getInputMonitor();
|
||||
inputMonitor.destroyInputConsumer(mName);
|
||||
final DisplayContent dc = mService.mRoot.getDisplayContent(mWindowHandle.displayId);
|
||||
if (dc == null) {
|
||||
return;
|
||||
}
|
||||
dc.getInputMonitor().destroyInputConsumer(mName);
|
||||
unlinkFromDeathRecipient();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
@@ -57,12 +58,12 @@ import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.EventLog;
|
||||
import android.util.Slog;
|
||||
import android.view.InputApplicationHandle;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputEventReceiver;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -81,7 +82,7 @@ final class InputMonitor {
|
||||
private boolean mUpdateInputWindowsImmediately;
|
||||
|
||||
private boolean mDisableWallpaperTouchEvents;
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final Region mTmpRegion = new Region();
|
||||
private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
|
||||
|
||||
private final int mDisplayId;
|
||||
@@ -276,66 +277,66 @@ final class InputMonitor {
|
||||
addInputConsumer(name, consumer);
|
||||
}
|
||||
|
||||
|
||||
void populateInputWindowHandle(final InputWindowHandle inputWindowHandle,
|
||||
final WindowState child, int flags, final int type, final boolean isVisible,
|
||||
final boolean focusable, final boolean hasWallpaper) {
|
||||
@VisibleForTesting
|
||||
void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle,
|
||||
final WindowState w) {
|
||||
// Add a window to our list of input windows.
|
||||
inputWindowHandle.name = child.toString();
|
||||
flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
|
||||
inputWindowHandle.layoutParamsFlags = flags;
|
||||
inputWindowHandle.layoutParamsType = type;
|
||||
inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
|
||||
inputWindowHandle.visible = isVisible;
|
||||
inputWindowHandle.focusable = focusable;
|
||||
inputWindowHandle.touchOcclusionMode = child.getTouchOcclusionMode();
|
||||
inputWindowHandle.hasWallpaper = hasWallpaper;
|
||||
inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
|
||||
inputWindowHandle.ownerPid = child.mSession.mPid;
|
||||
inputWindowHandle.ownerUid = child.mSession.mUid;
|
||||
inputWindowHandle.packageName = child.getOwningPackage();
|
||||
inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
|
||||
inputWindowHandle.displayId = child.getDisplayId();
|
||||
inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null
|
||||
? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null);
|
||||
inputWindowHandle.setToken(w.mInputChannelToken);
|
||||
inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
|
||||
inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
|
||||
inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
|
||||
inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
|
||||
inputWindowHandle.setVisible(w.isVisible());
|
||||
|
||||
final Rect frame = child.getFrame();
|
||||
inputWindowHandle.frameLeft = frame.left;
|
||||
inputWindowHandle.frameTop = frame.top;
|
||||
inputWindowHandle.frameRight = frame.right;
|
||||
inputWindowHandle.frameBottom = frame.bottom;
|
||||
final boolean focusable = w.canReceiveKeys()
|
||||
&& (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
|
||||
inputWindowHandle.setFocusable(focusable);
|
||||
|
||||
final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
|
||||
&& !mService.mPolicy.isKeyguardShowing()
|
||||
&& !mDisableWallpaperTouchEvents;
|
||||
inputWindowHandle.setHasWallpaper(hasWallpaper);
|
||||
|
||||
final Rect frame = w.getFrame();
|
||||
inputWindowHandle.setFrame(frame.left, frame.top, frame.right, frame.bottom);
|
||||
|
||||
// Surface insets are hardcoded to be the same in all directions
|
||||
// and we could probably deprecate the "left/right/top/bottom" concept.
|
||||
// we avoid reintroducing this concept by just choosing one of them here.
|
||||
inputWindowHandle.surfaceInset = child.getAttrs().surfaceInsets.left;
|
||||
inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left);
|
||||
|
||||
/**
|
||||
* If the window is in a TaskManaged by a TaskOrganizer then most cropping
|
||||
* will be applied using the SurfaceControl hierarchy from the Organizer.
|
||||
* This means we need to make sure that these changes in crop are reflected
|
||||
* in the input windows, and so ensure this flag is set so that
|
||||
* the input crop always reflects the surface hierarchy.
|
||||
*
|
||||
* TODO(b/168252846): we have some issues with modal-windows, so we need to
|
||||
* cross that bridge now that we organize full-screen Tasks.
|
||||
*/
|
||||
if (child.getTask() != null
|
||||
&& child.getTask().isOrganized()
|
||||
&& child.getTask().getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
|
||||
inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
|
||||
// If we are scaling the window, input coordinates need to be inversely scaled to map from
|
||||
// what is on screen to what is actually being touched in the UI.
|
||||
inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f);
|
||||
|
||||
final int flags = w.getSurfaceTouchableRegion(mTmpRegion, w.mAttrs.flags);
|
||||
inputWindowHandle.setTouchableRegion(mTmpRegion);
|
||||
inputWindowHandle.setLayoutParamsFlags(flags);
|
||||
|
||||
boolean useSurfaceCrop = false;
|
||||
final Task task = w.getTask();
|
||||
if (task != null) {
|
||||
if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
|
||||
// If the window is in a TaskManaged by a TaskOrganizer then most cropping will
|
||||
// be applied using the SurfaceControl hierarchy from the Organizer. This means
|
||||
// we need to make sure that these changes in crop are reflected in the input
|
||||
// windows, and so ensure this flag is set so that the input crop always reflects
|
||||
// the surface hierarchy.
|
||||
// TODO(b/168252846): we have some issues with modal-windows, so we need to cross
|
||||
// that bridge now that we organize full-screen Tasks.
|
||||
inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
|
||||
useSurfaceCrop = true;
|
||||
} else if (task.cropWindowsToStackBounds() && !w.inFreeformWindowingMode()) {
|
||||
inputWindowHandle.replaceTouchableRegionWithCrop(
|
||||
task.getRootTask().getSurfaceControl());
|
||||
useSurfaceCrop = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (child.mGlobalScale != 1) {
|
||||
// If we are scaling the window, input coordinates need
|
||||
// to be inversely scaled to map from what is on screen
|
||||
// to what is actually being touched in the UI.
|
||||
inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
|
||||
} else {
|
||||
inputWindowHandle.scaleFactor = 1;
|
||||
}
|
||||
|
||||
if (DEBUG_INPUT) {
|
||||
Slog.d(TAG_WM, "addInputWindowHandle: "
|
||||
+ child + ", " + inputWindowHandle);
|
||||
if (!useSurfaceCrop) {
|
||||
inputWindowHandle.setReplaceTouchableRegionWithCrop(false);
|
||||
inputWindowHandle.setTouchableRegionCrop(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,15 +402,8 @@ final class InputMonitor {
|
||||
|
||||
public void setFocusedAppLw(ActivityRecord newApp) {
|
||||
// Focused app has changed.
|
||||
if (newApp == null) {
|
||||
mService.mInputManager.setFocusedApplication(mDisplayId, null);
|
||||
} else {
|
||||
final InputApplicationHandle handle = newApp.mInputApplicationHandle;
|
||||
handle.name = newApp.toString();
|
||||
handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
|
||||
|
||||
mService.mInputManager.setFocusedApplication(mDisplayId, handle);
|
||||
}
|
||||
mService.mInputManager.setFocusedApplication(mDisplayId,
|
||||
newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
|
||||
}
|
||||
|
||||
public void pauseDispatchingLw(WindowToken window) {
|
||||
@@ -456,10 +450,6 @@ final class InputMonitor {
|
||||
private boolean mAddRecentsAnimationInputConsumerHandle;
|
||||
|
||||
boolean mInDrag;
|
||||
WallpaperController mWallpaperController;
|
||||
|
||||
// An invalid window handle that tells SurfaceFlinger not update the input info.
|
||||
final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, mDisplayId);
|
||||
|
||||
private void updateInputWindows(boolean inDrag) {
|
||||
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
|
||||
@@ -474,10 +464,8 @@ final class InputMonitor {
|
||||
mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
|
||||
mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
|
||||
|
||||
mTmpRect.setEmpty();
|
||||
mDisableWallpaperTouchEvents = false;
|
||||
mInDrag = inDrag;
|
||||
mWallpaperController = mDisplayContent.mWallpaperController;
|
||||
|
||||
resetInputConsumers(mInputTransaction);
|
||||
|
||||
@@ -499,7 +487,7 @@ final class InputMonitor {
|
||||
}
|
||||
|
||||
final WindowState focus = mDisplayContent.mCurrentFocus;
|
||||
if (focus == null || focus.mInputWindowHandle.token == null) {
|
||||
if (focus == null || focus.mInputChannelToken == null) {
|
||||
mDisplayContent.mLastRequestedFocus = focus;
|
||||
return;
|
||||
}
|
||||
@@ -510,7 +498,7 @@ final class InputMonitor {
|
||||
return;
|
||||
}
|
||||
|
||||
mInputTransaction.setFocusedWindow(focus.mInputWindowHandle.token, mDisplayId);
|
||||
mInputTransaction.setFocusedWindow(focus.mInputChannelToken, mDisplayId);
|
||||
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
|
||||
"Focus request " + focus, "reason=UpdateInputWindows");
|
||||
mDisplayContent.mLastRequestedFocus = focus;
|
||||
@@ -519,33 +507,26 @@ final class InputMonitor {
|
||||
|
||||
@Override
|
||||
public void accept(WindowState w) {
|
||||
final InputChannel inputChannel = w.mInputChannel;
|
||||
final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
|
||||
final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
|
||||
final RecentsAnimationController recentsAnimationController =
|
||||
mService.getRecentsAnimationController();
|
||||
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
|
||||
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
|
||||
final int type = w.mAttrs.type;
|
||||
final boolean isVisible = w.isVisibleLw();
|
||||
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
|
||||
if (w.mInputChannelToken == null || w.mRemoved
|
||||
|| (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
|
||||
if (w.mWinAnimator.hasSurface()) {
|
||||
// Assign an InputInfo with type to the overlay window which can't receive input
|
||||
// event. This is used to omit Surfaces from occlusion detection.
|
||||
populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
|
||||
mInputTransaction.setInputWindowInfo(
|
||||
w.mWinAnimator.mSurfaceController.mSurfaceControl,
|
||||
mInvalidInputWindow);
|
||||
populateOverlayInputInfo(inputWindowHandle, w.isVisible());
|
||||
setInputWindowInfoIfNeeded(mInputTransaction,
|
||||
w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
|
||||
return;
|
||||
}
|
||||
// Skip this window because it cannot possibly receive input.
|
||||
return;
|
||||
}
|
||||
|
||||
final int flags = w.mAttrs.flags;
|
||||
final int privateFlags = w.mAttrs.privateFlags;
|
||||
final boolean focusable = w.canReceiveKeys()
|
||||
&& (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
|
||||
|
||||
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
|
||||
if (recentsAnimationController.updateInputConsumerForApp(
|
||||
@@ -584,47 +565,53 @@ final class InputMonitor {
|
||||
if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
|
||||
mDisableWallpaperTouchEvents = true;
|
||||
}
|
||||
final boolean hasWallpaper = mWallpaperController.isWallpaperTarget(w)
|
||||
&& !mService.mPolicy.isKeyguardShowing()
|
||||
&& !mDisableWallpaperTouchEvents;
|
||||
|
||||
// If there's a drag in progress and 'child' is a potential drop target,
|
||||
// make sure it's been told about the drag
|
||||
if (mInDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
|
||||
if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) {
|
||||
mService.mDragDropController.sendDragStartedIfNeededLocked(w);
|
||||
}
|
||||
|
||||
populateInputWindowHandle(
|
||||
inputWindowHandle, w, flags, type, isVisible, focusable, hasWallpaper);
|
||||
|
||||
// register key interception info
|
||||
mService.mKeyInterceptionInfoForToken.put(inputWindowHandle.token,
|
||||
mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken,
|
||||
w.getKeyInterceptionInfo());
|
||||
|
||||
if (w.mWinAnimator.hasSurface()) {
|
||||
mInputTransaction.setInputWindowInfo(
|
||||
populateInputWindowHandle(inputWindowHandle, w);
|
||||
setInputWindowInfoIfNeeded(mInputTransaction,
|
||||
w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
|
||||
InputWindowHandleWrapper inputWindowHandle) {
|
||||
if (DEBUG_INPUT) {
|
||||
Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
|
||||
}
|
||||
if (inputWindowHandle.isChanged()) {
|
||||
inputWindowHandle.applyChangesToSurface(t, sc);
|
||||
}
|
||||
}
|
||||
|
||||
// This would reset InputWindowHandle fields to prevent it could be found by input event.
|
||||
// We need to check if any new field of InputWindowHandle could impact the result.
|
||||
private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
|
||||
final String name, final int type, final boolean isVisible) {
|
||||
inputWindowHandle.name = name;
|
||||
inputWindowHandle.layoutParamsType = type;
|
||||
inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
|
||||
inputWindowHandle.visible = isVisible;
|
||||
inputWindowHandle.focusable = false;
|
||||
inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
|
||||
inputWindowHandle.scaleFactor = 1;
|
||||
inputWindowHandle.layoutParamsFlags =
|
||||
FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
|
||||
inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
|
||||
inputWindowHandle.touchableRegion.setEmpty();
|
||||
@VisibleForTesting
|
||||
static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
|
||||
boolean isVisible) {
|
||||
inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input.
|
||||
inputWindowHandle.setVisible(isVisible);
|
||||
inputWindowHandle.setFocusable(false);
|
||||
inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL);
|
||||
// The input window handle without input channel must not have a token.
|
||||
inputWindowHandle.setToken(null);
|
||||
inputWindowHandle.setScaleFactor(1f);
|
||||
inputWindowHandle.setLayoutParamsFlags(
|
||||
FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
|
||||
inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY);
|
||||
inputWindowHandle.clearTouchableRegion();
|
||||
inputWindowHandle.setTouchableRegionCrop(null);
|
||||
inputWindowHandle.trustedOverlay = isTrustedOverlay(type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,9 +622,13 @@ final class InputMonitor {
|
||||
*/
|
||||
static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
|
||||
int displayId, String name) {
|
||||
InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
|
||||
populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
|
||||
t.setInputWindowInfo(sc, inputWindowHandle);
|
||||
final InputWindowHandleWrapper inputWindowHandle = new InputWindowHandleWrapper(
|
||||
new InputWindowHandle(null /* inputApplicationHandle */, displayId));
|
||||
inputWindowHandle.setName(name);
|
||||
inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
|
||||
inputWindowHandle.setTrustedOverlay(true);
|
||||
populateOverlayInputInfo(inputWindowHandle, true /* isVisible */);
|
||||
setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
|
||||
}
|
||||
|
||||
static boolean isTrustedOverlay(int type) {
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Region;
|
||||
import android.os.IBinder;
|
||||
import android.view.InputApplicationHandle;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary
|
||||
* updates to surface, e.g. if there are no changes, then skip invocation of
|
||||
* {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}.
|
||||
*/
|
||||
class InputWindowHandleWrapper {
|
||||
/** The wrapped handle should not be directly exposed to avoid untracked changes. */
|
||||
private final @NonNull InputWindowHandle mHandle;
|
||||
|
||||
/** Whether the {@link #mHandle} is changed. */
|
||||
private boolean mChanged = true;
|
||||
|
||||
InputWindowHandleWrapper(@NonNull InputWindowHandle handle) {
|
||||
mHandle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the input window handle has changed since the last invocation of
|
||||
* {@link #applyChangesToSurface(SurfaceControl.Transaction, SurfaceControl)}}
|
||||
*/
|
||||
boolean isChanged() {
|
||||
return mChanged;
|
||||
}
|
||||
|
||||
void forceChange() {
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
|
||||
t.setInputWindowInfo(sc, mHandle);
|
||||
mChanged = false;
|
||||
}
|
||||
|
||||
int getDisplayId() {
|
||||
return mHandle.displayId;
|
||||
}
|
||||
|
||||
InputApplicationHandle getInputApplicationHandle() {
|
||||
return mHandle.inputApplicationHandle;
|
||||
}
|
||||
|
||||
void setInputApplicationHandle(InputApplicationHandle handle) {
|
||||
if (mHandle.inputApplicationHandle == handle) {
|
||||
return;
|
||||
}
|
||||
mHandle.inputApplicationHandle = handle;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setToken(IBinder token) {
|
||||
if (mHandle.token == token) {
|
||||
return;
|
||||
}
|
||||
mHandle.token = token;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
if (Objects.equals(mHandle.name, name)) {
|
||||
return;
|
||||
}
|
||||
mHandle.name = name;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setLayoutParamsFlags(int flags) {
|
||||
if (mHandle.layoutParamsFlags == flags) {
|
||||
return;
|
||||
}
|
||||
mHandle.layoutParamsFlags = flags;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setLayoutParamsType(int type) {
|
||||
if (mHandle.layoutParamsType == type) {
|
||||
return;
|
||||
}
|
||||
mHandle.layoutParamsType = type;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setDispatchingTimeoutMillis(long timeout) {
|
||||
if (mHandle.dispatchingTimeoutMillis == timeout) {
|
||||
return;
|
||||
}
|
||||
mHandle.dispatchingTimeoutMillis = timeout;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setTouchableRegion(Region region) {
|
||||
if (mHandle.touchableRegion.equals(region)) {
|
||||
return;
|
||||
}
|
||||
mHandle.touchableRegion.set(region);
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void clearTouchableRegion() {
|
||||
if (mHandle.touchableRegion.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mHandle.touchableRegion.setEmpty();
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setVisible(boolean visible) {
|
||||
if (mHandle.visible == visible) {
|
||||
return;
|
||||
}
|
||||
mHandle.visible = visible;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setFocusable(boolean focusable) {
|
||||
if (mHandle.focusable == focusable) {
|
||||
return;
|
||||
}
|
||||
mHandle.focusable = focusable;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setTouchOcclusionMode(int mode) {
|
||||
if (mHandle.touchOcclusionMode == mode) {
|
||||
return;
|
||||
}
|
||||
mHandle.touchOcclusionMode = mode;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setHasWallpaper(boolean hasWallpaper) {
|
||||
if (mHandle.hasWallpaper == hasWallpaper) {
|
||||
return;
|
||||
}
|
||||
mHandle.hasWallpaper = hasWallpaper;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setPaused(boolean paused) {
|
||||
if (mHandle.paused == paused) {
|
||||
return;
|
||||
}
|
||||
mHandle.paused = paused;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setTrustedOverlay(boolean trustedOverlay) {
|
||||
if (mHandle.trustedOverlay == trustedOverlay) {
|
||||
return;
|
||||
}
|
||||
mHandle.trustedOverlay = trustedOverlay;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setOwnerPid(int pid) {
|
||||
if (mHandle.ownerPid == pid) {
|
||||
return;
|
||||
}
|
||||
mHandle.ownerPid = pid;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setOwnerUid(int uid) {
|
||||
if (mHandle.ownerUid == uid) {
|
||||
return;
|
||||
}
|
||||
mHandle.ownerUid = uid;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setPackageName(String packageName) {
|
||||
if (Objects.equals(mHandle.packageName, packageName)) {
|
||||
return;
|
||||
}
|
||||
mHandle.packageName = packageName;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setInputFeatures(int features) {
|
||||
if (mHandle.inputFeatures == features) {
|
||||
return;
|
||||
}
|
||||
mHandle.inputFeatures = features;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setDisplayId(int displayId) {
|
||||
if (mHandle.displayId == displayId) {
|
||||
return;
|
||||
}
|
||||
mHandle.displayId = displayId;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setPortalToDisplayId(int displayId) {
|
||||
if (mHandle.portalToDisplayId == displayId) {
|
||||
return;
|
||||
}
|
||||
mHandle.portalToDisplayId = displayId;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setFrame(int left, int top, int right, int bottom) {
|
||||
if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
|
||||
&& mHandle.frameBottom == bottom) {
|
||||
return;
|
||||
}
|
||||
mHandle.frameLeft = left;
|
||||
mHandle.frameTop = top;
|
||||
mHandle.frameRight = right;
|
||||
mHandle.frameBottom = bottom;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setSurfaceInset(int inset) {
|
||||
if (mHandle.surfaceInset == inset) {
|
||||
return;
|
||||
}
|
||||
mHandle.surfaceInset = inset;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setScaleFactor(float scale) {
|
||||
if (mHandle.scaleFactor == scale) {
|
||||
return;
|
||||
}
|
||||
mHandle.scaleFactor = scale;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) {
|
||||
setTouchableRegionCrop(bounds);
|
||||
setReplaceTouchableRegionWithCrop(true);
|
||||
}
|
||||
|
||||
void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
|
||||
if (mHandle.touchableRegionSurfaceControl.get() == bounds) {
|
||||
return;
|
||||
}
|
||||
mHandle.setTouchableRegionCrop(bounds);
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
void setReplaceTouchableRegionWithCrop(boolean replace) {
|
||||
if (mHandle.replaceTouchableRegionWithCrop == replace) {
|
||||
return;
|
||||
}
|
||||
mHandle.replaceTouchableRegionWithCrop = replace;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mHandle + ", changed=" + mChanged;
|
||||
}
|
||||
}
|
||||
@@ -225,10 +225,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
|
||||
mClientChannel, mService.mAnimationHandler.getLooper(),
|
||||
mService.mAnimator.getChoreographer());
|
||||
|
||||
mDragApplicationHandle = new InputApplicationHandle(new Binder());
|
||||
mDragApplicationHandle.name = TAG;
|
||||
mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
|
||||
|
||||
mDragApplicationHandle = new InputApplicationHandle(new Binder(), TAG,
|
||||
DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
|
||||
|
||||
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
|
||||
displayContent.getDisplayId());
|
||||
|
||||
@@ -8365,7 +8365,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
embeddedWindow.getName());
|
||||
return;
|
||||
}
|
||||
t.requestFocusTransfer(newFocusTarget.mInputWindowHandle.token, targetInputToken,
|
||||
t.requestFocusTransfer(newFocusTarget.mInputChannelToken, targetInputToken,
|
||||
displayId).apply();
|
||||
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
|
||||
"Transfer focus request " + newFocusTarget,
|
||||
|
||||
@@ -555,9 +555,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
boolean mWindowRemovalAllowed;
|
||||
|
||||
// Input channel and input window handle used by the input dispatcher.
|
||||
final InputWindowHandle mInputWindowHandle;
|
||||
final InputWindowHandleWrapper mInputWindowHandle;
|
||||
InputChannel mInputChannel;
|
||||
|
||||
/**
|
||||
* The token will be assigned to {@link InputWindowHandle#token} if this window can receive
|
||||
* input event. Note that the token of associated input window handle can be cleared if this
|
||||
* window becomes unable to receive input, but this field will remain until the input channel
|
||||
* is actually disposed.
|
||||
*/
|
||||
IBinder mInputChannelToken;
|
||||
|
||||
// Used to improve performance of toString()
|
||||
private String mStringNameCache;
|
||||
private CharSequence mLastTitle;
|
||||
@@ -855,6 +863,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
DeathRecipient deathRecipient = new DeathRecipient();
|
||||
mPowerManagerWrapper = powerManagerWrapper;
|
||||
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
|
||||
mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
|
||||
mActivityRecord != null
|
||||
? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
|
||||
getDisplayId()));
|
||||
mInputWindowHandle.setOwnerPid(s.mPid);
|
||||
mInputWindowHandle.setOwnerUid(s.mUid);
|
||||
mInputWindowHandle.setName(getName());
|
||||
mInputWindowHandle.setPackageName(mAttrs.packageName);
|
||||
mInputWindowHandle.setLayoutParamsType(mAttrs.type);
|
||||
// Check private trusted overlay flag and window type to set trustedOverlay variable of
|
||||
// input window handle.
|
||||
mInputWindowHandle.setTrustedOverlay(
|
||||
((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
|
||||
&& mOwnerCanAddInternalSystemWindow)
|
||||
|| InputMonitor.isTrustedOverlay(mAttrs.type));
|
||||
if (DEBUG) {
|
||||
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
|
||||
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
|
||||
@@ -870,7 +893,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
mIsFloatingLayer = false;
|
||||
mBaseLayer = 0;
|
||||
mSubLayer = 0;
|
||||
mInputWindowHandle = null;
|
||||
mWinAnimator = null;
|
||||
mWpcForDisplayConfigChanges = null;
|
||||
return;
|
||||
@@ -918,16 +940,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
mLastRequestedWidth = 0;
|
||||
mLastRequestedHeight = 0;
|
||||
mLayer = 0;
|
||||
mInputWindowHandle = new InputWindowHandle(
|
||||
mActivityRecord != null ? mActivityRecord.mInputApplicationHandle : null,
|
||||
getDisplayId());
|
||||
|
||||
// Check private trusted overlay flag and window type to set trustedOverlay variable of
|
||||
// input window handle.
|
||||
mInputWindowHandle.trustedOverlay =
|
||||
(mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
|
||||
&& mOwnerCanAddInternalSystemWindow;
|
||||
mInputWindowHandle.trustedOverlay |= InputMonitor.isTrustedOverlay(mAttrs.type);
|
||||
|
||||
// Make sure we initial all fields before adding to parentWindow, to prevent exception
|
||||
// during onDisplayChanged.
|
||||
@@ -1495,9 +1507,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
super.onDisplayChanged(dc);
|
||||
// Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
|
||||
if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) {
|
||||
if (dc != null && mInputWindowHandle.getDisplayId() != dc.getDisplayId()) {
|
||||
mLayoutSeq = dc.mLayoutSeq - 1;
|
||||
mInputWindowHandle.displayId = dc.getDisplayId();
|
||||
mInputWindowHandle.setDisplayId(dc.getDisplayId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2469,7 +2481,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
String name = getName();
|
||||
mInputChannel = mWmService.mInputManager.createInputChannel(name);
|
||||
mInputWindowHandle.token = mInputChannel.getToken();
|
||||
mInputChannelToken = mInputChannel.getToken();
|
||||
mInputWindowHandle.setToken(mInputChannelToken);
|
||||
mWmService.mInputToWindowMap.put(mInputChannelToken, this);
|
||||
if (outInputChannel != null) {
|
||||
mInputChannel.copyTo(outInputChannel);
|
||||
} else {
|
||||
@@ -2478,7 +2492,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
// Create fake event receiver that simply reports all events as handled.
|
||||
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
|
||||
}
|
||||
mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
|
||||
}
|
||||
|
||||
void disposeInputChannel() {
|
||||
@@ -2486,17 +2499,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
mDeadWindowEventReceiver.dispose();
|
||||
mDeadWindowEventReceiver = null;
|
||||
}
|
||||
if (mInputChannelToken != null) {
|
||||
// Unregister server channel first otherwise it complains about broken channel.
|
||||
mWmService.mInputManager.removeInputChannel(mInputChannelToken);
|
||||
mWmService.mKeyInterceptionInfoForToken.remove(mInputChannelToken);
|
||||
mWmService.mInputToWindowMap.remove(mInputChannelToken);
|
||||
mInputChannelToken = null;
|
||||
}
|
||||
|
||||
// unregister server channel first otherwise it complains about broken channel
|
||||
if (mInputChannel != null) {
|
||||
mWmService.mInputManager.removeInputChannel(mInputChannel.getToken());
|
||||
|
||||
mInputChannel.dispose();
|
||||
mInputChannel = null;
|
||||
}
|
||||
mWmService.mKeyInterceptionInfoForToken.remove(mInputWindowHandle.token);
|
||||
mWmService.mInputToWindowMap.remove(mInputWindowHandle.token);
|
||||
mInputWindowHandle.token = null;
|
||||
mInputWindowHandle.setToken(null);
|
||||
}
|
||||
|
||||
/** Returns true if the replacement window was removed. */
|
||||
@@ -2566,11 +2581,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
}
|
||||
|
||||
int getSurfaceTouchableRegion(InputWindowHandle inputWindowHandle, int flags) {
|
||||
int getSurfaceTouchableRegion(Region region, int flags) {
|
||||
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
|
||||
final Region region = inputWindowHandle.touchableRegion;
|
||||
setTouchableRegionCropIfNeeded(inputWindowHandle);
|
||||
|
||||
if (modal) {
|
||||
flags |= FLAG_NOT_TOUCH_MODAL;
|
||||
if (mActivityRecord != null) {
|
||||
@@ -2592,7 +2604,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
|
||||
// Translate to surface based coordinates.
|
||||
region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
|
||||
final Rect frame = mWindowFrames.mFrame;
|
||||
if (frame.left != 0 || frame.top != 0) {
|
||||
region.translate(-frame.left, -frame.top);
|
||||
}
|
||||
|
||||
// TODO(b/139804591): sizecompat layout needs to be reworked. Currently mFrame is post-
|
||||
// scaling but the existing logic doesn't expect that. The result is that the already-
|
||||
@@ -3441,7 +3456,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
break;
|
||||
case TOUCHABLE_INSETS_REGION: {
|
||||
outRegion.set(mGivenTouchableRegion);
|
||||
outRegion.translate(frame.left, frame.top);
|
||||
if (frame.left != 0 || frame.top != 0) {
|
||||
outRegion.translate(frame.left, frame.top);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3468,22 +3485,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
||||
}
|
||||
}
|
||||
|
||||
private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
|
||||
final Task task = getTask();
|
||||
if (task == null || !task.cropWindowsToStackBounds()) {
|
||||
handle.setTouchableRegionCrop(null);
|
||||
return;
|
||||
}
|
||||
|
||||
final Task stack = task.getRootTask();
|
||||
if (stack == null || inFreeformWindowingMode()) {
|
||||
handle.setTouchableRegionCrop(null);
|
||||
return;
|
||||
}
|
||||
|
||||
handle.setTouchableRegionCrop(stack.getSurfaceControl());
|
||||
}
|
||||
|
||||
private void cropRegionToStackBoundsIfNeeded(Region region) {
|
||||
final Task task = getTask();
|
||||
if (task == null || !task.cropWindowsToStackBounds()) {
|
||||
|
||||
@@ -488,6 +488,9 @@ class WindowStateAnimator {
|
||||
mSurfaceFormat = format;
|
||||
|
||||
w.setHasSurface(true);
|
||||
// The surface instance is changed. Make sure the input info can be applied to the
|
||||
// new surface, e.g. relaunch activity.
|
||||
w.mInputWindowHandle.forceChange();
|
||||
|
||||
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
|
||||
" CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x / %s",
|
||||
|
||||
@@ -63,15 +63,18 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.Size;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.InputWindowHandle;
|
||||
import android.view.InsetsState;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
@@ -466,10 +469,10 @@ public class WindowStateTests extends WindowTestsBase {
|
||||
public void testDisplayIdUpdatedOnReparent() {
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
// fake a different display
|
||||
app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
|
||||
app.mInputWindowHandle.setDisplayId(mDisplayContent.getDisplayId() + 1);
|
||||
app.onDisplayChanged(mDisplayContent);
|
||||
|
||||
assertThat(app.mInputWindowHandle.displayId, is(mDisplayContent.getDisplayId()));
|
||||
assertThat(app.mInputWindowHandle.getDisplayId(), is(mDisplayContent.getDisplayId()));
|
||||
assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
|
||||
}
|
||||
|
||||
@@ -680,6 +683,54 @@ public class WindowStateTests extends WindowTestsBase {
|
||||
assertFalse(win0.canReceiveTouchInput());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInputWindowHandle() {
|
||||
final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
|
||||
win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
|
||||
final InputWindowHandle handle = new InputWindowHandle(
|
||||
win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId());
|
||||
final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle);
|
||||
final IBinder inputChannelToken = mock(IBinder.class);
|
||||
win.mInputChannelToken = inputChannelToken;
|
||||
|
||||
mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
|
||||
|
||||
assertTrue(handleWrapper.isChanged());
|
||||
assertEquals(inputChannelToken, handle.token);
|
||||
assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */),
|
||||
handle.inputApplicationHandle);
|
||||
assertEquals(win.mAttrs.inputFeatures, handle.inputFeatures);
|
||||
assertEquals(win.isVisible(), handle.visible);
|
||||
|
||||
final SurfaceControl sc = mock(SurfaceControl.class);
|
||||
final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction;
|
||||
InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
|
||||
|
||||
// The fields of input window handle are changed, so it must set input window info
|
||||
// successfully. And then the changed flag should be reset.
|
||||
verify(transaction).setInputWindowInfo(eq(sc), eq(handle));
|
||||
assertFalse(handleWrapper.isChanged());
|
||||
// Populate the same states again, the handle should not detect change.
|
||||
mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
|
||||
assertFalse(handleWrapper.isChanged());
|
||||
|
||||
// Apply the no change handle, the invocation of setInputWindowInfo should be skipped.
|
||||
clearInvocations(transaction);
|
||||
InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
|
||||
verify(transaction, never()).setInputWindowInfo(any(), any());
|
||||
|
||||
// Populate as an overlay to disable the input of window.
|
||||
InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
|
||||
// The overlay attributes should be set.
|
||||
assertTrue(handleWrapper.isChanged());
|
||||
assertFalse(handle.focusable);
|
||||
assertFalse(handle.visible);
|
||||
assertNull(handle.token);
|
||||
assertEquals(0L, handle.dispatchingTimeoutMillis);
|
||||
assertEquals(WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL,
|
||||
handle.inputFeatures);
|
||||
}
|
||||
|
||||
@UseTestDisplay(addWindows = W_ACTIVITY)
|
||||
@Test
|
||||
public void testNeedsRelativeLayeringToIme_notAttached() {
|
||||
|
||||
Reference in New Issue
Block a user