Android之Input子系统事件分发流程

Android创建窗口机制,请看如下转载:

http://blog.csdn.net/sfdev/article/details/9130527

一、Android4.2系统服务侧——与View关系

1.服务端channel注册过程

frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  mInputChannel = new InputChannel(); //创建InputChannel
  res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
    getHostVisibility(), mDisplay.getDisplayId(),
    mAttachInfo.mContentInsets, mInputChannel);  //创建与上述InputChannel对应的通道至服务端
  /*
  mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
  frameworks/base/core/java/android/view/WindowManagerGlobal.java
  public static IWindowSession getWindowSession(Looper mainLooper) {
    IWindowManager windowManager = getWindowManagerService();
    sWindowSession = windowManager.openSession(
                            imm.getClient(), imm.getInputContext());
    return sWindowSession;
  }
  frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
  public IWindowSession openSession(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, client, inputContext);
    return session;
  }
  */
  mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, 
    Looper.myLooper());  //将本通道注册进InputEventReceiver
}
frameworks/base/services/java/com/android/server/wm/Session.java
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
  return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
}
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
  //以下包括了管道的创建(用于WMS与应用程序View通信)等
  String name = win.makeInputChannelName();
  InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
  win.setInputChannel(inputChannels[0]);
  inputChannels[1].transferTo(outInputChannel);
  //以下便是注册至server端过程
  //final InputManagerService mInputManager;
  mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
frameworks/base/service/java/com/android/server/input/InputManagerService.java
public void registerInputChannel(InputChannel inputChannel,
            InputWindowHandle inputWindowHandle) {
  nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
private static native void nativeRegisterInputChannel(int ptr, InputChannel inputChannel,
            InputWindowHandle inputWindowHandle, boolean monitor);
frameworks/base/service/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
        jint ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
  NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
  status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
}
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
  return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
  //mInputManager = new InputManager(eventHub, this, this);
  /*
  frameworks/base/services/input/InputManager.cpp
  sp<InputDispatcherInterface> InputManager::getDispatcher() {
    return mDispatcher;
  }
  mDispatcher = new InputDispatcher(dispatcherPolicy);
  */
}

frameworks/base/services/input/InputDispatcher.cpp

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
  int fd = inputChannel->getFd();
  mConnectionsByFd.add(fd, connection);
  //该fd监听对应的处理函数为handleReceiveCallback
  mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
}
2.服务端上报过程

2.1.InputReaderThread线程从驱动读取数据并处理,如实现鼠标右键上报back键即在此处完成、以下代码将会看到


frameworks/base/services/input/InputReader.cpp

