Android通过 KeyInputQ在WindowMangerService中建立一个独立的线程InputDeviceReader,使用Native函数readEvent来读取Linux Driver的数据构建RawEvent,并放入到KeyQ消息队列中。

KeyInputQueue.java

   Thread mThread = new Thread("InputDeviceReader") {        public void run() {            if (DEBUG) Log.v(TAG, "InputDeviceReader.run()");            android.os.Process.setThreadPriority(                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);                        RawInputEvent ev = new RawInputEvent();            while (true) {                try {                    InputDevice di;                    // block, doesn't release the monitor                    readEvent(ev);                    boolean send = false;                    boolean configChanged = false;                                        if (false) {                        Log.i(TAG, "Input event: dev=0x"                                + Integer.toHexString(ev.deviceId)                                + " type=0x" + Integer.toHexString(ev.type)                                + " scancode=" + ev.scancode                                + " keycode=" + ev.keycode                                + " value=" + ev.value);                    }                                        if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {                        synchronized (mFirst) {                            di = newInputDevice(ev.deviceId);                            if (di.classes != 0) {                                // If this device is some kind of input class,                                // we care about it.                                mDevices.put(ev.deviceId, di);                                if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {                                    readVirtualKeys(di.name);                                }                                // The configuration may have changed because                                // of this device.                                configChanged = true;                            } else {                                // We won't do anything with this device.                                mIgnoredDevices.put(ev.deviceId, di);                                Log.i(TAG, "Ignoring non-input device: id=0x"                                        + Integer.toHexString(di.id)                                        + ", name=" + di.name);                            }                        }                    } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {                        synchronized (mFirst) {                            if (false) {                                Log.i(TAG, "Device removed: id=0x"                                        + Integer.toHexString(ev.deviceId));                            }                            di = mDevices.get(ev.deviceId);                            if (di != null) {                                mDevices.delete(ev.deviceId);                                // The configuration may have changed because                                // of this device.                                configChanged = true;                            } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {                                mIgnoredDevices.remove(ev.deviceId);                            } else {                                Log.w(TAG, "Removing bad device id: "                                        + Integer.toHexString(ev.deviceId));                                continue;                            }                        }                    } else {                        di = getInputDevice(ev.deviceId);                        if (di == null) {                            // This may be some junk from an ignored device.                            continue;                        }                                                // first crack at it                        send = preprocessEvent(di, ev);                        if (ev.type == RawInputEvent.EV_KEY) {                            di.mMetaKeysState = makeMetaState(ev.keycode,                                    ev.value != 0, di.mMetaKeysState);                            mHaveGlobalMetaState = false;                        }                    }                    if (configChanged) {                        synchronized (mFirst) {                            addLocked(di, System.nanoTime(), 0,                                    RawInputEvent.CLASS_CONFIGURATION_CHANGED,                                    null);                        }                    }                                        if (!send) {                        continue;                    }                                        synchronized (mFirst) {                        // NOTE: The event timebase absolutely must be the same                        // timebase as SystemClock.uptimeMillis().                        //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();                        final long curTime = SystemClock.uptimeMillis();                        final long curTimeNano = System.nanoTime();                        //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());                                                final int classes = di.classes;                        final int type = ev.type;                        final int scancode = ev.scancode;                        send = false;                                                // Is it a key event?                        if (type == RawInputEvent.EV_KEY &&                                (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&                                (scancode < RawInputEvent.BTN_FIRST ||                                        scancode > RawInputEvent.BTN_LAST)) {                            boolean down;                            if (ev.value != 0) {                                down = true;                                di.mKeyDownTime = curTime;                            } else {                                down = false;                            }                            int keycode = rotateKeyCodeLocked(ev.keycode);                            addLocked(di, curTimeNano, ev.flags,                                    RawInputEvent.CLASS_KEYBOARD,                                    newKeyEvent(di, di.mKeyDownTime, curTime, down,                                            keycode, 0, scancode,                                            ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)                                             ? KeyEvent.FLAG_WOKE_HERE : 0));                                                    } else if (ev.type == RawInputEvent.EV_KEY) {                            // Single touch protocol: touch going down or up.                            if (ev.scancode == RawInputEvent.BTN_TOUCH &&                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))                                            == RawInputEvent.CLASS_TOUCHSCREEN) {                                di.mAbs.changed = true;                                di.mAbs.mDown[0] = ev.value != 0;                                                        // Trackball (mouse) protocol: press down or up.                            } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&                                    (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {                                di.mRel.changed = true;                                di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;                                send = true;                            }                            // Process position events from multitouch protocol.                        } else if (ev.type == RawInputEvent.EV_ABS &&                                (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {                            if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {                                di.mAbs.changed = true;                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset                                        + MotionEvent.SAMPLE_PRESSURE] = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {                                di.mAbs.changed = true;                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset                                    + MotionEvent.SAMPLE_X] = ev.value;                                if (DEBUG_POINTERS) Log.v(TAG, "MT @"                                        + di.mAbs.mAddingPointerOffset                                        + " X:" + ev.value);                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {                                di.mAbs.changed = true;                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset                                    + MotionEvent.SAMPLE_Y] = ev.value;                                if (DEBUG_POINTERS) Log.v(TAG, "MT @"                                        + di.mAbs.mAddingPointerOffset                                        + " Y:" + ev.value);                            } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {                                di.mAbs.changed = true;                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset                                    + MotionEvent.SAMPLE_SIZE] = ev.value;                            }                                                // Process position events from single touch protocol.                        } else if (ev.type == RawInputEvent.EV_ABS &&                                (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {                            if (ev.scancode == RawInputEvent.ABS_X) {                                di.mAbs.changed = true;                                di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_Y) {                                di.mAbs.changed = true;                                di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {                                di.mAbs.changed = true;                                di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA                                                 + MotionEvent.SAMPLE_PRESSURE] = ev.value;                            } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {                                di.mAbs.changed = true;                                di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA                                                 + MotionEvent.SAMPLE_SIZE] = ev.value;                            }                            // Process movement events from trackball (mouse) protocol.                        } else if (ev.type == RawInputEvent.EV_REL &&                                (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {                            // Add this relative movement into our totals.                            if (ev.scancode == RawInputEvent.REL_X) {                                di.mRel.changed = true;                                di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;                            } else if (ev.scancode == RawInputEvent.REL_Y) {                                di.mRel.changed = true;                                di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;                            }                        }                                                // Handle multitouch protocol sync: tells us that the                        // driver has returned all data for -one- of the pointers                        // that is currently down.                        if (ev.type == RawInputEvent.EV_SYN                                && ev.scancode == RawInputEvent.SYN_MT_REPORT                                && di.mAbs != null) {                            di.mAbs.changed = true;                            if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {                                // If the value is <= 0, the pointer is not                                // down, so keep it in the count.                                                                if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset                                                      + MotionEvent.SAMPLE_PRESSURE] != 0) {                                    final int num = di.mAbs.mNextNumPointers+1;                                    di.mAbs.mNextNumPointers = num;                                    if (DEBUG_POINTERS) Log.v(TAG,                                            "MT_REPORT: now have " + num + " pointers");                                    final int newOffset = (num <= InputDevice.MAX_POINTERS)                                            ? (num * MotionEvent.NUM_SAMPLE_DATA)                                            : (InputDevice.MAX_POINTERS *                                                    MotionEvent.NUM_SAMPLE_DATA);                                    di.mAbs.mAddingPointerOffset = newOffset;                                    di.mAbs.mNextData[newOffset                                            + MotionEvent.SAMPLE_PRESSURE] = 0;                                } else {                                    if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");                                }                            }                                                // Handle general event sync: all data for the current                        // event update has been delivered.                        } else if (send || (ev.type == RawInputEvent.EV_SYN                                && ev.scancode == RawInputEvent.SYN_REPORT)) {                            if (mDisplay != null) {                                if (!mHaveGlobalMetaState) {                                    computeGlobalMetaStateLocked();                                }                                                                MotionEvent me;                                                                InputDevice.MotionState ms = di.mAbs;                                if (ms.changed) {                                    ms.changed = false;                                                                        if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))                                            == RawInputEvent.CLASS_TOUCHSCREEN) {                                        ms.mNextNumPointers = 0;                                        if (ms.mDown[0]) {                                            System.arraycopy(di.curTouchVals, 0,                                                    ms.mNextData, 0,                                                    MotionEvent.NUM_SAMPLE_DATA);                                            ms.mNextNumPointers++;                                        }                                    }                                                                        if (BAD_TOUCH_HACK) {                                        ms.dropBadPoint(di);                                    }                                                                        boolean doMotion = !monitorVirtualKey(di,                                            ev, curTime, curTimeNano);                                                                        if (doMotion && ms.mNextNumPointers > 0                                            && (ms.mLastNumPointers == 0                                                    || ms.mSkipLastPointers)) {                                        doMotion = !generateVirtualKeyDown(di,                                                ev, curTime, curTimeNano);                                    }                                                                        if (doMotion) {                                        // XXX Need to be able to generate                                        // multiple events here, for example                                        // if two fingers change up/down state                                        // at the same time.                                        do {                                            me = ms.generateAbsMotion(di, curTime,                                                    curTimeNano, mDisplay,                                                    mOrientation, mGlobalMetaState);                                            if (DEBUG_POINTERS) Log.v(TAG, "Absolute: x="                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_X]                                                    + " y="                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]                                                    + " ev=" + me);                                            if (me != null) {                                                if (WindowManagerPolicy.WATCH_POINTER) {                                                    Log.i(TAG, "Enqueueing: " + me);                                                }                                                addLocked(di, curTimeNano, ev.flags,                                                        RawInputEvent.CLASS_TOUCHSCREEN, me);                                            }                                        } while (ms.hasMore());                                    } else {                                        // We are consuming movement in the                                        // virtual key area...  but still                                        // propagate this to the previous                                        // data for comparisons.                                        int num = ms.mNextNumPointers;                                        if (num > InputDevice.MAX_POINTERS) {                                            num = InputDevice.MAX_POINTERS;                                        }                                        System.arraycopy(ms.mNextData, 0,                                                ms.mLastData, 0,                                                num * MotionEvent.NUM_SAMPLE_DATA);                                        ms.mLastNumPointers = num;                                        ms.mSkipLastPointers = true;                                    }                                                                        ms.finish();                                }                                                                ms = di.mRel;                                if (ms.changed) {                                    ms.changed = false;                                                                        me = ms.generateRelMotion(di, curTime,                                            curTimeNano,                                            mOrientation, mGlobalMetaState);                                    if (false) Log.v(TAG, "Relative: x="                                            + di.mRel.mNextData[MotionEvent.SAMPLE_X]                                            + " y="                                            + di.mRel.mNextData[MotionEvent.SAMPLE_Y]                                            + " ev=" + me);                                    if (me != null) {                                        addLocked(di, curTimeNano, ev.flags,                                                RawInputEvent.CLASS_TRACKBALL, me);                                    }                                                                        ms.finish();                                }                            }                        }                    }                                } catch (RuntimeException exc) {                    Log.e(TAG, "InputReaderThread uncaught exception", exc);                }            }        }    };

    private static native boolean readEvent(RawInputEvent outEvent);

framworks.base.server.jni

static jbooleanandroid_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,                                          jobject event){    gLock.lock();    sp<EventHub> hub = gHub;    if (hub == NULL) {        hub = new EventHub;        gHub = hub;    }    gLock.unlock();    int32_t deviceId;    int32_t type;    int32_t scancode, keycode;    uint32_t flags;    int32_t value;    nsecs_t when;    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,            &flags, &value, &when);    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);    env->SetIntField(event, gInputOffsets.mType, (jint)type);    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);    env->SetIntField(event, gInputOffsets.mValue, value);    env->SetLongField(event, gInputOffsets.mWhen,                        (jlong)(nanoseconds_to_milliseconds(when)));    return res;}


