touchmode

针对source不是非touchscreen设备进行判断

<!-- Whether to start in touch mode -->
<bool name="config_defaultInTouchMode">true</bool> 默认开启touchmode

ViewRootImpl.java

private int processPointerEvent(QueuedInputEvent q) {
    final MotionEvent event = (MotionEvent)q.mEvent;

    // Translate the pointer event for compatibility, if needed.
    if (mTranslator != null) {
        mTranslator.translateEventInScreenToAppWindow(event);
    }

    // Enter touch mode on down or scroll, if it is coming from a touch screen device,
    // exit otherwise.
    final int action = event.getAction();
    if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
        ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));//判断设备类型如果不是touchscreen 则显示焦点
    }
@UnsupportedAppUsage
boolean ensureTouchMode(boolean inTouchMode) {
    if (DBG) Log.d("touchmode", "ensureTouchMode(" + inTouchMode + "), current "
            + "touch mode is " + mAttachInfo.mInTouchMode);
    if (mAttachInfo.mInTouchMode == inTouchMode) return false;

    // tell the window manager
    try {
        mWindowSession.setInTouchMode(inTouchMode);
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    }

    // handle the change
    return ensureTouchModeLocally(inTouchMode);
}

WindowManagerService.java

// 设置touchmode
@Override
public void setInTouchMode(boolean mode) {
    synchronized (mGlobalLock) {
        mInTouchMode = mode;
    }
}
//添加window
public int addWindow(
1578            if (mInTouchMode) {
1579                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; // 判断是否添加touchmode
1580            }
//动态加view的
relayoutWindow(
result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
}


case REPORT_FOCUS_CHANGE: or case REPORT_LOSING_FOCUS
        newFocus.reportFocusChangedSerialized(true, mInTouchMode);

WindowState.java

/* Report a focus change.  Must be called with no locks held, and consistently
 * from the same serialized thread (such as dispatched from a handler).
 */
void reportFocusChangedSerialized(boolean focused, boolean inTouchMode) {
    try {
        mClient.windowFocusChanged(focused, inTouchMode);
    } catch (RemoteException e) {
    }
    if (mFocusCallbacks != null) {
        final int N = mFocusCallbacks.beginBroadcast();
        for (int i=0; i<N; i++) {
            IWindowFocusObserver obs = mFocusCallbacks.getBroadcastItem(i);
            try {
                if (focused) {
                    obs.focusGained(mWindowId.asBinder());
                } else {
                    obs.focusLost(mWindowId.asBinder());
                }
            } catch (RemoteException e) {
            }
        }
        mFocusCallbacks.finishBroadcast();
    }
}

ViewRootImpl.java

public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
    synchronized (this) {
        mWindowFocusChanged = true;
        mUpcomingWindowFocus = hasFocus;
        mUpcomingInTouchMode = inTouchMode;
    }
    Message msg = Message.obtain();
    msg.what = MSG_WINDOW_FOCUS_CHANGED;
    mHandler.sendMessage(msg);
}
private void handleWindowFocusChanged() {
    final boolean hasWindowFocus;
    final boolean inTouchMode;
    synchronized (this) {
        if (!mWindowFocusChanged) {
            return;
        }
        mWindowFocusChanged = false;
        hasWindowFocus = mUpcomingWindowFocus;
        inTouchMode = mUpcomingInTouchMode;//设置mode
    }
    if (sNewInsetsMode != NEW_INSETS_MODE_NONE) {
        // TODO (b/131181940): Make sure this doesn't leak Activity with mActivityConfigCallback
        // config changes.
        if (hasWindowFocus) {
            mInsetsController.onWindowFocusGained();
        } else {
            mInsetsController.onWindowFocusLost();
        }
    }

    if (mAdded) {
        profileRendering(hasWindowFocus);

        if (hasWindowFocus) {
            ensureTouchModeLocally(inTouchMode);// 设置模式
            if (mAttachInfo.mThreadedRenderer != null && mSurface.isValid()) {
                mFullRedrawNeeded = true;
                try {
                    final WindowManager.LayoutParams lp = mWindowAttributes;
                    final Rect surfaceInsets = lp != null ? lp.surfaceInsets : null;
                    mAttachInfo.mThreadedRenderer.initializeIfNeeded(
                            mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
                } catch (OutOfResourcesException e) {
                    Log.e(mTag, "OutOfResourcesException locking surface", e);
                    try {
                        if (!mWindowSession.outOfMemory(mWindow)) {
                            Slog.w(mTag, "No processes killed for memory;"
                                    + " killing self");
                            Process.killProcess(Process.myPid());
                        }
                    } catch (RemoteException ex) {
                    }
                    // Retry in a bit.
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
                            MSG_WINDOW_FOCUS_CHANGED), 500);
                    return;
                }
            }
        }

        mAttachInfo.mHasWindowFocus = hasWindowFocus;

        mLastWasImTarget = WindowManager.LayoutParams
                .mayUseInputMethod(mWindowAttributes.flags);

        InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
        if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
            imm.onPreWindowFocus(mView, hasWindowFocus);
        }
        if (mView != null) {
            mAttachInfo.mKeyDispatchState.reset();
            mView.dispatchWindowFocusChanged(hasWindowFocus);
            mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
            if (mAttachInfo.mTooltipHost != null) {
                mAttachInfo.mTooltipHost.hideTooltip();
            }
        }

        // Note: must be done after the focus change callbacks,
        // so all of the view state is set up correctly.
        if (hasWindowFocus) {
            if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
                imm.onPostWindowFocus(mView, mView.findFocus(),
                        mWindowAttributes.softInputMode,
                        !mHasHadWindowFocus, mWindowAttributes.flags);
            }
            // Clear the forward bit.  We can just do this directly, since
            // the window manager doesn't care about it.
            mWindowAttributes.softInputMode &=
                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            ((WindowManager.LayoutParams) mView.getLayoutParams())
                    .softInputMode &=
                    ~WindowManager.LayoutParams
                            .SOFT_INPUT_IS_FORWARD_NAVIGATION;
            mHasHadWindowFocus = true;

            // Refocusing a window that has a focused view should fire a
            // focus event for the view since the global focused view changed.
            fireAccessibilityFocusEventIfHasFocusedNode();
        } else {
            if (mPointerCapture) {
                handlePointerCaptureChanged(false);
            }
        }
    }
    mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
}

