Merge "Input: Override touchable region bounds with surface bounds 1/2"
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index ec79eea..16a6412 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -18,9 +18,12 @@
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 @@
// 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 @@
// 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 @@
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());
+ }
+ }
}
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index eb71052..a1d1d4f 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -31,6 +31,11 @@
namespace android {
+struct WeakRefHandleField {
+ jfieldID handle;
+ jmethodID get;
+};
+
static struct {
jfieldID ptr;
jfieldID inputApplicationHandle;
@@ -57,6 +62,8 @@
jfieldID inputFeatures;
jfieldID displayId;
jfieldID portalToDisplayId;
+ jfieldID replaceTouchableRegionWithCrop;
+ WeakRefHandleField touchableRegionCropHandle;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -90,6 +97,7 @@
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 @@
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 @@
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 @@
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;
}