InputDispatcherThread从KeyQ中读取Events,找到Window Manager中的Focus Window,通过Focus Window记录的mClient接口,将Events专递到Client端。Client端在根据自己的Focus Path传递事件,直到事件被处理。

    private final class InputDispatcherThread extends Thread {        // Time to wait when there is nothing to do: 9999 seconds.        static final int LONG_WAIT=9999*1000;        public InputDispatcherThread() {            super("InputDispatcher");        }        @Override        public void run() {            while (true) {                try {                    process();                } catch (Exception e) {                    Log.e(TAG, "Exception in input dispatcher", e);                }            }        }        private void process() {            android.os.Process.setThreadPriority(                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);            // The last key event we saw            KeyEvent lastKey = null;            // Last keydown time for auto-repeating keys            long lastKeyTime = SystemClock.uptimeMillis();            long nextKeyTime = lastKeyTime+LONG_WAIT;            long downTime = 0;            // How many successive repeats we generated            int keyRepeatCount = 0;            // Need to report that configuration has changed?            boolean configChanged = false;            while (true) {                long curTime = SystemClock.uptimeMillis();                if (DEBUG_INPUT) Log.v(                    TAG, "Waiting for next key: now=" + curTime                    + ", repeat @ " + nextKeyTime);                // Retrieve next event, waiting only as long as the next                // repeat timeout.  If the configuration has changed, then                // don't wait at all -- we'll report the change as soon as                // we have processed all events.                QueuedEvent ev = mQueue.getEvent(                    (int)((!configChanged && curTime < nextKeyTime)                            ? (nextKeyTime-curTime) : 0));                if (DEBUG_INPUT && ev != null) Log.v(                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);                if (MEASURE_LATENCY) {                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);                }                if (lastKey != null && !mPolicy.allowKeyRepeat()) {                    // cancel key repeat at the request of the policy.                    lastKey = null;                    downTime = 0;                    lastKeyTime = curTime;                    nextKeyTime = curTime + LONG_WAIT;                }                try {                    if (ev != null) {                        curTime = SystemClock.uptimeMillis();                        int eventType;                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {                            eventType = eventType((MotionEvent)ev.event);                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {                            eventType = LocalPowerManager.BUTTON_EVENT;                        } else {                            eventType = LocalPowerManager.OTHER_EVENT;                        }                        try {                            if ((curTime - mLastBatteryStatsCallTime)                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {                                mLastBatteryStatsCallTime = curTime;                                mBatteryStats.noteInputEvent();                            }                        } catch (RemoteException e) {                            // Ignore                        }                        if (eventType != TOUCH_EVENT                                && eventType != LONG_TOUCH_EVENT                                && eventType != CHEEK_EVENT) {                            mPowerManager.userActivity(curTime, false,                                    eventType, false);                        } else if (mLastTouchEventType != eventType                                || (curTime - mLastUserActivityCallTime)                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {                            mLastUserActivityCallTime = curTime;                            mLastTouchEventType = eventType;                            mPowerManager.userActivity(curTime, false,                                    eventType, false);                        }                        switch (ev.classType) {                            case RawInputEvent.CLASS_KEYBOARD:                                KeyEvent ke = (KeyEvent)ev.event;                                if (ke.isDown()) {                                    lastKey = ke;                                    downTime = curTime;                                    keyRepeatCount = 0;                                    lastKeyTime = curTime;                                    nextKeyTime = lastKeyTime                                            + ViewConfiguration.getLongPressTimeout();    //a21966,Creekside: if it is a SLIDER close event do not wait the key up event                                    if (ke.getScanCode() == 254){        lastKey = null;downTime = 0;lastKeyTime = curTime;nextKeyTime = curTime + LONG_WAIT;    }                                    if (DEBUG_INPUT) Log.v(                                        TAG, "Received key down: first repeat @ "                                        + nextKeyTime);                                } else {                                    lastKey = null;                                    downTime = 0;                                    // Arbitrary long timeout.                                    lastKeyTime = curTime;                                    nextKeyTime = curTime + LONG_WAIT;                                    if (DEBUG_INPUT) Log.v(                                        TAG, "Received key up: ignore repeat @ "                                        + nextKeyTime);                                }                                dispatchKey((KeyEvent)ev.event, 0, 0);                                mQueue.recycleEvent(ev);                                break;                            case RawInputEvent.CLASS_TOUCHSCREEN:                                //Log.i(TAG, "Read next event " + ev);                                dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);                                break;                            case RawInputEvent.CLASS_TRACKBALL:                                dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);                                break;                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:                                configChanged = true;                                break;                            default:                                mQueue.recycleEvent(ev);                            break;                        }                    } else if (configChanged) {                        configChanged = false;                        sendNewConfiguration();                    } else if (lastKey != null) {                        curTime = SystemClock.uptimeMillis();                        // Timeout occurred while key was down.  If it is at or                        // past the key repeat time, dispatch the repeat.                        if (DEBUG_INPUT) Log.v(                            TAG, "Key timeout: repeat=" + nextKeyTime                            + ", now=" + curTime);                        if (curTime < nextKeyTime) {                            continue;                        }                        lastKeyTime = nextKeyTime;                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;                        keyRepeatCount++;                        if (DEBUG_INPUT) Log.v(                            TAG, "Key repeat: count=" + keyRepeatCount                            + ", next @ " + nextKeyTime);                        KeyEvent newEvent;                        if (downTime != 0 && (downTime                                + ViewConfiguration.getLongPressTimeout())                                <= curTime) {                            newEvent = KeyEvent.changeTimeRepeat(lastKey,                                    curTime, keyRepeatCount,                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);                            downTime = 0;                        } else {                            newEvent = KeyEvent.changeTimeRepeat(lastKey,                                    curTime, keyRepeatCount);                        }                        dispatchKey(newEvent, 0, 0);                    } else {                        curTime = SystemClock.uptimeMillis();                        lastKeyTime = curTime;                        nextKeyTime = curTime + LONG_WAIT;                    }                } catch (Exception e) {                    Log.e(TAG,                        "Input thread received uncaught exception: " + e, e);                }            }        }    }

更多相关文章

  1. 读写系统设置
  2. Android(安卓)View绘制过程以及事件传递原理
  3. 【android】点击事件穿透解决方案
  4. 读取android手机流量信息
  5. Android软件开发之获取通讯录联系人信息 + android联系人信息的
  6. Accessibility辅助功能--一念天堂,一念地狱
  7. Android——View的事件体系
  8. 浅入浅出Android(015):使用ImageView显示网络图片
  9. Android事件分发机制全解析

随机推荐

  1. 业务数据分析
  2. pyinstaller打包总结
  3. aipai服务架构
  4. 量化交易
  5. 关于分库分表后的数据统计异构方案
  6. 已安装nginx动态添加模块
  7. ce内存寻址基址
  8. h5图片展示和ajax上传
  9. downloadonly使用小技巧,快速给无外网系统
  10. vSAN集群 无法识别磁盘处理