bool InputReaderThread::threadLoop() {
  mReader->loopOnce();
  return true;
}
void InputReader::loopOnce() {
  size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
  /*
  frameworks/base/services/input/EventHub.cpp
  size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    int32_t readSize = read(device->fd, readBuffer,
      sizeof(struct input_event) * capacity);//从驱动读取事件
  }
  */
  processEventsLocked(mEventBuffer, count);
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
  processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
         const RawEvent* rawEvents, size_t count) {
  device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
  //该设备的所有mapper进行处理;注意:这里使用了多态
  for (size_t i = 0; i < numMappers; i++) {
    InputMapper* mapper = mMappers[i];
    mapper->process(rawEvent);
  }
}
//以下就是各个mapper
//CursorInput鼠标设备
void CursorInputMapper::process(const RawEvent* rawEvent) {
  mCursorButtonAccumulator.process(rawEvent);
  mCursorMotionAccumulator.process(rawEvent);
  mCursorScrollAccumulator.process(rawEvent);
  if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
    sync(rawEvent->when);
  }
}
//CursorButtonAccumulator::process(const RawEvent* rawEvent)
//CursorMotionAccumulator::process(const RawEvent* rawEvent)
//CursorScrollAccumulator::process(const RawEvent* rawEvent)
void CursorInputMapper::sync(nsecs_t when) {
  int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
  /*
  uint32_t CursorButtonAccumulator::getButtonState() const {
    if (mBtnRight) {
      //Changed by tank for mouse left button to back  
      result |= AMOTION_EVENT_BUTTON_BACK;
      //  result |= AMOTION_EVENT_BUTTON_SECONDARY;
    }
    if (mBtnMiddle) {
      //change by tank@tcl.com for mouse middle button to menu
      result |= AMOTION_EVENT_BUTTON_MENU;
      //result |= AMOTION_EVENT_BUTTON_TERTIARY;
    }
  }
  */

  getListener()->notifyMotion(&args);

  synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
      policyFlags, lastButtonState, currentButtonState);  
  /*
  static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
      nsecs_t when, int32_t deviceId, uint32_t source,
      uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
              lastButtonState, currentButtonState,
              AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
              lastButtonState, currentButtonState,
              AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
    //add by tank  mouse key event middle->menu.
    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
              lastButtonState, currentButtonState,
              AMOTION_EVENT_BUTTON_MENU, AKEYCODE_MENU);
    //end tank
  }
  static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
          nsecs_t when, int32_t deviceId, uint32_t source,
          uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
          int32_t buttonState, int32_t keyCode) {
    if ((action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState)
	&& (currentButtonState & buttonState))
	|| (action == AKEY_EVENT_ACTION_UP
	&& (lastButtonState & buttonState)
	&& !(currentButtonState & buttonState))) {
      context->getListener()->notifyKey(&args);
    }
  }
  */
}
//TouchInput触摸板设备
void SingleTouchInputMapper::process(const RawEvent* rawEvent) 
  TouchInputMapper::process(rawEvent);
  mSingleTouchMotionAccumulator.process(rawEvent);
}
//SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) 
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
  TouchInputMapper::process(rawEvent);
  mMultiTouchMotionAccumulator.process(rawEvent);
}
//MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) 
void TouchInputMapper::process(const RawEvent* rawEvent) {
  mCursorButtonAccumulator.process(rawEvent);
  mCursorScrollAccumulator.process(rawEvent);
  mTouchButtonAccumulator.process(rawEvent);
  if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
    sync(rawEvent->when);
  }
}
//TouchButtonAccumulator::process(const RawEvent* rawEvent) 
void TouchInputMapper::sync(nsecs_t when) {
  dispatchTouches(when, policyFlags);
}
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
  dispatchMotion(when, policyFlags, mSource,
    AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState,
    AMOTION_EVENT_EDGE_FLAG_NONE,
    mCurrentCookedPointerData.pointerProperties,
    mCurrentCookedPointerData.pointerCoords,
    mCurrentCookedPointerData.idToIndex,
    currentIdBits, -1,
    mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
    int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
    const PointerProperties* properties, const PointerCoords* coords,
    const uint32_t* idToIndex, BitSet32 idBits,
    int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
  getListener()->notifyMotion(&args);
}
//SwitchInput设备
void SwitchInputMapper::process(const RawEvent* rawEvent) {
  sync(rawEvent->when);
}
void SwitchInputMapper::sync(nsecs_t when) {
  getListener()->notifySwitch(&args);
}
//JoystickInput游戏手柄设备
void JoystickInputMapper::process(const RawEvent* rawEvent) {
  sync(rawEvent->when, false /*force*/);
}
void JoystickInputMapper::sync(nsecs_t when, bool force) {
  getListener()->notifyMotion(&args);
}
//KeyboardInput按键设备
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
  processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
         int32_t scanCode, uint32_t policyFlags) {
  getListener()->notifyKey(&args);
}

2.2.InputReaderThread线程对系统层按键做处理(比较重要的是POWER键,最终在PhoneWindowManager中的interceptKeyBeforeQueueing和interceptMotionBeforeQueueingWhenScreenOff)后分发给InputDispatcherThread线程,以下分析将看到之前一个鼠标操作过程中无法待机的问题解决

以下几种情况都会唤醒InputDispatcherThread线程,即调用mLooper->wake()唤醒正在awoken()中的InputReaderThread线程:

frameworks/base/services/input/InputDispatcher.cpp

