Merge "Make Activites touch opaque - DO NOT MERGE" into rvc-dev

This commit is contained in:
Linus Tufvesson
2022-07-01 08:53:41 +00:00
committed by Android (Google) Code Review
2 changed files with 126 additions and 0 deletions

View File

@@ -673,6 +673,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
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 =
(matrix, translation) -> mWmService.mH.post(() -> {
synchronized (mWmService.mGlobalLock) {
@@ -1650,6 +1657,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
}
mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
}
/**
@@ -3170,6 +3179,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
void removeImmediately() {
onRemovedFromDisplay();
mActivityRecordInputSink.releaseSurfaceControl();
super.removeImmediately();
}
@@ -6036,6 +6046,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else if (!show && mLastSurfaceShowing) {
getSyncTransaction().hide(mSurfaceControl);
}
if (show) {
mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction());
}
}
if (mThumbnail != null) {
mThumbnail.setShowing(getPendingTransaction(), show);

View File

@@ -0,0 +1,113 @@
/*
* 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;
}
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;
}
}
}