framework學(xué)習(xí)筆記16. Input 輸入事件(2)

原計劃 input 輸入事件的學(xué)習(xí)分為兩節(jié)內(nèi)容學(xué)習(xí)并記錄,經(jīng)學(xué)習(xí)發(fā)現(xiàn)并遠不止這些內(nèi)容,所以決定重新寫 input 輸入事件番外篇,如需參考,請閱讀 input 輸入事件番外篇;造成的不便,深表抱歉。

1. Window 的創(chuàng)建和 WMS的綁定
上一節(jié)中講到 dispatchMotionLocked() 向目標(biāo)窗口分發(fā)事件,這里簡單介紹一下目標(biāo)窗口是如何獲取和綁定的;在 Activity 的啟動流程中(具體可以參考 筆記14):
(1)handleLaunchActivity() 調(diào)用了 performLaunchActivity() ->
(2)performLaunchActivity() 中調(diào)用了 activity.attach()方法,之前就說過這個是對 activity進行綁定,完成這一步activity才成為四大組件之一,未完成時都只能算一個對象(創(chuàng)建activity的第一步) ->
(3)handleLaunchActivity() 調(diào)用了 handleResumeActivity() 方法(第二步:onResume()并渲染);
窗口的獲取和綁定就在 performLaunchActivity() 調(diào)用的 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);
        // 創(chuàng)建 Window
        // 這里的 mWindow 時 PhoneWindow,后續(xù)版本的 mWindow 初始化如下,更加直觀:
        // mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        // ...
        // 在window中創(chuàng)建時 mWindowManager 其實是 WindowManagerImpl,代碼不復(fù)雜,可以跟進去看看
        mWindow.setWindowManager(  // 設(shè)置 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;
    }

在這里記住三個知識點(后續(xù)講setContentView時再詳細分析):
a. Window 類是一個抽象類,它的唯一實現(xiàn)類是 PhoneWindow;
b. PhoneWindow 有一個內(nèi)部類 DecorView,DecorView 是 Activity 的根 View;
c. DecorView 繼承自 FramLayout;