//有新输入设备注册等
void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
  ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime);
  needWake = enqueueInboundEventLocked(newEntry);
  if (needWake) {
    mLooper->wake();
  }
}
//分发按键事件
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
  //说明:PhoneWindowManager.java中policyFlags位决定系统按键(如HOME等是否需要由系统处理)
  mPolicy->interceptKeyBeforeQueueing(&event, policyFlags);
  //以下分析将看到,该调用实际是在PhoneWindowManager.java中实现
  /*
  frameworks/base/services/input/InputManager.cpp
  InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
  }
  frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
  NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper) {
    mInputManager = new InputManager(eventHub, this, this);
  }
  void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
        uint32_t& policyFlags) {
    wmActions = env->CallIntMethod(mServiceObj,
                    gServiceClassInfo.interceptKeyBeforeQueueing,
                    keyEventObj, policyFlags, isScreenOn);
    //如下函数中将有待机和开机的处理
    handleInterceptActions(wmActions, when, policyFlags);
  }
  frameworks/base/service/java/com/android/server/input/InputManagerService.java
  private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
    return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
                event, policyFlags, isScreenOn);
  }
  frameworks/base/service/java/com/android/server/SystemServer.java
  inputManager = new InputManagerService(context, wmHandler);
  wm = WindowManagerService.main(context, power, display, inputManager,
      uiHandler, wmHandler,
      factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
      !firstBoot, onlyCore);
  inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
  frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
  public InputMonitor getInputMonitor() {
    return mInputMonitor;
  }
  frameworks/base/service/java/com/android/server/wm/InputMonitor.java
  public int interceptKeyBeforeQueueing(
            KeyEvent event, int policyFlags, boolean isScreenOn) {
    return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
  }
  public InputMonitor(WindowManagerService service) {
    mService = service;
  }
  frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
  final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
  frameworks/base/core/java/com/android/internal/policy/PolicyManager.java
  public static WindowManagerPolicy makeNewWindowManager() {
    return sPolicy.makeNewWindowManager();
  }
  private static final String POLICY_IMPL_CLASS_NAME =
        "com.android.internal.policy.impl.Policy";
  Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
  sPolicy = (IPolicy)policyClass.newInstance();
  frameworks/base/core/java/com/android/internal/policy/Policy.java
  package com.android.internal.policy.impl;
  public class Policy implements IPolicy {
    public WindowManagerPolicy makeNewWindowManager() {
      return new PhoneWindowManager();
    }
  }
  frameworks/base/core/java/com/android/internal/policy/PhoneWindowManager.java
  public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
    case KeyEvent.KEYCODE_POWER: {
      result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
    }
  }
  */
  KeyEntry* newEntry = new KeyEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, flags, args->keyCode, args->scanCode,
                metaState, repeatCount, args->downTime);
  needWake = enqueueInboundEventLocked(newEntry);
  if (needWake) {
    mLooper->wake();
  }
}
//分发Motion事件
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
  mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);
  /*
  如上分析,不再累赘;该接口是:
  frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
  void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
    jint wmActions = env->CallIntMethod(mServiceObj,
                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
                        policyFlags);
    handleInterceptActions(wmActions, when,  policyFlags);
  }
  如上interceptMotionBeforeQueueingWhenScreenOff在PhoneWindowManager中实现;分析同上,不再累赘:
  frameworks/base/core/java/com/android/internal/policy/PhoneWindowManager.java
  public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
    //result |= ACTION_WAKE_UP;
    //add by tank
    result = result & (~ACTION_WAKE_UP);
    //end tank
    return result;
  }
  看看handleInterceptActions函数:
  void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
        uint32_t& policyFlags) {
    //接上边PhoneWindowManager中interceptKeyBeforeQueueing对于power键的返回值可知,系统将待机
    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
      #if DEBUG_INPUT_DISPATCHER_POLICY
      ALOGD("handleInterceptActions: Going to sleep.");
      #endif
      android_server_PowerManagerService_goToSleep(when);
    }
    //以下说明PhoneWindowManager中interceptMotionBeforeQueueingWhenScreenOff返回值WM_ACTION_WAKE_UP将会导致唤醒
    //当然,是可是收到motion事件的前提下
    if (wmActions & WM_ACTION_WAKE_UP) {
      #if DEBUG_INPUT_DISPATCHER_POLICY
      ALOGD("handleInterceptActions: Waking up.");
      #endif
      android_server_PowerManagerService_wakeUp(when);
    }
    //以下是可以上报给系统的
    if (wmActions & WM_ACTION_PASS_TO_USER) {
        policyFlags |= POLICY_FLAG_PASS_TO_USER;
    }
  }
  */
  MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, args->flags, args->metaState, args->buttonState,
                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                args->displayId,
                args->pointerCount, args->pointerProperties, args->pointerCoords);
  needWake = enqueueInboundEventLocked(newEntry);
  if (needWake) {
    mLooper->wake();
  }
}
//设备重置
void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
  DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId);
  needWake = enqueueInboundEventLocked(newEntry);
  if (needWake) {
    mLooper->wake();
  }
}
//C层的按键注入接口
int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
        int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
        uint32_t policyFlags) {
  needWake |= enqueueInboundEventLocked(entry);
  if (needWake) {
    mLooper->wake();
  }
}
//setInputWindows
//setFocusedApplication
//setInputDispatchMode
//setInputFilterEnabled
//transferTouchFocus
//registerInputChannel
//unregisterInputChannel
//monitor

