Input: Override touchable region bounds with surface bounds 1/2

Take advantage of the surface flinger layer hierarchy to set touchable
region.

- Let a client set a surface touchable region to its own bounds.
- Let a client set a surface touchable region to another surface bounds.
- Let a client bound its touchable region to a surface.

Test: go/wm-smoke
Test: existing tests

Change-Id: Id5ef8b35f4779861c1537811a045a44ee2394fdf
This commit is contained in:
Vishnu Nair
2019-03-12 13:37:51 -07:00
parent 0304cf83ac
commit 40efb71f79
2 changed files with 84 additions and 1 deletions

View File

@@ -18,9 +18,12 @@ package android.view;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
import android.graphics.Region;
import android.os.IBinder;
import java.lang.ref.WeakReference;
/**
* Functions as a handle for a window that can receive input.
* Enables the native input dispatcher to refer indirectly to the window manager's window state.
@@ -38,7 +41,7 @@ public final class InputWindowHandle {
// The client window.
public final IWindow clientWindow;
// The token assosciated with the window.
// The token associated with the window.
public IBinder token;
// The window name.
@@ -98,6 +101,23 @@ public final class InputWindowHandle {
// transports the touch of this window to the display indicated by portalToDisplayId.
public int portalToDisplayId = INVALID_DISPLAY;
/**
* Crops the touchable region to the bounds of the surface provided.
*
* This can be used in cases where the window is not
* {@link android.view.WindowManager#FLAG_NOT_TOUCH_MODAL} but should be constrained to the
* bounds of a parent window. That is the window should receive touch events outside its
* window but be limited to its stack bounds, such as in the case of split screen.
*/
public WeakReference<IBinder> touchableRegionCropHandle = new WeakReference<>(null);
/**
* Replace {@link touchableRegion} with the bounds of {@link touchableRegionCropHandle}. If
* the handle is {@code null}, the bounds of the surface associated with this window is used
* as the touchable region.
*/
public boolean replaceTouchableRegionWithCrop;
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
@@ -127,4 +147,25 @@ public final class InputWindowHandle {
super.finalize();
}
}
/**
* Set the window touchable region to the bounds of {@link touchableRegionBounds} ignoring any
* touchable region provided.
*
* @param bounds surface to set the touchable region to. Set to {@code null} to set the bounds
* to the current surface.
*/
public void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) {
setTouchableRegionCrop(bounds);
replaceTouchableRegionWithCrop = true;
}
/**
* Crop the window touchable region to the bounds of the surface provided.
*/
public void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
if (bounds != null) {
touchableRegionCropHandle = new WeakReference<>(bounds.getHandle());
}
}
}

View File

@@ -31,6 +31,11 @@
namespace android {
struct WeakRefHandleField {
jfieldID handle;
jmethodID get;
};
static struct {
jfieldID ptr;
jfieldID inputApplicationHandle;
@@ -57,6 +62,8 @@ static struct {
jfieldID inputFeatures;
jfieldID displayId;
jfieldID portalToDisplayId;
jfieldID replaceTouchableRegionWithCrop;
WeakRefHandleField touchableRegionCropHandle;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -90,6 +97,7 @@ bool NativeInputWindowHandle::updateInfo() {
jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
if (tokenObj) {
mInfo.token = ibinderForJavaObject(env, tokenObj);
env->DeleteLocalRef(tokenObj);
} else {
mInfo.token.clear();
}
@@ -161,6 +169,24 @@ bool NativeInputWindowHandle::updateInfo() {
env->DeleteLocalRef(inputApplicationHandleObj);
}
mInfo.replaceTouchableRegionWithCrop = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop);
jobject handleObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.touchableRegionCropHandle.handle);
if (handleObj) {
// Promote java weak reference.
jobject strongHandleObj = env->CallObjectMethod(handleObj,
gInputWindowHandleClassInfo.touchableRegionCropHandle.get);
if (strongHandleObj) {
mInfo.touchableRegionCropHandle = ibinderForJavaObject(env, strongHandleObj);
env->DeleteLocalRef(strongHandleObj);
} else {
mInfo.touchableRegionCropHandle.clear();
}
env->DeleteLocalRef(handleObj);
}
env->DeleteLocalRef(obj);
return true;
}
@@ -220,6 +246,10 @@ static const JNINativeMethod gInputWindowHandleMethods[] = {
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
#define GET_METHOD_ID(var, clazz, methodName, methodSignature) \
var = env->GetMethodID(clazz, methodName, methodSignature); \
LOG_FATAL_IF(! (var), "Unable to find method " methodName);
int register_android_view_InputWindowHandle(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
@@ -303,6 +333,18 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
"portalToDisplayId", "I");
GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
"replaceTouchableRegionWithCrop", "Z");
jclass weakRefClazz;
FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
GET_METHOD_ID(gInputWindowHandleClassInfo.touchableRegionCropHandle.get, weakRefClazz,
"get", "()Ljava/lang/Object;")
GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionCropHandle.handle, clazz,
"touchableRegionCropHandle", "Ljava/lang/ref/WeakReference;");
return 0;
}