Android5.1 双输入的处理--理解inputChannel

近期在处理双屏异显双触摸屏的问题, 发现副屏上的事件处理区域只能和主屏一样大,当副屏小于主屏时不会有问题,但是当副屏大于主屏时问题就比较明显;跟代码发现副屏在设置触摸区域大小时是按照主屏大小设置的,看了很多代码,还是总结下窗口接收按键和自更新的过程,这里其实就是inputDispatcher和窗口的交互。

inputDispatcher和窗口是通过inputChannel来传递信息的,来看看inputChannel的本质:

status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& 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<InputChannel> serverChannel;
    sp<InputChannel> 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));
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值