2.3.InputDispatcherThread线程处理,根据PhoneWindowManager中的interceptKeyBeforeDispatching决定是否丢弃按键


InputDispatcherThread线程被唤醒

bool InputDispatcherThread::threadLoop() {
  mDispatcher->dispatchOnce();
  return true;
}
void InputDispatcher::dispatchOnce() {
  dispatchOnceInnerLocked(&nextWakeupTime);
  mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
  if (!mPolicy->isKeyRepeatEnabled()) {
        resetKeyRepeatLocked();
  }
  switch (mPendingEvent->type) {
    case EventEntry::TYPE_CONFIGURATION_CHANGED: {
      done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
    }
    case EventEntry::TYPE_DEVICE_RESET: {
      done = dispatchDeviceResetLocked(currentTime, typedEntry);
    }
    case EventEntry::TYPE_KEY: {
      done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
    }
    case EventEntry::TYPE_MOTION: {
      done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
    }
  }
  dropInboundEventLocked(mPendingEvent, dropReason);  //丢弃的事件!!!!
}

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
  CommandEntry* commandEntry = postCommandLocked(
                    & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
  /*
  void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
        CommandEntry* commandEntry) {
    //说明:PhoneWindowManager.java中可以截断事件而不上报,即返回-1、将被丢弃
    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
            &event, entry->policyFlags);
    if (delay < 0) {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
    } else if (!delay) {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
    } else {
        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
        entry->interceptKeyWakeupTime = now() + delay;
    }
  }
  */
  else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
    if (*dropReason == DROP_REASON_NOT_DROPPED) {
      *dropReason = DROP_REASON_POLICY; //dropReason是因为策略丢弃
    }
  }
  if (*dropReason != DROP_REASON_NOT_DROPPED) {
    setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
      ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
    return true;
  }
  dispatchEventLocked(currentTime, entry, inputTargets);
}
bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
  dispatchEventLocked(currentTime, entry, inputTargets);
}

2.4.InputDispatcherThread线程分发给应用程序进程

在这里解决了up事件上报两次的问题!!!!!!

frameworks/base/services/input/InputDispatcher.cpp

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
  pokeUserActivityLocked(eventEntry);  //和Activity相关,后边三中有设备删除的分析;基本同下
  ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
  sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
  prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
  enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
   enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); //将按键注入队列
   /*
   void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) {
     DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
            inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
            inputTarget->scaleFactor);
     if (!connection->inputState.trackKey(keyEntry,
                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags) || (dispatchEntry->resolvedFlags == 0x28)){
       //add by tankai 0x28
       delete dispatchEntry;
       return;
     }
   }
   */
   //dropInboundEventLocked
   //synthesizeCancelationEventsForAllConnectionsLocked->
   //synthesizeCancelationEventsForConnectionLocked->
   /*
   void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
        const sp<Connection>& connection, const CancelationOptions& options) {
     Vector<EventEntry*> cancelationEvents;
     connection->inputState.synthesizeCancelationEvents(currentTime,
            cancelationEvents, options);  
     //关键在这里,mKeyMementos;在enqueueDispatchEntryLocked时调用trackKey由addKeyMemento注入!!!!!!
     if (!cancelationEvents.isEmpty()) {
       enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
                    &target, InputTarget::FLAG_DISPATCH_AS_IS);
     }
   }
   */
   //enqueueDispatchEntriesLocked,注入了0x28标志的按键
   startDispatchCycleLocked(currentTime, connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {
  switch (eventEntry->type) {
    case EventEntry::TYPE_KEY: {
      status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                    keyEntry->deviceId, keyEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    keyEntry->keyCode, keyEntry->scanCode,
                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                    keyEntry->eventTime);
    }
    case EventEntry::TYPE_MOTION: {
      status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                    motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset,
                    motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
    }
  }
}
frameworks/base/libs/androidfw/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t action,
        int32_t flags,
        int32_t keyCode,
        int32_t scanCode,
        int32_t metaState,
        int32_t repeatCount,
        nsecs_t downTime,
        nsecs_t eventTime) {
  return mChannel->sendMessage(&msg);
}
status_t InputChannel::sendMessage(const InputMessage* msg) {
  do {
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
  } while (nWrite == -1 && errno == EINTR);
}

