summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-01-16 14:06:57 -0800
committerJeff Brown <jeffbrown@google.com>2011-01-16 18:58:49 -0800
commitfbf097732137a32930d151f7ba6816a5b870c32a (patch)
tree1f05823ea1cb06aaa3ab0954cdde614b370f30e6
parent115ad16551c9cf9551f44cbea59f3edf83e4a340 (diff)
downloadframeworks_base-fbf097732137a32930d151f7ba6816a5b870c32a.zip
frameworks_base-fbf097732137a32930d151f7ba6816a5b870c32a.tar.gz
frameworks_base-fbf097732137a32930d151f7ba6816a5b870c32a.tar.bz2
Support non-rectangular input regions.
This enables the system bar to carve out a region through which events will be sent to the IME behind it. Bug: 3238092 Change-Id: I69b855a8d9b5b3ee525266c0861826e53e5b5028
-rw-r--r--api/current.xml21
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java16
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java28
-rw-r--r--core/java/android/view/IWindowSession.aidl2
-rw-r--r--core/java/android/view/ViewRoot.java36
-rw-r--r--core/java/android/view/ViewTreeObserver.java36
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/Region.cpp33
-rw-r--r--core/jni/android/graphics/Region.h30
-rw-r--r--services/input/InputDispatcher.cpp34
-rw-r--r--services/input/InputWindow.cpp5
-rw-r--r--services/input/InputWindow.h13
-rw-r--r--services/java/com/android/server/InputWindow.java16
-rw-r--r--services/java/com/android/server/WindowManagerService.java125
-rw-r--r--services/jni/com_android_server_InputWindow.cpp62
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java2
16 files changed, 270 insertions, 191 deletions
diff --git a/api/current.xml b/api/current.xml
index 68d3187..78104b0 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -95568,6 +95568,17 @@
visibility="public"
>
</field>
+<field name="TOUCHABLE_INSETS_REGION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TOUCHABLE_INSETS_VISIBLE"
type="int"
transient="false"
@@ -95599,6 +95610,16 @@
visibility="public"
>
</field>
+<field name="touchableRegion"
+ type="android.graphics.Region"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="visibleTopInsets"
type="int"
transient="false"
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 406b091..6baf1c2 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -283,6 +283,7 @@ public class CompatibilityInfo {
private Rect mContentInsetsBuffer = null;
private Rect mVisibleInsetsBuffer = null;
+ private Region mTouchableAreaBuffer = null;
Translator(float applicationScale, float applicationInvertedScale) {
this.applicationScale = applicationScale;
@@ -395,14 +396,25 @@ public class CompatibilityInfo {
/**
* Translate the visible insets in application window to Screen. This uses
- * the internal buffer for content insets to avoid extra object allocation.
+ * the internal buffer for visible insets to avoid extra object allocation.
*/
- public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
+ public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
mVisibleInsetsBuffer.set(visibleInsets);
translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
return mVisibleInsetsBuffer;
}
+
+ /**
+ * Translate the touchable area in application window to Screen. This uses
+ * the internal buffer for touchable area to avoid extra object allocation.
+ */
+ public Region getTranslatedTouchableArea(Region touchableArea) {
+ if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
+ mTouchableAreaBuffer.set(touchableArea);
+ mTouchableAreaBuffer.scale(applicationScale);
+ return mTouchableAreaBuffer;
+ }
}
/**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 23b9ad5..4d25bac 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -25,6 +25,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ResultReceiver;
@@ -283,11 +284,13 @@ public class InputMethodService extends AbstractInputMethodService {
View decor = getWindow().getWindow().getDecorView();
info.contentInsets.top = info.visibleInsets.top
= decor.getHeight();
+ info.touchableRegion.setEmpty();
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
} else {
onComputeInsets(mTmpInsets);
info.contentInsets.top = mTmpInsets.contentTopInsets;
info.visibleInsets.top = mTmpInsets.visibleTopInsets;
+ info.touchableRegion.set(mTmpInsets.touchableRegion);
info.setTouchableInsets(mTmpInsets.touchableInsets);
}
}
@@ -510,7 +513,14 @@ public class InputMethodService extends AbstractInputMethodService {
* of the input method window.
*/
public int visibleTopInsets;
-
+
+ /**
+ * This is the region of the UI that is touchable. It is used when
+ * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+ * The region should be specified relative to the origin of the window frame.
+ */
+ public final Region touchableRegion = new Region();
+
/**
* Option for {@link #touchableInsets}: the entire window frame
* can be touched.
@@ -531,11 +541,19 @@ public class InputMethodService extends AbstractInputMethodService {
*/
public static final int TOUCHABLE_INSETS_VISIBLE
= ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-
+
+ /**
+ * Option for {@link #touchableInsets}: the region specified by
+ * {@link #touchableRegion} can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_REGION
+ = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
/**
* Determine which area of the window is touchable by the user. May
* be one of: {@link #TOUCHABLE_INSETS_FRAME},
- * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}.
+ * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
+ * or {@link #TOUCHABLE_INSETS_REGION}.
*/
public int touchableInsets;
}
@@ -950,6 +968,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
outInsets.visibleTopInsets = loc[1];
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
+ outInsets.touchableRegion.setEmpty();
}
/**
@@ -2153,6 +2172,7 @@ public class InputMethodService extends AbstractInputMethodService {
p.println("Last computed insets:");
p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ " visibleTopInsets=" + mTmpInsets.visibleTopInsets
- + " touchableInsets=" + mTmpInsets.touchableInsets);
+ + " touchableInsets=" + mTmpInsets.touchableInsets
+ + " touchableRegion=" + mTmpInsets.touchableRegion);
}
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a5f405a..1218e81 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -101,7 +101,7 @@ interface IWindowSession {
* {@link android.view.ViewTreeObserver.InternalInsetsInfo}.
*/
void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
- in Rect visibleInsets);
+ in Rect visibleInsets, in Region touchableRegion);
/**
* Return the current display size in which the window is being laid out,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ad9e6863..b7ab3c1 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1229,24 +1229,34 @@ public final class ViewRoot extends Handler implements ViewParent,
}
if (computesInternalInsets) {
- ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
- final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
- final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
- givenContent.left = givenContent.top = givenContent.right
- = givenContent.bottom = givenVisible.left = givenVisible.top
- = givenVisible.right = givenVisible.bottom = 0;
+ // Clear the original insets.
+ final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
+ insets.reset();
+
+ // Compute new insets in place.
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
- Rect contentInsets = insets.contentInsets;
- Rect visibleInsets = insets.visibleInsets;
- if (mTranslator != null) {
- contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
- visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
- }
+
+ // Tell the window manager.
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
+
+ // Translate insets to screen coordinates if needed.
+ final Rect contentInsets;
+ final Rect visibleInsets;
+ final Region touchableRegion;
+ if (mTranslator != null) {
+ contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
+ visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
+ touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
+ } else {
+ contentInsets = insets.contentInsets;
+ visibleInsets = insets.visibleInsets;
+ touchableRegion = insets.touchableRegion;
+ }
+
try {
sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
- contentInsets, visibleInsets);
+ contentInsets, visibleInsets, touchableRegion);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 06a0fa6..db87175 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -17,6 +17,7 @@
package android.view;
import android.graphics.Rect;
+import android.graphics.Region;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -126,11 +127,18 @@ public final class ViewTreeObserver {
public final Rect contentInsets = new Rect();
/**
- * Offsets from the fram of the window at which windows behind it
+ * Offsets from the frame of the window at which windows behind it
* are visible.
*/
public final Rect visibleInsets = new Rect();
-
+
+ /**
+ * Touchable region defined relative to the origin of the frame of the window.
+ * Only used when {@link #setTouchableInsets(int)} is called with
+ * the option {@link #TOUCHABLE_INSETS_REGION}.
+ */
+ public final Region touchableRegion = new Region();
+
/**
* Option for {@link #setTouchableInsets(int)}: the entire window frame
* can be touched.
@@ -148,11 +156,17 @@ public final class ViewTreeObserver {
* the visible insets can be touched.
*/
public static final int TOUCHABLE_INSETS_VISIBLE = 2;
-
+
+ /**
+ * Option for {@link #setTouchableInsets(int)}: the area inside of
+ * the provided touchable region in {@link #touchableRegion} can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_REGION = 3;
+
/**
* Set which parts of the window can be touched: either
* {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
- * or {@link #TOUCHABLE_INSETS_VISIBLE}.
+ * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
*/
public void setTouchableInsets(int val) {
mTouchableInsets = val;
@@ -165,11 +179,9 @@ public final class ViewTreeObserver {
int mTouchableInsets;
void reset() {
- final Rect givenContent = contentInsets;
- final Rect givenVisible = visibleInsets;
- givenContent.left = givenContent.top = givenContent.right
- = givenContent.bottom = givenVisible.left = givenVisible.top
- = givenVisible.right = givenVisible.bottom = 0;
+ contentInsets.setEmpty();
+ visibleInsets.setEmpty();
+ touchableRegion.setEmpty();
mTouchableInsets = TOUCHABLE_INSETS_FRAME;
}
@@ -179,13 +191,16 @@ public final class ViewTreeObserver {
return false;
}
InternalInsetsInfo other = (InternalInsetsInfo)o;
+ if (mTouchableInsets != other.mTouchableInsets) {
+ return false;
+ }
if (!contentInsets.equals(other.contentInsets)) {
return false;
}
if (!visibleInsets.equals(other.visibleInsets)) {
return false;
}
- return mTouchableInsets == other.mTouchableInsets;
+ return touchableRegion.equals(other.touchableRegion);
} catch (ClassCastException e) {
return false;
}
@@ -194,6 +209,7 @@ public final class ViewTreeObserver {
void set(InternalInsetsInfo other) {
contentInsets.set(other.contentInsets);
visibleInsets.set(other.visibleInsets);
+ touchableRegion.set(other.touchableRegion);
mTouchableInsets = other.mTouchableInsets;
}
}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d28bdc9..f023e94 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -63,7 +63,6 @@ extern int register_android_graphics_MaskFilter(JNIEnv* env);
extern int register_android_graphics_Movie(JNIEnv* env);
extern int register_android_graphics_NinePatch(JNIEnv*);
extern int register_android_graphics_PathEffect(JNIEnv* env);
-extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_Shader(JNIEnv* env);
extern int register_android_graphics_Typeface(JNIEnv* env);
extern int register_android_graphics_YuvImage(JNIEnv* env);
@@ -111,6 +110,7 @@ extern int register_android_graphics_PathMeasure(JNIEnv* env);
extern int register_android_graphics_Picture(JNIEnv*);
extern int register_android_graphics_PorterDuff(JNIEnv* env);
extern int register_android_graphics_Rasterizer(JNIEnv* env);
+extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_PixelFormat(JNIEnv* env);
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 723cd37..c43b5ce 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -1,8 +1,30 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
#include "SkRegion.h"
#include "SkPath.h"
#include "GraphicsJNI.h"
+#include <binder/Parcel.h>
+#include "android_util_Binder.h"
+
#include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
static jfieldID gRegion_nativeInstanceFieldID;
@@ -134,9 +156,6 @@ static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst)
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include <binder/Parcel.h>
-#include "android_util_Binder.h"
-
static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
{
if (parcel == NULL) {
@@ -215,8 +234,6 @@ static jboolean RegionIter_next(JNIEnv* env, jobject, RgnIterPair* pair, jobject
////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#include <android_runtime/AndroidRuntime.h>
-
static JNINativeMethod gRegionIterMethods[] = {
{ "nativeConstructor", "(I)I", (void*)RegionIter_constructor },
{ "nativeDestructor", "(I)V", (void*)RegionIter_destructor },
@@ -268,3 +285,9 @@ int register_android_graphics_Region(JNIEnv* env)
return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
}
+
+SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
+ return GetSkRegion(env, regionObj);
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/Region.h b/core/jni/android/graphics/Region.h
new file mode 100644
index 0000000..c15f06e
--- /dev/null
+++ b/core/jni/android/graphics/Region.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef _ANDROID_GRAPHICS_REGION_H
+#define _ANDROID_GRAPHICS_REGION_H
+
+#include "jni.h"
+#include "SkRegion.h"
+
+namespace android {
+
+/* Gets the underlying SkRegion from a Region object. */
+extern SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj);
+
+} // namespace android
+
+#endif // _ANDROID_GRAPHICS_REGION_H
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index b5a4bd2..e314145 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -154,6 +154,24 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount,
return true;
}
+static void dumpRegion(String8& dump, const SkRegion& region) {
+ if (region.isEmpty()) {
+ dump.append("<empty>");
+ return;
+ }
+
+ bool first = true;
+ for (SkRegion::Iterator it(region); !it.done(); it.next()) {
+ if (first) {
+ first = false;
+ } else {
+ dump.append("|");
+ }
+ const SkIRect& rect = it.rect();
+ dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
+ }
+}
+
// --- InputDispatcher ---
@@ -495,7 +513,7 @@ const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t
if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+ if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
// Found window.
return window;
}
@@ -1188,7 +1206,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+ if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
newTouchedWindow = window;
}
@@ -2884,9 +2902,7 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], "
- "visibleFrame=[%d,%d][%d,%d], "
- "touchableArea=[%d,%d][%d,%d], "
- "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+ "touchableRegion=",
i, window.name.string(),
toString(window.paused),
toString(window.hasFocus),
@@ -2896,11 +2912,9 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
window.layoutParamsFlags, window.layoutParamsType,
window.layer,
window.frameLeft, window.frameTop,
- window.frameRight, window.frameBottom,
- window.visibleFrameLeft, window.visibleFrameTop,
- window.visibleFrameRight, window.visibleFrameBottom,
- window.touchableAreaLeft, window.touchableAreaTop,
- window.touchableAreaRight, window.touchableAreaBottom,
+ window.frameRight, window.frameBottom);
+ dumpRegion(dump, window.touchableRegion);
+ dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
window.ownerPid, window.ownerUid,
window.dispatchingTimeout / 1000000.0);
}
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index 9ce45f5..b552f6d 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -24,9 +24,8 @@ namespace android {
// --- InputWindow ---
-bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
- return x >= touchableAreaLeft && x <= touchableAreaRight
- && y >= touchableAreaTop && y <= touchableAreaBottom;
+bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+ return touchableRegion.contains(x, y);
}
bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index b3d5a65..9c43067 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -23,6 +23,8 @@
#include <utils/Timers.h>
#include <utils/String8.h>
+#include <SkRegion.h>
+
#include "InputApplication.h"
namespace android {
@@ -129,14 +131,7 @@ struct InputWindow {
int32_t frameTop;
int32_t frameRight;
int32_t frameBottom;
- int32_t visibleFrameLeft;
- int32_t visibleFrameTop;
- int32_t visibleFrameRight;
- int32_t visibleFrameBottom;
- int32_t touchableAreaLeft;
- int32_t touchableAreaTop;
- int32_t touchableAreaRight;
- int32_t touchableAreaBottom;
+ SkRegion touchableRegion;
bool visible;
bool canReceiveKeys;
bool hasFocus;
@@ -146,7 +141,7 @@ struct InputWindow {
int32_t ownerPid;
int32_t ownerUid;
- bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+ bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
bool frameContainsPoint(int32_t x, int32_t y) const;
/* Returns true if the window is of a trusted type that is allowed to silently
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index 1515290..2c2cdfe 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.graphics.Region;
import android.view.InputChannel;
/**
@@ -39,23 +40,14 @@ public final class InputWindow {
// Dispatching timeout.
public long dispatchingTimeoutNanos;
- // Window frame area.
+ // Window frame.
public int frameLeft;
public int frameTop;
public int frameRight;
public int frameBottom;
- // Window visible frame area.
- public int visibleFrameLeft;
- public int visibleFrameTop;
- public int visibleFrameRight;
- public int visibleFrameBottom;
-
- // Window touchable area.
- public int touchableAreaLeft;
- public int touchableAreaTop;
- public int touchableAreaRight;
- public int touchableAreaBottom;
+ // Window touchable region.
+ public final Region touchableRegion = new Region();
// Window is visible.
public boolean visible;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index bdc779c..1b3725c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -520,7 +520,7 @@ public class WindowManagerService extends IWindowManager.Stub
int mRotation;
int mAnimFlags;
- private final Rect tmpRect = new Rect();
+ private final Region mTmpRegion = new Region();
DragState(IBinder token, Surface surface, int flags, IBinder localWin) {
mToken = token;
@@ -816,31 +816,13 @@ public class WindowManagerService extends IWindowManager.Stub
// not touchable == don't tell about drags
continue;
}
- // account for the window's decor etc
- tmpRect.set(child.mFrame);
- if (child.mTouchableInsets == ViewTreeObserver
- .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
- // The point is inside of the window if it is
- // inside the frame, AND the content part of that
- // frame that was given by the application.
- tmpRect.left += child.mGivenContentInsets.left;
- tmpRect.top += child.mGivenContentInsets.top;
- tmpRect.right -= child.mGivenContentInsets.right;
- tmpRect.bottom -= child.mGivenContentInsets.bottom;
- } else if (child.mTouchableInsets == ViewTreeObserver
- .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
- // The point is inside of the window if it is
- // inside the frame, AND the visible part of that
- // frame that was given by the application.
- tmpRect.left += child.mGivenVisibleInsets.left;
- tmpRect.top += child.mGivenVisibleInsets.top;
- tmpRect.right -= child.mGivenVisibleInsets.right;
- tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
- }
+
+ child.getTouchableRegion(mTmpRegion);
+
final int touchFlags = flags &
- (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- if (tmpRect.contains(x, y) || touchFlags == 0) {
+ (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ if (mTmpRegion.contains(x, y) || touchFlags == 0) {
// Found it
touchedWin = child;
break;
@@ -2667,7 +2649,7 @@ public class WindowManagerService extends IWindowManager.Stub
void setInsetsWindow(Session session, IWindow client,
int touchableInsets, Rect contentInsets,
- Rect visibleInsets) {
+ Rect visibleInsets, Region touchableRegion) {
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
@@ -2676,6 +2658,7 @@ public class WindowManagerService extends IWindowManager.Stub
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
w.mGivenVisibleInsets.set(visibleInsets);
+ w.mGivenTouchableRegion.set(touchableRegion);
w.mTouchableInsets = touchableInsets;
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -5882,7 +5865,7 @@ public class WindowManagerService extends IWindowManager.Stub
final InputWindow inputWindow = windowList.add();
inputWindow.inputChannel = mDragState.mServerChannel;
inputWindow.name = "drag";
- inputWindow.layoutParamsFlags = 0;
+ inputWindow.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
inputWindow.visible = true;
@@ -5900,15 +5883,8 @@ public class WindowManagerService extends IWindowManager.Stub
inputWindow.frameRight = mDisplay.getWidth();
inputWindow.frameBottom = mDisplay.getHeight();
- inputWindow.visibleFrameLeft = inputWindow.frameLeft;
- inputWindow.visibleFrameTop = inputWindow.frameTop;
- inputWindow.visibleFrameRight = inputWindow.frameRight;
- inputWindow.visibleFrameBottom = inputWindow.frameBottom;
-
- inputWindow.touchableAreaLeft = inputWindow.frameLeft;
- inputWindow.touchableAreaTop = inputWindow.frameTop;
- inputWindow.touchableAreaRight = inputWindow.frameRight;
- inputWindow.touchableAreaBottom = inputWindow.frameBottom;
+ // The drag window cannot receive new touches.
+ inputWindow.touchableRegion.setEmpty();
}
/* Updates the cached window information provided to the input dispatcher. */
@@ -5973,40 +5949,8 @@ public class WindowManagerService extends IWindowManager.Stub
inputWindow.frameTop = frame.top;
inputWindow.frameRight = frame.right;
inputWindow.frameBottom = frame.bottom;
-
- final Rect visibleFrame = child.mVisibleFrame;
- inputWindow.visibleFrameLeft = visibleFrame.left;
- inputWindow.visibleFrameTop = visibleFrame.top;
- inputWindow.visibleFrameRight = visibleFrame.right;
- inputWindow.visibleFrameBottom = visibleFrame.bottom;
-
- switch (child.mTouchableInsets) {
- default:
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
- inputWindow.touchableAreaLeft = frame.left;
- inputWindow.touchableAreaTop = frame.top;
- inputWindow.touchableAreaRight = frame.right;
- inputWindow.touchableAreaBottom = frame.bottom;
- break;
-
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
- Rect inset = child.mGivenContentInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
-
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
- Rect inset = child.mGivenVisibleInsets;
- inputWindow.touchableAreaLeft = frame.left + inset.left;
- inputWindow.touchableAreaTop = frame.top + inset.top;
- inputWindow.touchableAreaRight = frame.right - inset.right;
- inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
- break;
- }
- }
+
+ child.getTouchableRegion(inputWindow.touchableRegion);
}
// Send windows to native code.
@@ -6516,9 +6460,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void setInsets(IWindow window, int touchableInsets,
- Rect contentInsets, Rect visibleInsets) {
+ Rect contentInsets, Rect visibleInsets, Region touchableArea) {
setInsetsWindow(this, window, touchableInsets, contentInsets,
- visibleInsets);
+ visibleInsets, touchableArea);
}
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
@@ -6648,7 +6592,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
long ident = Binder.clearCallingIdentity();
try {
- if (mDragState.mToken != token) {
+ if (mDragState == null || mDragState.mToken != token) {
Slog.w(TAG, "Invalid drop-result claim by " + window);
throw new IllegalStateException("reportDropResult() by non-recipient");
}
@@ -6857,6 +6801,11 @@ public class WindowManagerService extends IWindowManager.Stub
final Rect mGivenVisibleInsets = new Rect();
/**
+ * This is the given touchable area relative to the window frame, or null if none.
+ */
+ final Region mGivenTouchableRegion = new Region();
+
+ /**
* Flag indicating whether the touchable region should be adjusted by
* the visible insets; if false the area outside the visible insets is
* NOT touchable, so we must use those to adjust the frame during hit
@@ -8139,6 +8088,36 @@ public class WindowManagerService extends IWindowManager.Stub
return true;
}
+ public void getTouchableRegion(Region outRegion) {
+ final Rect frame = mFrame;
+ switch (mTouchableInsets) {
+ default:
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
+ outRegion.set(frame);
+ break;
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
+ final Rect inset = mGivenContentInsets;
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
+ break;
+ }
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
+ final Rect inset = mGivenVisibleInsets;
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
+ break;
+ }
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
+ final Region givenTouchableRegion = mGivenTouchableRegion;
+ outRegion.set(givenTouchableRegion);
+ outRegion.translate(frame.left, frame.top);
+ break;
+ }
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index a4609a0..7515456 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -21,6 +21,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
#include "com_android_server_InputWindow.h"
#include "com_android_server_InputWindowHandle.h"
@@ -39,14 +40,7 @@ static struct {
jfieldID frameTop;
jfieldID frameRight;
jfieldID frameBottom;
- jfieldID visibleFrameLeft;
- jfieldID visibleFrameTop;
- jfieldID visibleFrameRight;
- jfieldID visibleFrameBottom;
- jfieldID touchableAreaLeft;
- jfieldID touchableAreaTop;
- jfieldID touchableAreaRight;
- jfieldID touchableAreaBottom;
+ jfieldID touchableRegion;
jfieldID visible;
jfieldID canReceiveKeys;
jfieldID hasFocus;
@@ -108,22 +102,17 @@ void android_server_InputWindow_toNative(
gInputWindowClassInfo.frameRight);
outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
gInputWindowClassInfo.frameBottom);
- outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameLeft);
- outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameTop);
- outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameRight);
- outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.visibleFrameBottom);
- outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaLeft);
- outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaTop);
- outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaRight);
- outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.touchableAreaBottom);
+
+ jobject regionObj = env->GetObjectField(inputWindowObj,
+ gInputWindowClassInfo.touchableRegion);
+ if (regionObj) {
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ outInputWindow->touchableRegion.set(*region);
+ env->DeleteLocalRef(regionObj);
+ } else {
+ outInputWindow->touchableRegion.setEmpty();
+ }
+
outInputWindow->visible = env->GetBooleanField(inputWindowObj,
gInputWindowClassInfo.visible);
outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
@@ -187,29 +176,8 @@ int register_android_server_InputWindow(JNIEnv* env) {
GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
"frameBottom", "I");
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
- "visibleFrameLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
- "visibleFrameTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
- "visibleFrameRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
- "visibleFrameBottom", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
- "touchableAreaLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz,
- "touchableAreaTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz,
- "touchableAreaRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz,
- "touchableAreaBottom", "I");
+ GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
+ "touchableRegion", "Landroid/graphics/Region;");
GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
"visible", "Z");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 443d881..8422d48 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -102,7 +102,7 @@ public final class BridgeWindowSession implements IWindowSession {
}
public void setInsets(IWindow window, int touchable, Rect contentInsets,
- Rect visibleInsets) {
+ Rect visibleInsets, Region touchableRegion) {
// pass for now.
}