android WindowManagerService addFakeWindow 研究

首先,該方法起源於:

FakeWindow com.android.server.wm.WindowManagerService.addFakeWindow(Looper looper, Factory inputEventReceiverFactory, String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen)
定義位置:

<span style="font-family: Arial, Helvetica, sans-serif;">FakeWindow android.view.WindowManagerPolicy.WindowManagerFuncs.addFakeWindow(Looper looper, Factory inputEventReceiverFactory, String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags, boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen)</span>

實現:

        synchronized (mWindowMap) {
            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
                    name, windowType,
                    layoutParamsFlags, layoutParamsPrivateFlags, canReceiveKeys,
                    hasFocus, touchFullscreen);
            int i=0;
            while (i<mFakeWindows.size()) {
                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
                    break;
                }
            }
            mFakeWindows.add(i, fw);
            mInputMonitor.updateInputWindowsLw(true);

好,接下來該看 FakeWindowImpl ,位置:

com.android.server.wm.FakeWindowImpl
到這裏我先講講我爲什麼要研究這個方法,因爲我發現這個方法有一個功能是可以添加一個虛擬窗口,監聽全屏觸摸事件,我想實現的就是監聽全局觸摸事件,所以可以以此方法爲切入點!


我們來看看他的構造函數:

public FakeWindowImpl(WindowManagerService service,
            Looper looper, InputEventReceiver.Factory inputEventReceiverFactory,
            String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) 

InputEventReceiver.Factory inputEventReceiverFactory, 這個參數纔是我的重點,因爲他纔是接收 InputEvent 的實體,那好我們看看構造函數如何使用此參數咯,

重點來啦,

        InputChannel[] channels = InputChannel.openInputChannelPair(name);
        mServerChannel = channels[0];
        mClientChannel = channels[1];
        mService.mInputManager.registerInputChannel(mServerChannel, null);

        mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
                mClientChannel, looper);
重點在於 InputChannel ,看來我得先搞懂他是什麼咯,

關於 InputChannel 可以移步到這裏: Android入門之在客戶進程中註冊InputChannel  Android入門之創建InputChannel


再看 InputEventReceiver 的創建,

 mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(mClientChannel, looper);

這個對象在這裏:

com.android.internal.policy.impl.PhoneWindowManager.mHideNavInputEventReceiverFactory
    final InputEventReceiver.Factory mHideNavInputEventReceiverFactory =
            new InputEventReceiver.Factory() {
        @Override
        public InputEventReceiver createInputEventReceiver(
                InputChannel inputChannel, Looper looper) {
            return new HideNavInputEventReceiver(inputChannel, looper);
        }
    };
InputEventReceiver 的實現是:
    /**
     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
     * to determine when the nav bar should be shown and prevent applications from
     * receiving those touches.
     */
    final class HideNavInputEventReceiver extends InputEventReceiver {
        public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
        }
他這個對象是幹嘛用的呢,我們知道從 Android 4.2 開始,開發者可以將導航欄 和 狀態欄隱藏來使屏幕顯示更多內容,這個對象就是用來監聽導航欄隱藏掉的時候,如何呼喚出來,要不然就得重啓手機了偷笑,不過就此吐槽幾點,Android 框架過於複雜, 以至於一個導航欄處理起來都是很麻煩,廢話不多說,


來看 InputEventReceiver 如何使用 InputChannel:

    /**
     * Creates an input event receiver bound to the specified input channel.
     *
     * @param inputChannel The input channel.
     * @param looper The looper to use when invoking callbacks.
     */
    public InputEventReceiver(InputChannel inputChannel, Looper looper) {
        if (inputChannel == null) {
            throw new IllegalArgumentException("inputChannel must not be null");
        }
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mInputChannel = inputChannel;
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
                inputChannel, mMessageQueue);

        mCloseGuard.open("dispose");
    }
我們看到他的工作賺到了 native 層,nativeInit,這我就不深究了,我已經知道我該怎麼做了!


重點就是先使用:

InputChannel[] channels = InputChannel.openInputChannelPair(name); 

創建一對輸入接收器,然後向 InputManagerService 註冊 channel :

void com.android.server.input.InputManagerService.registerInputChannel(InputChannel inputChannel, InputWindowHandle inputWindowHandle)


Android輸入輸出機制之來龍去脈之前生後世


然後我開始測試代碼。。。























發佈了72 篇原創文章 · 獲贊 72 · 訪問量 57萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章