二、Android4.2系统应用程序侧——与View关系

InputManagerService也就是InputDispatcher与应用程序通信是靠looper。

说明:

  InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等。

  InputDispatcher获得按键事件后,根据当前设备的状况来优先消化事件(该过程交由PhoneWindowManager.java来处理);最后,剩余事件分发给ViewRoot;ViewRoot再分发给IME输入法或View、Activity。

1.应用程序View中channel注册过程

frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  mInputChannel = new InputChannel(); //创建InputChannel
  res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
    getHostVisibility(), mDisplay.getDisplayId(),
    mAttachInfo.mContentInsets, mInputChannel);  //创建与上述InputChannel对应的通道至服务端
  mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, 
    Looper.myLooper());  //将本通道注册进InputEventReceiver
}
final class WindowInputEventReceiver extends InputEventReceiver {
  public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
    super(inputChannel, looper);
  }
  @Override
  public void onInputEvent(InputEvent event) {
    enqueueInputEvent(event, this, 0, true);
  }
}

frameworks/base/core/java/android/view/InputEventReceiver.java

public InputEventReceiver(InputChannel inputChannel, Looper looper) {
  mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
}
private static native int nativeInit(InputEventReceiver receiver,
            InputChannel inputChannel, MessageQueue messageQueue);

frameworks/base/core/jni/android_view_InputEventReceiver.cpp

static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
        jobject inputChannelObj, jobject messageQueueObj) {
  sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverObj, inputChannel, messageQueue);
  status_t status = receiver->initialize();
}
status_t NativeInputEventReceiver::initialize() {
  int receiveFd = mInputConsumer.getChannel()->getFd();
  mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
  return OK;
}

frameworks/native/libs/utils/Looper.cpp

int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
  request.callback = callback;
}

2.应用程序View响应过程

frameworks/native/libs/utils/Looper.cpp

int Looper::pollInner(int timeoutMillis) {
  awoken(); //阻塞,等待
  int callbackResult = response.request.callback->handleEvent(fd, events, data);
}


frameworks/base/core/jni/android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
  status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime) {
  env->CallVoidMethod(mReceiverObjGlobal,
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
}
frameworks/base/core/java/android/view/InputEventReceiver.java
private void dispatchInputEvent(int seq, InputEvent event) {
        mSeqMap.put(event.getSequenceNumber(), seq);
        onInputEvent(event);
}
frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
  public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
    super(inputChannel, looper);
  }
  @Override
  public void onInputEvent(InputEvent event) {
    enqueueInputEvent(event, this, 0, true);
  }
}
void enqueueInputEvent(InputEvent event,
    InputEventReceiver receiver, int flags, boolean processImmediately) {
  scheduleProcessInputEvents();
}

/

有关handler机制请看下文:

http://blog.csdn.net/itachi85/article/details/8035333

final ViewRootHandler mHandler = new ViewRootHandler();
private void scheduleProcessInputEvents() {
  Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
  mHandler.sendMessage(msg);
}
public void handleMessage(Message msg) {
  switch (msg.what) {
    case MSG_PROCESS_INPUT_EVENTS:
      doProcessInputEvents();
  }
}

///


  这其中ViewRootImpl.java的deliverKeyEventPostIme接口中在调用mView.dispatchKeyEvent(event)返回为false时,会再次调用mFallbackEventHandler.dispatchKeyEvent(event)让系统做默认处理。

void doProcessInputEvents() {
  deliverInputEvent(q);
}
private void deliverInputEvent(QueuedInputEvent q) {
  deliverKeyEvent(q);
  deliverPointerEvent(q);
  deliverTrackballEvent(q);
  deliverGenericMotionEvent(q);
}
private void deliverKeyEvent(QueuedInputEvent q) {
  imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback); //分发给输入法
  deliverKeyEventPostIme(q);//分发给View
  /*
  private void deliverKeyEventPostIme(QueuedInputEvent q) {
    mView.dispatchKeyEvent(event) 
  }
  */
}
private void deliverPointerEvent(QueuedInputEvent q) {
  boolean handled = mView.dispatchPointerEvent(event); //分发给View
}
private void deliverTrackballEvent(QueuedInputEvent q) {
  imm.dispatchTrackballEvent(mView.getContext(), seq, event,
    mInputMethodCallback);  //分发给输入法
  deliverTrackballEventPostIme(q);  //分发给View
  /*
  private void deliverTrackballEventPostIme(QueuedInputEvent q) {
    mView.dispatchTrackballEvent(event)
  }
  */
}
private void deliverGenericMotionEvent(QueuedInputEvent q) {
  imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
    mInputMethodCallback);  //分发给输入法
  deliverGenericMotionEventPostIme(q); //分发给View
  /*
  private void deliverGenericMotionEventPostIme(QueuedInputEvent q) {
    updateJoystickDirection(event, false); //游戏手柄的摇杆就是在这处理
    mView.dispatchGenericMotionEvent(event) 
  }
  */
}