關(guān)于創(chuàng)建Window對象:
PolicyManager為策略類,其實現(xiàn)類Policy 的makeNewWindow內(nèi)部創(chuàng)建了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 {  // 通過反射創(chuàng)建 sPolicy
        try {
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME); 
            sPolicy = (IPolicy)policyClass.newInstance();
        } catch (ClassNotFoundException ex) {
            // ...
        }
    }

    private PolicyManager() {}

    // 創(chuàng)建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) {
        
        // 主要作用是調(diào)用performResumeActivity()到activity的onResume狀態(tài),然后獲取
        // DecorView,創(chuàng)建一個關(guān)聯(lián)的ViewRootImpl對象,用來配合WindowManagerService
        // 服務(wù)來管理該Activity組件的窗口狀態(tài),最后addView
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;
            // ...

            //activity創(chuàng)建成功,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;
                    // 一層層的看最終調(diào)用的是: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) {

        // ... 省略部分代碼:參數(shù)的校驗
        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 的實例,
        // 然后調(diào)用 requestLayout() 方法,以完成應(yīng)用程序用戶界面的初次布局。
        if (mView == null) {
            mView = view;
            // mWindowAttributes保存了窗口所對應(yīng)的LayoutParams
           mWindowAttributes.copyFrom(attrs);
            /**
            * 在添加窗口之前,先通過requestLayout方法在主線程上安排一次“遍歷”。
            * 所謂“遍歷”是指ViewRootImpl中的核心方法performTraversal()。
            * 這個方法實現(xiàn)對控件樹進行測量、布局、向WMS申請修改窗口屬性以及重繪的所有工作。
            */
           requestLayout();  
           /***初始化mInputChannel。InputChannel是窗口接受來自InputDispatcher 的輸入事件的管道。 
             注意,僅當(dāng)窗口的屬性inputFeatures不含有 INPUT_FEATURE_NO_INPUT_CHANNEL時才
             會創(chuàng)建 InputChannel,否則mInputChannel 為空,從而導(dǎo)致此窗口無法接受任何輸入事件 */
           if ((mWindowAttributes.inputFeatures
                   & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
               mInputChannel = new InputChannel();  // 見 2.2
           }
           try {
             // ...
             /* 將窗口添加到WMS中。完成這個操作之后,mWindow已經(jīng)被添加到指定的Display中去
               而且mInputChannel(如果不為空)已經(jīng)準(zhǔn)備好接受事件了。只是由于這個窗口沒有進行
               過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的構(gòu)造函數(shù):此時 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();

    // 構(gòu)造函數(shù)中沒有任何操作,此時 mInputChannel = new InputChannel() 只是一個普通的java對象;
    // 那么要想具有 c++ 的屬性,唯一的方法就是持有c++對象的指針,也就是將 mPtr 賦值;
    public InputChannel() {
    }
    // ...
  }

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

// mWindowSession 的初始化:ViewRootImpl 的構(gòu)造函數(shù)中進行初始化的;
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接口,它的真的實現(xiàn)類是Session,它是一個Binder對象,用來和
//WindowManagerService建立連接,在ViewRootImpl的setView中最終也是通過它和WindowManagerService
//通信完成了Window的添加的。這個Session是應(yīng)用唯一的,它的創(chuàng)建時在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;
}

這里創(chuàng)建了 Session 對象,其參數(shù) this 就是 WMS;
mWindowSession.addToDisplay() 就是 調(diào)用了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();
                // 關(guān)鍵代碼,打開一對 InputChannel,客戶端和服務(wù)端 見 2.3.1
                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 
                // WMS 設(shè)置 Channel 為 inputChannels[0] 
                win.setInputChannel(inputChannels[0]); 
                // 客戶端設(shè)置 Channel 為 inputChannels[1],此時給上面 Java層的 mInputChannel 中 mPtr 賦值
                // 經(jīng)過賦值后,Java 層 mInputChannel 才具有 c++ 的對象
                inputChannels[1].transferTo(outInputChannel);  

                // 將服務(wù)端的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;
    // 創(chuàng)建一對 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()函數(shù)用于創(chuàng)建一對無名的、相互連接的套接字。
如果函數(shù)成功,則返回0,創(chuàng)建好的套接字分別是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]是進程共享的,所以讀的進程要關(guān)閉寫描述符, 反之,寫的進程關(guān)閉讀描述符。

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,關(guān)聯(lián) 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
簡介:實現(xiàn)了 WindowManagerCallbacks接口,在 WindowManagerService 的構(gòu)造函數(shù)中創(chuàng)建了InputMonitor 對象,并以 mInputMonitor 作為參數(shù)創(chuàng)建 InputManagerService 的對象,在 InputManagerService 構(gòu)造函數(shù)中,將 mInputMonitor 作為參數(shù)調(diào)用了 JNI 函數(shù) nativeInit() ,將回調(diào)接口傳到JNI層,在需要的時候,JNI 再回調(diào) mInputMonitor中 的函數(shù),實現(xiàn)數(shù)據(jù)才傳遞。

    public interface WindowManagerCallbacks {
        public void notifyConfigurationChanged();

        // 輸入設(shè)備的配置變更
        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);        
        public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);

        // 連接InputDispatcher 與應(yīng)用程序的 socket 通道
        public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
        // ANR
        public long notifyANR(InputApplicationHandle inputApplicationHandle,
                InputWindowHandle inputWindowHandle, String reason);

        // 以下三個回調(diào),是WMS在消息處理中有優(yōu)先權(quán)處理
        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
        public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
        public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                KeyEvent event, int policyFlags);

        // 按鍵事件在整個事件處理過程中沒有任何處理時,發(fā)送給 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 數(shù)組中
                if (child.mWinAnimator != universeBackground) {
                    addInputWindowHandleLw(inputWindowHandle, child, flags, privateFlags, type,
                            isVisible, hasFocus, hasWallpaper);
                }
        }
            
        // 發(fā)送窗口到本地方法;
        mService.mInputManager.setInputWindows(mInputWindowHandles);
        // Clear the list in preparation for the next round.
        clearInputWindowHandlesLw();
    }
}


// InputServiceManager.java中:調(diào)用的是 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;
    // ...   
    // 調(diào)用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,這里就知道分發(fā)的目標(biāo)窗口是哪個窗口了;
        // input 事件就是根據(jù)匹配 InputWindowHandle 來進行分發(fā)的;
        mWindowHandles = inputWindowHandles;
    }    

    // ... 一些窗口的更新等操作
    // Wake up poll loop since it may need to make new input dispatching choices.
    mLooper->wake();
}

由于篇幅過長,input 輸入事件篇未完成,請參考更為詳細的 input 輸入事件番外篇;造成的不便,深表抱歉;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容