美文网首页
framework学习笔记16. Input 输入事件(2)

framework学习笔记16. Input 输入事件(2)

作者: 加个标志位 | 来源:发表于2021-01-26 19:55 被阅读0次

    原计划 input 输入事件的学习分为两节内容学习并记录,经学习发现并远不止这些内容,所以决定重新写 input 输入事件番外篇,如需参考,请阅读 input 输入事件番外篇;造成的不便,深表抱歉。

    1. Window 的创建和 WMS的绑定
    上一节中讲到 dispatchMotionLocked() 向目标窗口分发事件,这里简单介绍一下目标窗口是如何获取和绑定的;在 Activity 的启动流程中(具体可以参考 笔记14):
    (1)handleLaunchActivity() 调用了 performLaunchActivity() ->
    (2)performLaunchActivity() 中调用了 activity.attach()方法,之前就说过这个是对 activity进行绑定,完成这一步activity才成为四大组件之一,未完成时都只能算一个对象(创建activity的第一步) ->
    (3)handleLaunchActivity() 调用了 handleResumeActivity() 方法(第二步:onResume()并渲染);
    窗口的获取和绑定就在 performLaunchActivity() 调用的 activity.attach() 中完成的,进入源码中看看:

        final void attach(Context context, ActivityThread aThread,
                Instrumentation instr, IBinder token, int ident,
                Application application, Intent intent, ActivityInfo info,
                CharSequence title, Activity parent, String id,
                NonConfigurationInstances lastNonConfigurationInstances,
                Configuration config, IVoiceInteractor voiceInteractor) {
            attachBaseContext(context);
    
            mFragments.attachActivity(this, mContainer, null);
            // 创建 Window
            // 这里的 mWindow 时 PhoneWindow,后续版本的 mWindow 初始化如下,更加直观:
            // mWindow = new PhoneWindow(this, window, activityConfigCallback);
            mWindow = PolicyManager.makeNewWindow(this);
            mWindow.setCallback(this);
            mWindow.setOnWindowDismissedCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
            // ...
            // 在window中创建时 mWindowManager 其实是 WindowManagerImpl,代码不复杂,可以跟进去看看
            mWindow.setWindowManager(  // 设置 WindowManager
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
            if (mParent != null) {
                mWindow.setContainer(mParent.getWindow());
            }
            mWindowManager = mWindow.getWindowManager();  // 这里就可以获取 WindowManager 了
            mCurrentConfig = config;
        }
    

    在这里记住三个知识点(后续讲setContentView时再详细分析):
    a. Window 类是一个抽象类,它的唯一实现类是 PhoneWindow;
    b. PhoneWindow 有一个内部类 DecorView,DecorView 是 Activity 的根 View;
    c. DecorView 继承自 FramLayout;

    关于创建Window对象:
    PolicyManager为策略类,其实现类Policy 的makeNewWindow内部创建了window对象;

    // mWindow = PolicyManager.makeNewWindow(this):
    public final class PolicyManager {
        private static final String POLICY_IMPL_CLASS_NAME =
            "com.android.internal.policy.impl.Policy";
    
        private static final IPolicy sPolicy;
    
        static {  // 通过反射创建 sPolicy
            try {
                Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME); 
                sPolicy = (IPolicy)policyClass.newInstance();
            } catch (ClassNotFoundException ex) {
                // ...
            }
        }
    
        private PolicyManager() {}
    
        // 创建PhoneWindow
        public static Window makeNewWindow(Context context) {
            return sPolicy.makeNewWindow(context);
        }
    
        public static LayoutInflater makeNewLayoutInflater(Context context) {
            return sPolicy.makeNewLayoutInflater(context);
        }
    
        public static WindowManagerPolicy makeNewWindowManager() {
            return sPolicy.makeNewWindowManager();
        }
    
        public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
            return sPolicy.makeNewFallbackEventHandler(context);
        }
    }
    
    // Policy.java 类中的 makeNewWindow() 方法:
    public window makeNewWindow(Context context){
            return new PhoneWindow(context);
    }
    

    2. ViewRootImpl 与 WMS 的通信

        // 第二步:
        final void handleResumeActivity(IBinder token,
                boolean clearHide, boolean isForward, boolean reallyResume) {
            
            // 主要作用是调用performResumeActivity()到activity的onResume状态,然后获取
            // DecorView,创建一个关联的ViewRootImpl对象,用来配合WindowManagerService
            // 服务来管理该Activity组件的窗口状态,最后addView
            ActivityClientRecord r = performResumeActivity(token, clearHide);
    
            if (r != null) {
                final Activity a = r.activity;
                // ...
    
                //activity创建成功,window此时为空,进入此分支;
                if (r.window == null && !a.mFinished && willBeVisible) { 
                    r.window = r.activity.getWindow();
                    View decor = r.window.getDecorView();
                    decor.setVisibility(View.INVISIBLE);
                    ViewManager wm = a.getWindowManager();
                    WindowManager.LayoutParams l = r.window.getAttributes();
                    a.mDecor = decor;
                    l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                    l.softInputMode |= forwardBit;
                    if (a.mVisibleFromClient) {
                        a.mWindowAdded = true;
                        // 一层层的看最终调用的是:WindowManagerGlobal.java -> addView()
                        wm.addView(decor, l);  // 这里就是测量,摆放,绘制
                    }
    
                } else if (!willBeVisible) {
                    r.hideForNow = true;
                }
                // Get rid of anything left hanging around.
                cleanUpPendingRemoveWindows(r);
    
                // ...
            } 
        }
    

    2.1 wm.addView(decor, l):这里的 wm 是 WindowManagerImpl,查看一下 addView() 方法:

    // WindowManagerImpl.addView():
        // 单例获取 WindowManagerGlobal
        private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
        @Override
        public void addView(View view, ViewGroup.LayoutParams params) {
            mGlobal.addView(view, params, mDisplay, mParentWindow);
        }
    
    
    //WindowManagerGlobal.addView():
        public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
    
            // ... 省略部分代码:参数的校验
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
            // ...
            ViewRootImpl root;
            View panelParentView = null;
    
                //...
         
                // 实例化ViewRootImpl
                root = new ViewRootImpl(view.getContext(), display);
    
                view.setLayoutParams(wparams);
                // 添加 view 到全局集合中
                // 如果想 hook 全部的 view 时,可以通过反射获取 WindowManagerGlobal -> mViews;
                mViews.add(view);  
                mRoots.add(root);
                mParams.add(wparams);
            }
           
            // do this last because it fires off messages to start doing things
            try {  //将view添加到ViewRootImpl中去
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
               // ...
            }
        }
    

    ViewRootImpl.setView():

        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
            // 这里先将 mView 保存了 DecorView 的实例,
            // 然后调用 requestLayout() 方法,以完成应用程序用户界面的初次布局。
            if (mView == null) {
                mView = view;
                // mWindowAttributes保存了窗口所对应的LayoutParams
               mWindowAttributes.copyFrom(attrs);
                /**
                * 在添加窗口之前,先通过requestLayout方法在主线程上安排一次“遍历”。
                * 所谓“遍历”是指ViewRootImpl中的核心方法performTraversal()。
                * 这个方法实现对控件树进行测量、布局、向WMS申请修改窗口属性以及重绘的所有工作。
                */
               requestLayout();  
               /***初始化mInputChannel。InputChannel是窗口接受来自InputDispatcher 的输入事件的管道。 
                 注意,仅当窗口的属性inputFeatures不含有 INPUT_FEATURE_NO_INPUT_CHANNEL时才
                 会创建 InputChannel,否则mInputChannel 为空,从而导致此窗口无法接受任何输入事件 */
               if ((mWindowAttributes.inputFeatures
                       & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                   mInputChannel = new InputChannel();  // 见 2.2
               }
               try {
                 // ...
                 /* 将窗口添加到WMS中。完成这个操作之后,mWindow已经被添加到指定的Display中去
                   而且mInputChannel(如果不为空)已经准备好接受事件了。只是由于这个窗口没有进行
                   过relayout(),因此它还没有有效的Surface可以进行绘制 */
                 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                           getHostVisibility(), mDisplay.getDisplayId(),
                           mAttachInfo.mContentInsets, mInputChannel);  // 见2.3 
                  // 这里的 mWindowSession 是向WMS跨进程请求获取的 
               } catch (RemoteException e) {  
                  // ... 
               } finally { 
                  // ... 
               }
    
            }
        }
    

    2.2 InputChannel的构造函数:此时 mInputChannel = new InputChannel() 这里还是一个 Java 的对象;

    public final class InputChannel implements Parcelable {
        private static final String TAG = "InputChannel";
        
        @SuppressWarnings("unused")
        private long mPtr; // used by native code
        private static native InputChannel[] nativeOpenInputChannelPair(String name);
        
        private native void nativeDispose(boolean finalized);
        private native void nativeTransferTo(InputChannel other);
        private native void nativeReadFromParcel(Parcel parcel);
        private native void nativeWriteToParcel(Parcel parcel);
        private native void nativeDup(InputChannel target);
        
        private native String nativeGetName();
    
        // 构造函数中没有任何操作,此时 mInputChannel = new InputChannel() 只是一个普通的java对象;
        // 那么要想具有 c++ 的属性,唯一的方法就是持有c++对象的指针,也就是将 mPtr 赋值;
        public InputChannel() {
        }
        // ...
      }
    

    2.3 mWindowSession.addToDisplay():
    首先,mWindowSession 是如何获取到的:

    // mWindowSession 的初始化:ViewRootImpl 的构造函数中进行初始化的;
    public ViewRootImpl(Context context, Display display) {
            mContext = context;
            mWindowSession = WindowManagerGlobal.getWindowSession();  // 通过 WMS 获取
    }
    
    
    // 通过 WMS 获取 mWindowSession:WindowManagerGlobal类中的 getWindowSession() 方法
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                    ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }
    
    
    // WMS 中openSession():
    //IWindowSession :一个aidl接口,它的真的实现类是Session,它是一个Binder对象,用来和
    //WindowManagerService建立连接,在ViewRootImpl的setView中最终也是通过它和WindowManagerService
    //通信完成了Window的添加的。这个Session是应用唯一的,它的创建时在WindowManagerGloable中通过getWindowSession获取的
    @Override
    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }
    

    这里创建了 Session 对象,其参数 this 就是 WMS;
    mWindowSession.addToDisplay() 就是 调用了Session的 addToDisplay() 方法:

    // Session 的 addToDisplay() 方法:又是跨进程通讯
        @Override
        public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
                int viewVisibility, int displayId, Rect outContentInsets,
                InputChannel outInputChannel) {
            // outInputChannel 是 2.2 中 mInputChannel = new InputChannel(),此时的指针还未赋值
            // mService 就是 new Session 时传入的 WMS
            return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                    outContentInsets, outInputChannel); 
        }
    

    WMS的addWindow() 方法:

    public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, InputChannel outInputChannel) {
            int[] appOp = new int[1];
            int res = mPolicy.checkAddPermission(attrs, appOp);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }
    
            boolean reportNewConfig = false;
            WindowState attachedWindow = null;
            WindowState win = null;  // window 对象的信息
            long origId;
            final int type = attrs.type;
    
            synchronized(mWindowMap) {
                // ...
                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,客户端和服务端 见 2.3.1
                    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 
                    // WMS 设置 Channel 为 inputChannels[0] 
                    win.setInputChannel(inputChannels[0]); 
                    // 客户端设置 Channel 为 inputChannels[1],此时给上面 Java层的 mInputChannel 中 mPtr 赋值
                    // 经过赋值后,Java 层 mInputChannel 才具有 c++ 的对象
                    inputChannels[1].transferTo(outInputChannel);  
    
                    // 将服务端的socket注册到InputDispatcher中 见 2.3.2
                    // 这里的 win.mInputWindowHandle 是在 win 初始化的时候 new 出来的;
                    mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
                }
    
                // ...
                // 每次添加都会更新,见 2.3.3
                mInputMonitor.updateInputWindowsLw(false /*force*/);
                // ...
            }
            // ...
    }
    

    2.3.1 建立socket 通信:
    InputChannel.openInputChannelPair(name) 是一个native方法,在 frameworks/base/core/jni/
    android_view_InputChannel.cpp中:

    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;
        // 创建一对 socket 通信
        status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    
        if (result) {
            String8 message;
            message.appendFormat("Could not open input channel pair.  status=%d", result);
            jniThrowRuntimeException(env, message.string());
            return NULL;
        }
    
        // 封装成java对象    
        jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
        if (env->ExceptionCheck()) {
            return NULL;
        }
    
        jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
                new NativeInputChannel(serverChannel));
        if (env->ExceptionCheck()) {
            return NULL;
        }
    
        jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
                new NativeInputChannel(clientChannel));
        if (env->ExceptionCheck()) {
            return NULL;
        }
    
        env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
        env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
        return channelPair;
    }
    

    InputChannel.cpp中:

    status_t InputChannel::openInputChannelPair(const String8& name,
            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
        int sockets[2];
        if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
            status_t result = -errno;
        // ...    
        String8 serverChannelName = name;
        serverChannelName.append(" (server)");
        outServerChannel = new InputChannel(serverChannelName, sockets[0]);
    
        String8 clientChannelName = name;
        clientChannelName.append(" (client)");
        outClientChannel = new InputChannel(clientChannelName, sockets[1]);
        return OK;
    }
    

    socketpair()函数用于创建一对无名的、相互连接的套接字。
    如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。

    用法:
    (1) 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
    (2) 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功;
    (3)读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述符sv[0]和sv[1]是进程共享的,所以读的进程要关闭写描述符, 反之,写的进程关闭读描述符。

    2.3.2 注册:frameworks/base/services/core/jni/
    com_android_server_input_InputManagerService.cpp 中:

    // nativeRegisterInputChannel():
    static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
            jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    
        sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
                inputChannelObj);
        if (inputChannel == NULL) {
            throwInputChannelNotInitialized(env);
            return;
        }
        // window 的一些信息
        sp<InputWindowHandle> inputWindowHandle =
                android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);  
    
        status_t status = im->registerInputChannel(  // 注册的方法,如下 registerInputChannel()方法:
                env, inputChannel, inputWindowHandle, monitor);
        if (status) {
            String8 message;
            message.appendFormat("Failed to register input channel.  status=%d", status);
            jniThrowRuntimeException(env, message.string());
            return;
        }
    
        if (! monitor) {
            android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
                    handleInputChannelDisposed, im);
        }
    }
    
    
    // registerInputChannel()方法:
    status_t NativeInputManager::registerInputChannel(JNIEnv* env,
            const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
        // 终于看到我们 InputDispatcher 了
        return mInputManager->getDispatcher()->registerInputChannel(
                inputChannel, inputWindowHandle, monitor);
    }
    

    InputDispatcher.cpp 中的注册方法:registerInputChannel()

    status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    
        { // acquire lock
            AutoMutex _l(mLock);
    
            // 连接的媒介,只是一个对象,没有跨进程等操作;
            sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
    
            int fd = inputChannel->getFd();
            // 传入 fd 和 connection,关联 fd 和 connection;
            mConnectionsByFd.add(fd, connection);
    
            if (monitor) {
                mMonitoringChannels.push(inputChannel);
            }
    
            mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
        } // release lock
    
        // Wake the looper because some connections have changed.
        mLooper->wake();
        return OK;
    }
    

    2.3.3 InputMonitor
    简介:实现了 WindowManagerCallbacks接口,在 WindowManagerService 的构造函数中创建了InputMonitor 对象,并以 mInputMonitor 作为参数创建 InputManagerService 的对象,在 InputManagerService 构造函数中,将 mInputMonitor 作为参数调用了 JNI 函数 nativeInit() ,将回调接口传到JNI层,在需要的时候,JNI 再回调 mInputMonitor中 的函数,实现数据才传递。

        public interface WindowManagerCallbacks {
            public void notifyConfigurationChanged();
    
            // 输入设备的配置变更
            public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);        
            public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
    
            // 连接InputDispatcher 与应用程序的 socket 通道
            public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
            // ANR
            public long notifyANR(InputApplicationHandle inputApplicationHandle,
                    InputWindowHandle inputWindowHandle, String reason);
    
            // 以下三个回调,是WMS在消息处理中有优先权处理
            public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
            public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
            public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                    KeyEvent event, int policyFlags);
    
            // 按键事件在整个事件处理过程中没有任何处理时,发送给 WMS 
            public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
                    KeyEvent event, int policyFlags);
            public int getPointerLayer();
        }
    
    // 简化代码:
    final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
        private final WindowManagerService mService;
        private WindowState mInputFocus;
        private boolean mUpdateInputWindowsNeeded = true;
        private InputWindowHandle[] mInputWindowHandles;
    
    
        private final Object mInputDevicesReadyMonitor = new Object();
        private boolean mInputDevicesReady;
        Rect mTmpRect = new Rect();
        public InputMonitor(WindowManagerService service) {
            mService = service;
        }
    
        public void updateInputWindowsLw(boolean force) {
            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                    // ...
                    // 加入到 mInputWindowHandles 数组中
                    if (child.mWinAnimator != universeBackground) {
                        addInputWindowHandleLw(inputWindowHandle, child, flags, privateFlags, type,
                                isVisible, hasFocus, hasWallpaper);
                    }
            }
                
            // 发送窗口到本地方法;
            mService.mInputManager.setInputWindows(mInputWindowHandles);
            // Clear the list in preparation for the next round.
            clearInputWindowHandlesLw();
        }
    }
    
    
    // InputServiceManager.java中:调用的是 native 方法;
      public void setInputWindows(InputWindowHandle[] windowHandles) {
          nativeSetInputWindows(mPtr, windowHandles);
      }
    

    frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp 中 nativeSetInputWindows() 方法:

    // com_android_server_input_InputManagerService.cpp 中:
    static void nativeSetInputWindows(JNIEnv* env, jclass clazz,
            jlong ptr, jobjectArray windowHandleObjArray) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
        im->setInputWindows(env, windowHandleObjArray);
    }
    
    
    // com_android_server_input_InputManagerService.cpp 中:
    void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
        Vector<sp<InputWindowHandle> > windowHandles;
        // ...   
        // 调用InputDispatcher 中 setInputWindows()
        mInputManager->getDispatcher()->setInputWindows(windowHandles);
        // ...
    }
    
    // InputDispatcher.cpp 中的 setInputWindows():
    void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
        { // acquire lock
            Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
            // 把 inputWindowHandles 赋值给 mWindowHandles,这里就知道分发的目标窗口是哪个窗口了;
            // input 事件就是根据匹配 InputWindowHandle 来进行分发的;
            mWindowHandles = inputWindowHandles;
        }    
    
        // ... 一些窗口的更新等操作
        // Wake up poll loop since it may need to make new input dispatching choices.
        mLooper->wake();
    }
    

    由于篇幅过长,input 输入事件篇未完成,请参考更为详细的 input 输入事件番外篇;造成的不便,深表抱歉;

    相关文章

      网友评论

          本文标题:framework学习笔记16. Input 输入事件(2)

          本文链接:https://www.haomeiwen.com/subject/ndmtzktx.html