分发给应用程序Activity:

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
  public boolean dispatchKeyEvent(KeyEvent event) {
    final Callback cb = getCallback();
    //cb为应用程序MainActivity
    final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) : super.dispatchKeyEvent(event); 
    //给应用程序Activity的dispatchKeyEvent处理或交给View的dispatchKeyEvent
  }
}

而上述应用程序中的dispatchKeyEvent一般会调用其父类的该方法,例如:

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

public boolean dispatchKeyEvent(KeyEvent event) { 
  return super.dispatchKeyEvent(event);
}

应用程序Activity在分发给与之关联的某个View,如果这个View没有处理、最终交给该Activity自己处理。

应用程序有关View的设置:

private Dialog mMenuWin;
mMenuWin = new Dialog(aActivity, R.style.CameraDialog);
mMenuWin.setContentView(mMenuLayout);
mMenuWin.setOnClickListener();  //鼠标单击
mMenuWin.setOnLongClickListener();  //
mMenuWin.setOnTouchListener(); //触摸板
mMenuWin.setOnKeyListener(new OnKeyListener() {
  public boolean onKey();  //按键
  public void onClick(View v); //鼠标单击
}

frameworks/base/core/java/android/app/Activity.java

public boolean dispatchKeyEvent(KeyEvent event) {
  onUserInteraction();
  Window win = getWindow();
  if (win.superDispatchKeyEvent(event)) { //首先由Window消化,即如果View消化了、则Activity将不在回调onKeyDown
    return true;
  }
  View decor = mDecor; //如果没被消化,会调用Activity的onKeyDown
  if (decor == null) decor = win.getDecorView();
    return event.dispatch(this, decor != null ? decor.getKeyDispatcherState() : null, this);
  }
}

我们重点分析win.superDispatchKeyEvent,也就是View的处理流程:

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback {
  public boolean superDispatchKeyEvent(KeyEvent event) {
    return mDecor.superDispatchKeyEvent(event);
  }
}
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
  public boolean superDispatchKeyEvent(KeyEvent event) {      
    super.dispatchKeyEvent(event)
  }
}
frameworks/base/core/java/android/view/ViewGroup.java  //分发给View的关键部分!!!
public boolean dispatchKeyEvent(KeyEvent event) {
  mInputEventConsistencyVerifier.onKeyEvent(event, 1);
  super.dispatchKeyEvent(event)
}

frameworks/base/core/java/android/view/View.java

public boolean dispatchKeyEvent(KeyEvent event) {
  li.mOnKeyListener.onKey(this, event.getKeyCode(), event); //回调应用程序View相应方法
  event.dispatch(this, mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null, this)
  /*
  frameworks/base/core/java/android/view/KeyEvent.java
  public final boolean dispatch(Callback receiver, DispatcherState state,
    Object target) {  
    //按键响应
    boolean res = receiver.onKeyDown(mKeyCode, this); //应用程序回调函数
  }
  */
}
public final boolean dispatchPointerEvent(MotionEvent event) {
  if (event.isTouchEvent()) {
    return dispatchTouchEvent(event);
  } else {
    return dispatchGenericMotionEvent(event);
  }
}
public boolean dispatchTouchEvent(MotionEvent event) {
  //触摸板响应
  li.mOnTouchListener.onTouch(this, event) //应用程序继承OnTouchListener,实现的回调接口
  //鼠标左键响应
  onTouchEvent(event)
  /*
  public boolean onTouchEvent(MotionEvent event) {
    performClick();
    //该接口调用li.mOnClickListener.onClick(this);为应用程序继承OnClickListener的回调函数
  }
  */  
}