设置当前view的mode
/**
 * Ensure that the touch mode for this window is set, and if it is changing,
 * take the appropriate action.
 * @param inTouchMode Whether we want to be in touch mode.
 * @return True if the touch mode changed and focus changed was changed as a result
 */
private boolean ensureTouchModeLocally(boolean inTouchMode) {
    if (DBG) Log.d("touchmode", "ensureTouchModeLocally(" + inTouchMode + "), current "
            + "touch mode is " + mAttachInfo.mInTouchMode);

    if (mAttachInfo.mInTouchMode == inTouchMode) return false;

    mAttachInfo.mInTouchMode = inTouchMode;
    mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode);

    return (inTouchMode) ? enterTouchMode() : leaveTouchMode();
}

private boolean enterTouchMode() {
    if (mView != null && mView.hasFocus()) {
        // note: not relying on mFocusedView here because this could
        // be when the window is first being added, and mFocused isn't
        // set yet.
        final View focused = mView.findFocus();
        if (focused != null && !focused.isFocusableInTouchMode()) {
            final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
            if (ancestorToTakeFocus != null) {
                // there is an ancestor that wants focus after its
                // descendants that is focusable in touch mode.. give it
                // focus
                return ancestorToTakeFocus.requestFocus();
            } else {
                // There's nothing to focus. Clear and propagate through the
                // hierarchy, but don't attempt to place new focus.
                focused.clearFocusInternal(null, true, false);
                return true;
            }
        }
    }
    return false;
}
View.java

/**
 * Call this to try to give focus to a specific view or to one of its
 * descendants.
 *
 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
 * false), or if it can't be focused due to other conditions (not focusable in touch mode
 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not
 * enabled, or has no size).
 *
 * See also {@link #focusSearch(int)}, which is what you call to say that you
 * have focus, and you want your parent to look for the next one.
 *
 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments
 * {@link #FOCUS_DOWN} and <code>null</code>.
 *
 * @return Whether this view or one of its descendants actually took focus.
 */
