近期在处理双屏异显双触摸屏的问题, 发现副屏上的事件处理区域只能和主屏一样大,当副屏小于主屏时不会有问题,但是当副屏大于主屏时问题就比较明显;跟代码发现副屏在设置触摸区域大小时是按照主屏大小设置的,看了很多代码,还是总结下窗口接收按键和自更新的过程,这里其实就是inputDispatcher和窗口的交互。
inputDispatcher和窗口是通过inputChannel来传递信息的,来看看inputChannel的本质:
status_t InputChannel::openInputChannelPair(const String8& name,
sp& outServerChannel, sp& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
....
}
//配置缓冲区 ......
String8 serverChannelName = name;
serverChannelName.append(" (server)");//创建server
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
//创建client对象
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
通过openInputChannelPair方法构造两个inputChannel,而这两个inputChannel是传入了两个socket,而这两个socket是可以互相通信的。可以说inputChannel就是socket的封装,而openInputChannelPair会生成inputChannel对来封装socketpair。有了这个认识,接下来我们就进入流程。
在WMS中,apk端添加窗口时会新建windowstate,更新窗口列表,并同步到ims中,看看具体代码:
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
//创建windowstate
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
//创建两个inputChannel来相互通信
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);//windowstate保存一个
inputChannels[1].transferTo(outInputChannel);//调用端保存一个,即app进程保存一个
//将inputChannel和inputwindowhandle保存到ims中
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
// 更新窗口列表到ims中
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
}
一:openInputChannelPair
//InputChannel.java
public static InputChannel[] openInputChannelPair(String name) {
return nativeOpenInputChannelPair(name);
}
进入jni调用:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp serverChannel;
sp clientChannel;
//生成两个channel并回传给server和client
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
//生成java数组,用来返回给上层java,要注意数组的元素是gInputChannelClassInfo,其实就是InputChannel
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
//生成元素
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
//设置数组元素
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
上面的代码逻辑很清楚,就是在native层先生成一个inputChannelPair即serverchannel和clientchannel,然后用这两个channel构造NativeInputChannel,在用这个NativeInputChannel构造java层的InputChannel,然后返回给上层。InputChannel::openInputChannelPair的方法在文章开头已经介绍了,就是生成两个inputChannel。关于构造java数组的方式还是可以看一下,从这个方式可以看到native层和java层如何交互的:
//返回的静态变量数组
static struct {
jclass clazz;
jfieldID mPtr; // native object attached to the DVM InputChannel
jmethodID ctor;
} gInputChannelClassInfo;
//通过如下代码将native层和java层的元素对应
//gInputChannelClassInfo.clazz, ---> "android/view/InputChannel
//gInputChannelClassInfo.mPtr ----->InputChannel.mPtr
//gInputChannelClassInfo.ctor ----->InputChannel.init(猜测是构造函数)
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className); \
var = jclass(env->NewGlobalRef(var));
#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
var = env->GetMethodID(clazz, methodName, methodDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method " methodName);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_view_InputChannel(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/view/InputChannel",
gInputChannelMethods, NELEM(gInputChannelMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
FIND_CLASS(gInputChannelClassInfo.clazz, "android/view/InputChannel");
GET_FIELD_ID(gInputChannelClassInfo.mPtr, gInputChannelClassInfo.clazz,
"mPtr", "J");
GET_METHOD_ID(gInputChannelClassInfo.ctor, gInputChannelClassInfo.clazz,
"", "()V");
return 0;
}
从上面的代码可知,系统把java层inputChannel中的一些变量保存在了native层gInputChannelClassInfo结构体成员中,方便使用。
接下来看android_view_InputChannel_createInputChannel方法:
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
NativeInputChannel* nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);//构造方法,创建java层inputChannel对象
if (inputChannelObj) {//设置NativeInputChannel到java层inputChannel中
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
}
return inputChannelObj;
}
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {//设置到java层inputChannel对象的mPtr中
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast(nativeInputChannel));
}
第一个方法openInputChannelPair分析完成,这个函数其实做的事情就是进入native层,创建两个inputChannel,然后传入inputChannel创建NativeInputChannel,最后在创建java层inputChannel对象,并将创建的NativeInputChannel对象地址设置到java层inputChannel对象的mPtr变量中,然后返回这两个java层对象。
二:setInputChannel
void setInputChannel(InputChannel inputChannel) {
mInputChannel = inputChannel;
mInputWindowHandle.inputChannel = inputChannel;
}
mInputChannel的创建在windowstate的构造方法:
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
//.......
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, this,
displayContent.getDisplayId());
}
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
Object windowState, int displayId) {
this.inputApplicationHandle = inputApplicationHandle;
this.windowState = windowState;
this.displayId = displayId;
}
可以看到构造函数也很简单,推测大部分工作都是在native层做的。
三:registerInputChannel
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast(ptr);
//先从java层的inputChannel中获取mPtr转化为NativeInputChannel,在从中取出指向的InputChannel
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
sp inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
sp android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {//取出InputChannel中的mPtr,强制转化为NativeInputChannel
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast(longPtr);
}
接下来看android_server_InputWindowHandle_getHandle
sp android_server_InputWindowHandle_getHandle(
JNIEnv* env, jobject inputWindowHandleObj) {
jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
NativeInputWindowHandle* handle;
if (ptr) {
handle = reinterpret_cast(ptr);
} else {
jobject inputApplicationHandleObj = env->GetObjectField(inputWindowHandleObj,
gInputWindowHandleClassInfo.inputApplicationHandle);
sp inputApplicationHandle =
android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
env->DeleteLocalRef(inputApplicationHandleObj);
jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
//native层新建一个NativeInputWindowHandle
handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak);
handle->incStrong((void*)android_server_InputWindowHandle_getHandle);
//将native层的NativeInputWindowHandle设置到java层inputwindowhandle的ptr变量中
env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
reinterpret_cast(handle));
}
return handle;
}
接下来看registerInputChannel:
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);//调用InputDispatcher中的方法
}
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
{ //创建Connection类,封装inputChannel和inputwindowhandle
sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
//获取inputChannel中的fd,监控事件
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
}
mLooper->wake();
return OK;
}
至此,registerInputChannel分析结束:
1.取出在第一步创建的native层的inputChannel
2.新建native层nativeinputwindowhandle,并设置到java层inputwindowhandle对象中的ptr变量中
3.将native层的inputwindowhandle和inputChannel注册到inputdispatcher中,并创建Connection类封装上面两个类,用来和app端交互
四:mInputMonitor.updateInputWindowsLw(false /*force*/);
public void updateInputWindowsLw(boolean force) {
if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");
//.....
// Add all windows on the default display.
final int numDisplays = mService.mDisplayContents.size();
//遍历主副屏
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
//遍历每个窗口
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState child = windows.get(winNdx);
final InputChannel inputChannel = child.mInputChannel;
final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
//将窗口放到窗口列表中
addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible,
hasFocus, hasWallpaper);
}
}
// Send windows to native code.将列表设置到ims中,注意不是窗口列表,而是inputwindowhandles列表,即窗口在ims中的化身
mService.mInputManager.setInputWindows(mInputWindowHandles);
if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
}
private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle,
final WindowState child, int flags, final int type, final boolean isVisible,
final boolean hasFocus, final boolean hasWallpaper) {
// Add a window to our list of input windows.
inputWindowHandle.name = child.toString();
final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
//根据条件从窗口获得触摸区域的大小,并将设置触摸区域的大小设置到inputWindowHandle.touchableRegion中
if (modal && child.mAppToken != null ) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
child.getStackBounds(mTmpRect);
inputWindowHandle.touchableRegion.set(mTmpRect);
} else {
// Not modal or full screen modal
child.getTouchableRegion(inputWindowHandle.touchableRegion);
}
inputWindowHandle.layoutParamsFlags = flags;
//从窗口读取其属性,设置到inputWindowHandle中
inputWindowHandle.frameBottom = frame.bottom;
if (child.mGlobalScale != 1) {
inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
} else {
inputWindowHandle.scaleFactor = 1;
}//添加到mInputWindowHandles中
addInputWindowHandleLw(inputWindowHandle);
}
private void addInputWindowHandleLw(final InputWindowHandle windowHandle) {
if (mInputWindowHandles == null) {
mInputWindowHandles = new InputWindowHandle[16];
}
if (mInputWindowHandleCount >= mInputWindowHandles.length) {
mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
mInputWindowHandleCount * 2);
}
mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
}
上面的代码逻辑比较清晰,就是将遍历每个窗口,搞一个inputwindowhandles列表出来,然后同步到ims中去,这样ims就保存了当前所有窗口的信息,然后就可以根据窗口触摸区域大小等信息发送事件。所以inputwindowhandle就是窗口在ims中的化身,即其相应输入相关事件的一面。
接下来看看ims如何处理要同步的inputwindowhandles
public void setInputWindows(InputWindowHandle[] windowHandles) {
nativeSetInputWindows(mPtr, windowHandles);
}
不出所料,进入native层,其实可以看出,对于输入事件,其实窗口的各种属性如inputwindowhandle和inputChannel之类的都是一个空壳,只是一个保存信息的作用,真正要干活的还是在native层,从java层的对象中获取native等的对象。
static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
jlong ptr, jobjectArray windowHandleObjArray) {
//强制转化为NativeInputManager,并调用其setInputWindows方法
NativeInputManager* im = reinterpret_cast(ptr);
im->setInputWindows(env, windowHandleObjArray);
}
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector > windowHandles;
if (windowHandleObjArray) {
jsize length = env->GetArrayLength(windowHandleObjArray);
for (jsize i = 0; i < length; i++) {
jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
sp windowHandle =//从java层获取到ptr然后强制转化为NativeInputWindowHandle
android_server_InputWindowHandle_getHandle(env, windowHandleObj);
if (windowHandle != NULL) {
windowHandles.push(windowHandle);
}
env->DeleteLocalRef(windowHandleObj);
}
}
//设置到inputdispatcher中
mInputManager->getDispatcher()->setInputWindows(windowHandles);
// Do this after the dispatcher has updated the window handle state.
bool newPointerGesturesEnabled = true;
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp& windowHandle = windowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
& InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
newPointerGesturesEnabled = false;
}
}
uint32_t changes = 0;
{ // acquire lock
AutoMutex _l(mLock);
if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
changes |= InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT;
}
} // release lock
if (changes) {
mInputManager->getReader()->requestRefreshConfiguration(changes);
}
}
进入inputdispatcher中看看是什么动作:
void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) {
{ // acquire lock
AutoMutex _l(mLock);
Vector > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp& windowHandle = mWindowHandles.itemAt(i);
//更新底层和ims相关的窗口信息
if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
if (windowHandle->getInfo()->hasFocus) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
foundHoveredWindow = true;
}
}
if (!foundHoveredWindow) {
mLastHoverWindowHandle = NULL;
}
if (mFocusedWindowHandle != newFocusedWindowHandle) {
if (mFocusedWindowHandle != NULL) {
sp focusedInputChannel = mFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
}
if (newFocusedWindowHandle != NULL) {
}
mFocusedWindowHandle = newFocusedWindowHandle;
}
for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
TouchState& state = mTouchStatesByDisplay.editValueAt(d);
for (size_t i = 0; i < state.windows.size(); i++) {
TouchedWindow& touchedWindow = state.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
sp touchedInputChannel =
touchedWindow.windowHandle->getInputChannel();
if (touchedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(
touchedInputChannel, options);
}
state.windows.removeAt(i--);
}
}
}
// Release information for windows that are no longer present.
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
for (size_t i = 0; i < oldWindowHandles.size(); i++) {
const sp& oldWindowHandle = oldWindowHandles.itemAt(i);
if (!hasWindowHandleLocked(oldWindowHandle)) {
oldWindowHandle->releaseInfo();
}
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
bool NativeInputWindowHandle::updateInfo() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject obj = env->NewLocalRef(mObjWeak);
if (!obj) {
releaseInfo();
return false;
}
if (!mInfo) {
mInfo = new InputWindowInfo();
} else {
mInfo->touchableRegion.clear();
}
jobject inputChannelObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputChannel);
if (inputChannelObj) {//设置inputChannel
mInfo->inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
env->DeleteLocalRef(inputChannelObj);
} else {
mInfo->inputChannel.clear();
}
jstring nameObj = jstring(env->GetObjectField(obj,
gInputWindowHandleClassInfo.name));
if (nameObj) {
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
mInfo->name.setTo(nameStr);
env->ReleaseStringUTFChars(nameObj, nameStr);
env->DeleteLocalRef(nameObj);
} else {
mInfo->name.setTo("");
}
mInfo->layoutParamsFlags = env->GetIntField(obj,
gInputWindowHandleClassInfo.layoutParamsFlags);
mInfo->layoutParamsType = env->GetIntField(obj,
gInputWindowHandleClassInfo.layoutParamsType);
mInfo->dispatchingTimeout = env->GetLongField(obj,
gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
mInfo->frameLeft = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameLeft);
mInfo->frameTop = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameTop);
mInfo->frameRight = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameRight);
mInfo->frameBottom = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameBottom);
mInfo->scaleFactor = env->GetFloatField(obj,
gInputWindowHandleClassInfo.scaleFactor);
//从java中拿到touchableregion,即java中的Region对象
jobject regionObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.touchableRegion);
if (regionObj) {//从java的region类中获取mNativeRegion(从名字就知道是指向native层的对象的),然后强制转化为SkRegion
SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
for (SkRegion::Iterator it(*region); !it.done(); it.next()) {
const SkIRect& rect = it.rect();
mInfo->addTouchableRegion(Rect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom));
}
env->DeleteLocalRef(regionObj);
}
mInfo->visible = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.visible);
mInfo->canReceiveKeys = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.canReceiveKeys);
mInfo->hasFocus = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasFocus);
mInfo->hasWallpaper = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.hasWallpaper);
mInfo->paused = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.paused);
mInfo->layer = env->GetIntField(obj,
gInputWindowHandleClassInfo.layer);
mInfo->ownerPid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerPid);
mInfo->ownerUid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerUid);
mInfo->inputFeatures = env->GetIntField(obj,
gInputWindowHandleClassInfo.inputFeatures);
mInfo->displayId = env->GetIntField(obj,
gInputWindowHandleClassInfo.displayId);
env->DeleteLocalRef(obj);
return true;
}
总结下这个步骤:
1.上层更新窗口列表,并更新touchableregion的大小
2.将更新的窗口列表设置到ims,在ims,ims又将窗口信息设置到inputdispatcher中。
回到开头提出的问题,猜测肯定是上层设置大小的时候出问题了,做如下修改即可
@@ -174,7 +174,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
inputWindowHandle.name = child.toString();
final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
- if (modal && child.mAppToken != null) {
+ if (modal && child.mAppToken != null && (child.getDisplayId() == Display.DEFAULT_DISPLAY)) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
child.getStackBounds(mTmpRect);