以下不再做分析
dispatchGenericMotionEvent

dispatchTrackballEvent

dispatchConfigurationChanged //添加或删除键盘设备Activity重启,见http://blog.csdn.net/tankai19880619/article/details/16805401

三、Input设备与Activity关系

1.InputReaderThread线程检测到设备插入删除

frameworks/base/service/input/InputReader.cpp

void InputReader::loopOnce() {
  size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
  /*
  frameworks/base/services/input/EventHub.cpp
  size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    int32_t readSize = read(device->fd, readBuffer,
      sizeof(struct input_event) * capacity);//从驱动读取事件
  }
  */
  processEventsLocked(mEventBuffer, count);
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
  case EventHubInterface::FINISHED_DEVICE_SCAN:
    handleConfigurationChangedLocked(rawEvent->when);
}
void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
  updateGlobalMetaStateLocked();
  // Enqueue configuration changed.
  NotifyConfigurationChangedArgs args(when);
  mQueuedListener->notifyConfigurationChanged(&args);
}

说明:有的平台需要在接入硬件键盘时Activity不需要刷新;可以在上处做屏蔽:

    // add by tank
    // do not send configuration change
    //NotifyConfigurationChangedArgs args(when);
    //mQueuedListener->notifyConfigurationChanged(&args);
    // end tank

2.InputReaderThread线程分发给InputDispatcherThread线程

frameworks/base/service/input/InputDispatcher.cpp

void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
  needWake = enqueueInboundEventLocked(newEntry);
  if (needWake) {
    mLooper->wake();
  }
}
3.InputReaderThread线程收到消息并处理

frameworks/base/service/input/InputDispatcher.cpp

bool InputDispatcherThread::threadLoop() {
  mDispatcher->dispatchOnce();
  return true;
}
void InputDispatcher::dispatchOnce() {
  dispatchOnceInnerLocked(&nextWakeupTime);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
  case EventEntry::TYPE_CONFIGURATION_CHANGED: {
    ConfigurationChangedEntry* typedEntry =
                static_cast<ConfigurationChangedEntry*>(mPendingEvent);
  done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
  }
}
bool InputDispatcher::dispatchConfigurationChangedLocked(
        nsecs_t currentTime, ConfigurationChangedEntry* entry) {
  CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doNotifyConfigurationChangedInterruptible);
}
void InputDispatcher::doNotifyConfigurationChangedInterruptible(
        CommandEntry* commandEntry) {
  mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
}
如上,不再做分析:

frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
  env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyConfigurationChanged, when);
}
frameworks/base/services/java/com/android/server/input/InputManagerService.cpp
private void notifyConfigurationChanged(long whenNanos) {
  mWindowManagerCallbacks.notifyConfigurationChanged();
}
如上,不再做分析:

frameworks/base/service/java/com/android/server/wm/InputMonitor.java

public void notifyConfigurationChanged() {
  mService.sendNewConfiguration();
}
frameworks/base/service/java/com/android/server/wm/WindowManagerService.java
void sendNewConfiguration() {
  mActivityManager.updateConfiguration(null);
  /*
  mActivityManager = ActivityManagerNative.getDefault();
  frameworks/base/core/java/android/app/ActivityManagerNative.java
  static public IActivityManager getDefault() {
    return gDefault.get();
  }
  private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    IBinder b = ServiceManager.getService("activity");
    IActivityManager am = asInterface(b);
    return am;
  }
  frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
  public static void setSystemProcess() {
    ActivityManagerService m = mSelf;
    ServiceManager.addService("activity", m, true);
  }
  */
}
4.交由ActivityManagerService进程处理

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

public void updateConfiguration(Configuration values) {
  updateConfigurationLocked(values, null, false, false);
}
boolean updateConfigurationLocked(Configuration values,
            ActivityRecord starting, boolean persistent, boolean initLocale) {
  kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
  public void setWindowManager(WindowManagerService wm) {
    mWindowManager = wm;
  }
}
frameworks/base/services/java/com/android/server/am/ActivityStack.java
final boolean ensureActivityConfigurationLocked(ActivityRecord r,
            int globalChanges) {
  //一般会重启Activity
  if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
    relaunchActivityLocked(r, r.configChangeFlags, false);
    return false;
  }
  //应用程序AndroidMenifest中写标记将不会重启
  r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
}
frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleActivityConfigurationChanged(IBinder token) {
  queueOrSendMessage(H.ACTIVITY_CONFIGURATION_CHANGED, token);
}
//消息循环同上,不再分析
public void handleMessage(Message msg) {
  case ACTIVITY_CONFIGURATION_CHANGED:
    handleActivityConfigurationChanged((IBinder)msg.obj);
}
final void handleActivityConfigurationChanged(IBinder token) {
  performConfigurationChanged(r.activity, mCompatConfiguration);
}
private static void performConfigurationChanged(ComponentCallbacks2 cb, Configuration config) {
  cb.onConfigurationChanged(config); //回调Activity类的onConfigurationChanged方法
}

