In general, touch events are encapsulated into the android system service will be touch status. The MotionEvent,. Call the android app. Activity# dispatchTouchEvent method is passed to the Activity.
//android.app.Activity#dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == motionEvent.action_down) {// Empty method, comment can be used to indicate that the current activity is starting to interact with the user and better handle status bar notification events. I'm not going to go into that. onUserInteraction(); } // This determines the PhoneWindow to callThe #superDispatchTouchEvent method is the core method. The superDispatchTouchEvent method passes in a MotionEvent that passes touch events to the activity's layout. When a control in the layout returns true, the relevant touch event has been consumed and the dispatchTouchEvent is terminated. When all controls in the layout return false, it indicates that the controls in the layout did not handle touch events and is handled by the current Android.app.activity# onTouchEvent method.
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
Copy the code
//PhoneWindow#superDispatchTouchEvent// This is the top-level view of the window, //mDecor is a top-level view private DecorView mDecor. // Call the DecorView directly here#superDispatchTouchEvent
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
Copy the code
//DecorView#superDispatchTouchEvent// The parent class of the DecorView call, ViewGroup#dispatchTouchEvent
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
Copy the code
The touch event is passed from Acivity to the Activity’s contentView by the above three steps.
//ViewGroup#dispatchTouchEvent@override public Boolean dispatchTouchEvent(MotionEvent ev) {// Check whether ACTION_DOWN and ACTION_UP are matched. Error logs are also printed.if(mInputEventConsistencyVerifier ! = null) { mInputEventConsistencyVerifier.onTouchEvent(ev, 1); } // If the event targets the accessibility focused view and this is it, Start // Normal event dispatch. Maybe a retrieve is what will handle the click.if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
ev.setTargetAccessibilityFocus(false);
}
boolean handled = false; // Event security filter, discard the touch event if the window is blocked.if(onFilterTouchEventForSecurity(ev)) { final int action = ev.getAction(); final int actionMasked = action & MotionEvent.ACTION_MASK; // Handle an initial Down event.if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event forThe previous gesture // Due to an app switch, ANR, or some other state change. cancelAndClearTouchTargets(ev); // Reset the current touch state. resetTouchState(); } // CheckforInterception. // Check the interception of the child view. final boolean intercepted; // mFirstTouchTarget is null when the touch event first arrives here.if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget ! = null) {/ / public void requestDisallowInterceptTouchEvent (Boolean disallowIntercept) / / is called to set whether to ban intercept, Fale final Boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT)! = 0;if(! DisallowIntercept) {// onInterceptTouchEvent is used to intercept touch events in our viewGroup. We override this method to intercept related touch events according to our needs. When he returned totrueThe following touch events are passed to the onTouchEvent of the viewGroup instead of the onInterceptTouchEvent, which should be returned from the onTouchEventtrueTo indicate that the touch event processing is complete. intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore actionin case it was changed
} else {
intercepted = false; }}else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
// If intercepted, start normal event dispatch. Also if there is already
// a view that is handling the gesture, doNormal event Dispatch. // Handle barrier-free services.if(intercepted || mFirstTouchTarget ! = null) { ev.setTargetAccessibilityFocus(false);
}
// Check for cancelation.
final boolean canceled = resetCancelNextUpFlag(this)
|| actionMasked == MotionEvent.ACTION_CANCEL;
// Update list of touch targets for pointer down, ifneeded. final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) ! = 0; // Reset newTouchTaget TouchTarget newTouchTarget = null; boolean alreadyDispatchedToNewTouchTarget =false; // Determines whether the event is cancelled and whether it is intercepted.if(! canceled && ! intercepted) {// Handle barrier-free services. View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null; // MotionEvent.ACTION_HOVER_MOVE is pointer dependent. ACTION_POINTER_DOWN refers to DOWN except for the first finger of the operation // Handle DOWN eventsif(actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked ACTION_HOVER_MOVE) {// Final int actionIndex = ev.getActionIndex(); // always 0for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touch targets for this pointer id in caseThey // have become out of sync. // Clear the touchTarget of other fingers and set the touchTarget to the current finger. // TODO touchTarget is a linked list. removePointersFromTouchTargets(idBitsToAssign); final int childrenCount = mChildrenCount;if(newTouchTarget == null && childrenCount ! = 0) { finalfloat x = ev.getX(actionIndex);
final floaty = ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. final ArrayList<View> preorderedList = buildTouchDispatchChildList(); / / is there a custom drawing order final Boolean customOrder = preorderedList = = null && isChildrenDrawingOrderEnabled (); final View[] children = mChildren;for(int i = childrenCount - 1; i >= 0; i--) { final int childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); / /... // If mFirstTouchTarget is null, return NULL // If mFirstTouchTarget queue contains this child View, return the touchTarget of this child view. // Otherwise null is returned. newTouchTarget = getTouchTarget(child);if(newTouchTarget ! = null) { // Child is already receiving touch within its bounds. // Give it the new pointerin addition to the ones it is handling.
newTouchTarget.pointerIdBits |= idBitsToAssign;
break; } // reset the cancel and up flags? TODO resetCancelNextUpFlag(child); // event.getPointerIdBits(); TODO // Call the child view's dispatchTouchEvent(transformedEvent); Pass the touch event to the child view. But when the child view is null, the parent view's dispatchTouchEvent(transformedEvent) is called.if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if(preorderedList ! = null) { // childIndex points into presorted list, find original indexfor (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break; }}}else{ mLastTouchDownIndex = childIndex; } mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); TODO newTouchTarget = addTouchTarget(Child, idBitsToAssign); // Whether the touch event has been handed to newTouchTarget for processing. alreadyDispatchedToNewTouchTarget =true;
break;
}
// The accessibility focus didn't handle the event, so clear // the flag and do a normal dispatch to all children. ev.setTargetAccessibilityFocus(false); } if (preorderedList ! = null) preorderedList.clear(); } if (newTouchTarget == null && mFirstTouchTarget ! = null) { // Did not find a child to receive the event. // Assign the pointer to the least recently added target. // No child view receives the touch event and assigns newTouchTarget to the target of the last touch event. newTouchTarget = mFirstTouchTarget; while (newTouchTarget.next ! = null) { newTouchTarget = newTouchTarget.next; } newTouchTarget.pointerIdBits |= idBitsToAssign; If (mFirstTouchTarget == null) {// No touch targets so treat this as an Ordinary view. // No child view, treat itself as a view to handle touch events. handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { // Dispatch to touch targets, excluding the new touch target if we already // dispatched to it. Cancel touch targets if necessary. TouchTarget predecessor = null; TouchTarget target = mFirstTouchTarget; // Distribute the touch event to the touchTarget, excluding the already distributed newTouchTarget. // Distribute cancel events to other TouchTargets if needed. The newTouchTarget method is reset to NUll every time it comes in. The touch event is passed DOWN for the first time. NewTouchTarget and mFirstTouchTarget will be assigned, mFirstTouchTarget will not be NUll, and newTouchTarget will be reset to NUll. The child view that handled the Down event is then given the responsibility to handle subsequent events. while (target ! = null) { final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted; if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } if (cancelChild) { if (predecessor == null) { mFirstTouchTarget = next; } else { predecessor.next = next; } target.recycle(); target = next; continue; } } predecessor = target; target = next; }} // Update list of touch targets for pointer up or cancel, if needed. if (canceled || actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { resetTouchState(); } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { final int actionIndex = ev.getActionIndex(); final int idBitsToRemove = 1 << ev.getPointerId(actionIndex); removePointersFromTouchTargets(idBitsToRemove); }} // Unprocessed event if (! handled && mInputEventConsistencyVerifier ! = null) { mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1); } return handled; }Copy the code