private void addInputWindowHandleLw(
      final InputWindowHandle inputWindowHandle,
      final WindowState child,
      int flags,
      final int type,
      final boolean isVisible,
      final boolean hasFocus,
      final boolean hasWallpaper) {
    // Add a window to our list of input windows.
    inputWindowHandle.name = child.toString();
    flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags);
    inputWindowHandle.layoutParamsFlags = flags;
    inputWindowHandle.layoutParamsType = type;
    inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
    inputWindowHandle.visible = isVisible;
    inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
    inputWindowHandle.hasFocus = hasFocus;
    inputWindowHandle.hasWallpaper = hasWallpaper;
    inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
    inputWindowHandle.layer = child.mLayer;
    inputWindowHandle.ownerPid = child.mSession.mPid;
    inputWindowHandle.ownerUid = child.mSession.mUid;
    inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;

    final Rect frame = child.mFrame;
    inputWindowHandle.frameLeft = frame.left;
    inputWindowHandle.frameTop = frame.top;
    inputWindowHandle.frameRight = frame.right;
    inputWindowHandle.frameBottom = frame.bottom;

    if (child.isDockedInEffect()) {
      // Adjust to account for non-resizeable tasks that's scrolled
      inputWindowHandle.frameLeft += child.mXOffset;
      inputWindowHandle.frameTop += child.mYOffset;
      inputWindowHandle.frameRight += child.mXOffset;
      inputWindowHandle.frameBottom += child.mYOffset;
    }

    if (child.mGlobalScale != 1) {
      // If we are scaling the window, input coordinates need
      // to be inversely scaled to map from what is on screen
      // to what is actually being touched in the UI.
      inputWindowHandle.scaleFactor = 1.0f / child.mGlobalScale;
    } else {
      inputWindowHandle.scaleFactor = 1;
    }

    if (DEBUG_INPUT) {
      Slog.d(TAG_WM, "addInputWindowHandle: " + child + ", " + inputWindowHandle);
    }
    addInputWindowHandleLw(inputWindowHandle);
  }
  /* Called when the current input focus changes.
   * Layer assignment is assumed to be complete by the time this is called.
   */
  public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
    if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) {
      Slog.d(TAG_WM, "Input focus has changed to " + newWindow);
    }

    if (newWindow != mInputFocus) {
      if (newWindow != null && newWindow.canReceiveKeys()) {
        // Displaying a window implicitly causes dispatching to be unpaused.
        // This is to protect against bugs if someone pauses dispatching but
        // forgets to resume.
        newWindow.mToken.paused = false;
      }

      mInputFocus = newWindow;
      setUpdateInputWindowsNeededLw();

      if (updateInputWindows) {
        updateInputWindowsLw(false /*force*/);
      }
    }
  }
  /* Updates the cached window information provided to the input dispatcher. */
  public void updateInputWindowsLw(boolean force) {
    if (!force && !mUpdateInputWindowsNeeded) {
      return;
    }
    mUpdateInputWindowsNeeded = false;

    if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");

    // Populate the input window list with information about all of the windows that
    // could potentially receive input.
    // As an optimization, we could try to prune the list of windows but this turns
    // out to be difficult because only the native code knows for sure which window
    // currently has touch focus.
    final ArrayList<WindowState> windows = mService.mWindows;

    // If there's a drag in flight, provide a pseudowindow to catch drag input
    final boolean inDrag = (mService.mDragState != null);
    if (inDrag) {
      if (WindowManagerService.DEBUG_DRAG) {
        Log.d(WindowManagerService.TAG, "Inserting drag window");
      }
      final InputWindowHandle dragWindowHandle = mService.mDragState.mDragWindowHandle;
      if (dragWindowHandle != null) {
        addInputWindowHandleLw(dragWindowHandle);
      } else {
        Slog.w(
            WindowManagerService.TAG,
            "Drag is in progress but there is no " + "drag window handle.");
      }
    }

    final int NFW = mService.mFakeWindows.size();
    for (int i = 0; i < NFW; i++) {
      addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle);
    }

    final int N = windows.size();
    for (int i = N - 1; i >= 0; i--) {
      final WindowState child = windows.get(i);
      final InputChannel inputChannel = child.mInputChannel;
      final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
      if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
        // Skip this window because it cannot possibly receive input.
        continue;
      }

      final int flags = child.mAttrs.flags;
      final int type = child.mAttrs.type;

      final boolean hasFocus = (child == mInputFocus);
      final boolean isVisible = child.isVisibleLw();
      final boolean hasWallpaper =
          (child == mService.mWallpaperTarget)
              && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);

      // If there's a drag in progress and 'child' is a potential drop target,
      // make sure it's been told about the drag
      if (inDrag && isVisible) {
        mService.mDragState.sendDragStartedIfNeededLw(child);
      }

      // Add a window to our list of input windows.
      inputWindowHandle.name = child.toString();
      inputWindowHandle.layoutParamsFlags = flags;
      inputWindowHandle.layoutParamsType = type;
      inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
      inputWindowHandle.visible = isVisible;
      inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
      inputWindowHandle.hasFocus = hasFocus;
      inputWindowHandle.hasWallpaper = hasWallpaper;
      inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
      inputWindowHandle.layer = child.mLayer;
      inputWindowHandle.ownerPid = child.mSession.mPid;
      inputWindowHandle.ownerUid = child.mSession.mUid;
      inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;

      final Rect frame = child.mFrame;
      inputWindowHandle.frameLeft = frame.left;
      inputWindowHandle.frameTop = frame.top;
      inputWindowHandle.frameRight = frame.right;
      inputWindowHandle.frameBottom = frame.bottom;

      if (child.mGlobalScale != 1) {
        // If we are scaling the window, input coordinates need
        // to be inversely scaled to map from what is on screen
        // to what is actually being touched in the UI.
        inputWindowHandle.scaleFactor = 1.0f / child.mGlobalScale;
      } else {
        inputWindowHandle.scaleFactor = 1;
      }

      child.getTouchableRegion(inputWindowHandle.touchableRegion);

      addInputWindowHandleLw(inputWindowHandle);
    }

    // Send windows to native code.
    mService.mInputManager.setInputWindows(mInputWindowHandles);

    // Clear the list in preparation for the next round.
    clearInputWindowHandlesLw();

    if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
  }