四、项目问题

1.resumeTopActivity时的Activity重启。

http://blog.csdn.net/jivin_shen/article/details/6839175

  操作逻辑:打开Launcher界面下的一个应用(比如播放器),完后接入USB键盘;之后退出该应用,也就是resumeTopActivity到Launcher时也引发了config配置更新导致的Activity重启。

  原理以及解决部分:

frameworks/base/services/java/com/android/server/am/ActivityStack.java

final boolean resumeTopActivityLocked(ActivityRecord prev) {
  return resumeTopActivityLocked(prev, null);
}
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
  Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
                            mService.mConfiguration,
                            next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
}

frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

public Configuration updateOrientationFromAppTokens(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
  config = updateOrientationFromAppTokensLocked(currentConfig,
                    freezeThisOneIfNeeded);
}
private Configuration updateOrientationFromAppTokensLocked(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
  computeScreenConfigurationLocked(mTempConfiguration)
}
boolean computeScreenConfigurationLocked(Configuration config) {
  if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN) {
    //change by tank
    config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
    //config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
    //end tank
  }
  else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
                             && config.navigation == Configuration.NAVIGATION_NONAV) {
    //change by tank
    //config.navigation = Configuration.NAVIGATION_DPAD;
    //navigationPresence |= presenceFlag;
    //end tank
  }
  if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
    //change by tank
    //config.keyboard = Configuration.KEYBOARD_QWERTY;
    //keyboardPresence |= presenceFlag;
    //end tank
  }
}

2.面板设备与虚拟驱动导致的up上报两次:

drop类按键

down或up:

dispatchOnceInnerLocked>

dropInboundEventLocked>synthesizeCancelationEventsForAllConnectionsLocked-synthesizeCancelationEventsForConnectionLocked>inputState.synthesizeCancelationEvents->mKeyMementos.itemAt(i),最后上报系统(synthesizeCancelationEventsForConnectionLocked调用enqueueDispatchEntryLocked)

非drop类按键

down:

dispatchOnceInnerLocked->

dispatchKeyLocked->dispatchEventLocked->prepareDispatchCycleLocked->enqueueDispatchEntriesLocked->enqueueDispatchEntryLocked->InputState::trackKey->addKeyMemento  //只在down时保存对up的处理

问题:

面板down->drop

虚拟down->非drop,保存up

面板down->drop,将虚拟保存的up送上去

虚拟up->非drop,直接上报

结果——两个虚拟的up

修改方法:

frameworks/base/service/input/InputDispatcher.cpp

void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) 
{
  if (!connection->inputState.trackKey(keyEntry,
                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)/*add by tank@tcl.com end */ || (dispatchEntry->resolvedFlags == 0x28))   
  {
    #if DEBUG_DISPATCH_CYCLE
    ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
                    connection->getInputChannelName());
    #endif
    delete dispatchEntry;
    return; // skip the inconsistent event
  }
  /*
  //add by tankai
  if(dispatchEntry->resolvedFlags == 0x28 && keyEntry->deviceId == 3){
    ALOGD("TK--------->>>delete sim KeyMementos up\n");
    delete dispatchEntry;
    return; // skip the inconsistent event
  }
  //end tankai
  */
}

3.焦点request错误导致不能响应按键

正确调用:setFocusable(true)和requestFocus()重新获取焦点

错误调用:setFocusable(false)和requestFocus()

系统侧为该应用tv.huan.deezer强制修改:

frameworks/base/core/java/android/view/View.java

public final boolean requestFocus() {
        Log.d("TKTK","TK---->>>View.java>>>>requestFocus()");//add by tank
        if(SystemProperties.get("sys.user.camera",null).equals("tv.huan.deezer"))
        {
          setFocusable(true);
        }
        //end tank
        return requestFocus(View.FOCUS_DOWN);
    }


  • 3
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值