Make Activites touch opaque - DO NOT MERGE
Block touches from passing through activities by adding a dedicated surface that consumes all touches that would otherwise pass through the bounds availble to the Activity. + Keep displayId in sync for ActivityRecord Bug: 194480991 Test: atest CtsWindowManagerDeviceTestCases:ActivityRecordInputSinkTests Test: atest CtsWindowManagerDeviceTestCases:CrossAppDragAndDropTests Test: atest CtsWindowManagerDeviceTestCases:PinnedStackTests Test: Used "System > Developer Options > Simulate secondary display" to test that moving activites between displays work as intended. Change-Id: Idace4104c2708ce99309fa54fd44dd000e7f8894
This commit is contained in:
@@ -673,6 +673,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
|
|
||||||
private AppSaturationInfo mLastAppSaturationInfo;
|
private AppSaturationInfo mLastAppSaturationInfo;
|
||||||
|
|
||||||
|
private final ActivityRecordInputSink mActivityRecordInputSink;
|
||||||
|
|
||||||
|
// Activities with this uid are allowed to not create an input sink while being in the same
|
||||||
|
// task and directly above this ActivityRecord. This field is updated whenever a new activity
|
||||||
|
// is launched from this ActivityRecord. Touches are always allowed within the same uid.
|
||||||
|
int mAllowedTouchUid;
|
||||||
|
|
||||||
private final ColorDisplayService.ColorTransformController mColorTransformController =
|
private final ColorDisplayService.ColorTransformController mColorTransformController =
|
||||||
(matrix, translation) -> mWmService.mH.post(() -> {
|
(matrix, translation) -> mWmService.mH.post(() -> {
|
||||||
synchronized (mWmService.mGlobalLock) {
|
synchronized (mWmService.mGlobalLock) {
|
||||||
@@ -1650,6 +1657,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
|
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
|
||||||
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
|
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3170,6 +3179,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
@Override
|
@Override
|
||||||
void removeImmediately() {
|
void removeImmediately() {
|
||||||
onRemovedFromDisplay();
|
onRemovedFromDisplay();
|
||||||
|
mActivityRecordInputSink.releaseSurfaceControl();
|
||||||
super.removeImmediately();
|
super.removeImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6036,6 +6046,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
} else if (!show && mLastSurfaceShowing) {
|
} else if (!show && mLastSurfaceShowing) {
|
||||||
getSyncTransaction().hide(mSurfaceControl);
|
getSyncTransaction().hide(mSurfaceControl);
|
||||||
}
|
}
|
||||||
|
if (show) {
|
||||||
|
mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mThumbnail != null) {
|
if (mThumbnail != null) {
|
||||||
mThumbnail.setShowing(getPendingTransaction(), show);
|
mThumbnail.setShowing(getPendingTransaction(), show);
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.os.Process;
|
||||||
|
import android.view.InputWindowHandle;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a InputWindowHandle that catches all touches that would otherwise pass through an
|
||||||
|
* Activity.
|
||||||
|
*/
|
||||||
|
class ActivityRecordInputSink {
|
||||||
|
|
||||||
|
private final ActivityRecord mActivityRecord;
|
||||||
|
private final String mName;
|
||||||
|
|
||||||
|
private InputWindowHandle mInputWindowHandle;
|
||||||
|
private SurfaceControl mSurfaceControl;
|
||||||
|
|
||||||
|
ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) {
|
||||||
|
mActivityRecord = activityRecord;
|
||||||
|
mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
|
||||||
|
+ mActivityRecord.mActivityComponent.flattenToShortString();
|
||||||
|
if (sourceRecord != null) {
|
||||||
|
sourceRecord.mAllowedTouchUid = mActivityRecord.getUid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
|
||||||
|
boolean windowHandleChanged = updateInputWindowHandle();
|
||||||
|
if (mSurfaceControl == null) {
|
||||||
|
mSurfaceControl = createSurface(transaction);
|
||||||
|
}
|
||||||
|
if (windowHandleChanged) {
|
||||||
|
transaction.setInputWindowInfo(mSurfaceControl, mInputWindowHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SurfaceControl createSurface(SurfaceControl.Transaction t) {
|
||||||
|
SurfaceControl surfaceControl = mActivityRecord.makeChildSurface(null)
|
||||||
|
.setName(mName)
|
||||||
|
.setHidden(false)
|
||||||
|
.setCallsite("ActivityRecordInputSink.createSurface")
|
||||||
|
.build();
|
||||||
|
// Put layer below all siblings (and the parent surface too)
|
||||||
|
t.setLayer(surfaceControl, Integer.MIN_VALUE);
|
||||||
|
return surfaceControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean updateInputWindowHandle() {
|
||||||
|
boolean changed = false;
|
||||||
|
if (mInputWindowHandle == null) {
|
||||||
|
mInputWindowHandle = createInputWindowHandle();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
// Don't block touches from passing through to an activity below us in the same task, if
|
||||||
|
// that activity is either from the same uid or if that activity has launched an activity
|
||||||
|
// in our uid.
|
||||||
|
final ActivityRecord activityBelowInTask =
|
||||||
|
mActivityRecord.getTask().getActivityBelow(mActivityRecord);
|
||||||
|
final boolean allowPassthrough = activityBelowInTask != null && (
|
||||||
|
activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
|
||||||
|
|| activityBelowInTask.isUid(mActivityRecord.getUid()));
|
||||||
|
boolean notTouchable = (mInputWindowHandle.layoutParamsFlags
|
||||||
|
& WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0;
|
||||||
|
if (allowPassthrough || mActivityRecord.isAppTransitioning()) {
|
||||||
|
mInputWindowHandle.layoutParamsFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
|
changed |= !notTouchable;
|
||||||
|
} else {
|
||||||
|
mInputWindowHandle.layoutParamsFlags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||||
|
changed |= notTouchable;
|
||||||
|
}
|
||||||
|
if (mInputWindowHandle.displayId != mActivityRecord.getDisplayId()) {
|
||||||
|
mInputWindowHandle.displayId = mActivityRecord.getDisplayId();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputWindowHandle createInputWindowHandle() {
|
||||||
|
InputWindowHandle inputWindowHandle = new InputWindowHandle(null,
|
||||||
|
mActivityRecord.getDisplayId());
|
||||||
|
inputWindowHandle.replaceTouchableRegionWithCrop = true;
|
||||||
|
inputWindowHandle.name = mName;
|
||||||
|
inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
|
||||||
|
inputWindowHandle.ownerUid = Process.myUid();
|
||||||
|
inputWindowHandle.ownerPid = Process.myPid();
|
||||||
|
inputWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
|
inputWindowHandle.inputFeatures =
|
||||||
|
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
|
||||||
|
return inputWindowHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseSurfaceControl() {
|
||||||
|
if (mSurfaceControl != null) {
|
||||||
|
mSurfaceControl.release();
|
||||||
|
mSurfaceControl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user