public final boolean requestFocus() {
    return requestFocus(View.FOCUS_DOWN);
}
/**
 * Call this to try to give focus to a specific view or to one of its
 * descendants and give it a hint about what direction focus is heading.
 *
 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns
 * false), or if it is focusable and it is not focusable in touch mode
 * ({@link #isFocusableInTouchMode}) while the device is in touch mode.
 *
 * See also {@link #focusSearch(int)}, which is what you call to say that you
 * have focus, and you want your parent to look for the next one.
 *
 * This is equivalent to calling {@link #requestFocus(int, Rect)} with
 * <code>null</code> set for the previously focused rectangle.
 *
 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
 * @return Whether this view or one of its descendants actually took focus.
 */
public final boolean requestFocus(int direction) {
    return requestFocus(direction, null);
}

public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
    return requestFocusNoSearch(direction, previouslyFocusedRect);
}

private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) {
    // need to be focusable
    if (!canTakeFocus()) {
        return false;
    }

    // need to be focusable in touch mode if in touch mode
    if (isInTouchMode() &&
        (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) {
           return false;
    }

    // need to not have any parents blocking us
    if (hasAncestorThatBlocksDescendantFocus()) {
        return false;
    }

    if (!isLayoutValid()) {
        mPrivateFlags |= PFLAG_WANTS_FOCUS;
    } else {
        clearParentsWantFocus();
    }

    handleFocusGainInternal(direction, previouslyFocusedRect);
    return true;
}


 /**
 * Give this view focus. This will cause
 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
 *
 * Note: this does not check whether this {@link View} should get focus, it just
 * gives it focus no matter what.  It should only be called internally by framework
 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}.
 *
 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
 *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which
 *        focus moved when requestFocus() is called. It may not always
 *        apply, in which case use the default View.FOCUS_DOWN.
 * @param previouslyFocusedRect The rectangle of the view that had focus
 *        prior in this View's coordinate system.
 */
void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) {
    if (DBG) {
        System.out.println(this + " requestFocus()");
    }

    if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {
        mPrivateFlags |= PFLAG_FOCUSED;

        View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null;

        if (mParent != null) {
            mParent.requestChildFocus(this, this);
            updateFocusedInCluster(oldFocus, direction);
        }

        if (mAttachInfo != null) {
            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
        }

        onFocusChanged(true, direction, previouslyFocusedRect);
        refreshDrawableState();
    }
}

   protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
     @Nullable Rect previouslyFocusedRect) {
 if (gainFocus) {
     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); //设置焦点
 } else {
     notifyViewAccessibilityStateChangedIfNeeded(
             AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
 }


/**
 * Sends an accessibility event of the given type. If accessibility is
 * not enabled this method has no effect. The default implementation calls
 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first
 * to populate information about the event source (this View), then calls
 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to
 * populate the text content of the event source including its descendants,
 * and last calls
 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
 * on its parent to request sending of the event to interested parties.
 * <p>
 * If an {@link AccessibilityDelegate} has been specified via calling
 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
 * responsible for handling this call.
 * </p>
 *
 * @param eventType The type of the event to send, as defined by several types from
 * {@link android.view.accessibility.AccessibilityEvent}, such as
 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or
 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}.
 *
 * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)
 * @see AccessibilityDelegate
 */
public void sendAccessibilityEvent(int eventType) {
    if (mAccessibilityDelegate != null) {
        mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
    } else {
        sendAccessibilityEventInternal(eventType);
    }
}

public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
    if (mAccessibilityDelegate != null) {
        mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
    } else {
        sendAccessibilityEventUncheckedInternal(event);
    }
}

/**
 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
 *
 * Note: Called from the default {@link AccessibilityDelegate}.
 *
 * @hide
 */
public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
    // Panes disappearing are relevant even if though the view is no longer visible.
    boolean isWindowStateChanged =
            (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes()
            & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0);
    if (!isShown() && !isWindowDisappearedEvent) {
        return;
    }
    onInitializeAccessibilityEvent(event);
    // Only a subset of accessibility events populates text content.
    if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) {
        dispatchPopulateAccessibilityEvent(event);
    }
    // In the beginning we called #isShown(), so we know that getParent() is not null.
    ViewParent parent = getParent();
    if (parent != null) {
        getParent().requestSendAccessibilityEvent(this, event);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值