diff --git a/src/gui/view/view.cc b/src/gui/view/view.cc index 2680f8bb..29e35a24 100755 --- a/src/gui/view/view.cc +++ b/src/gui/view/view.cc @@ -143,7 +143,10 @@ View::View(Context*ctx,const AttributeSet&attrs){ setPivotY(attrs.getDimensionPixelSize("transformPivotY",0)); setKeyboardNavigationCluster( attrs.getBoolean("keyboardNavigationCluster",false) ); - + if(attrs.getBoolean("filterTouchesWhenObscured",false)){ + viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; + viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; + } if( attrs.getBoolean( "focusableInTouchMode" , false ) ){ viewFlagValues &= ~FOCUSABLE_AUTO; viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; @@ -161,6 +164,10 @@ View::View(Context*ctx,const AttributeSet&attrs){ viewFlagValues |= LONG_CLICKABLE; viewFlagMasks |= LONG_CLICKABLE; } + if( !attrs.getBoolean("saveEnabled",true)){ + viewFlagValues |=SAVE_DISABLED; + viewFlagMasks |=SAVE_DISABLED_MASK; + } if(attrs.getBoolean("duplicateParentState",false)){ viewFlagValues |= DUPLICATE_PARENT_STATE; viewFlagMasks |= DUPLICATE_PARENT_STATE; @@ -6061,6 +6068,27 @@ bool View::canReceivePointerEvents()const{ return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != nullptr; } +bool View::getFilterTouchesWhenObscured() const{ + return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; +} + +View& View::setFilterTouchesWhenObscured(bool enabled) { + setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, + FILTER_TOUCHES_WHEN_OBSCURED); + //calculateAccessibilityDataSensitive(); + return *this; +} + +bool View::onFilterTouchEventForSecurity(MotionEvent& event){ + //noinspection RedundantIfStatement + if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 + && (event.getFlags() & MotionEvent::FLAG_WINDOW_IS_OBSCURED) != 0) { + // Window is obscured, drop this touch. + return false; + } + return true; +} + bool View::dispatchTrackballEvent(MotionEvent& event){ if (mInputEventConsistencyVerifier) { mInputEventConsistencyVerifier->onTrackballEvent(event, 0); @@ -6157,10 +6185,10 @@ bool View::dispatchGenericMotionEvent(MotionEvent&event){ if (mInputEventConsistencyVerifier) mInputEventConsistencyVerifier->onGenericMotionEvent(event, 0); if ((source & InputDevice::SOURCE_CLASS_POINTER) != 0) { - int action = event.getAction(); - if (action == MotionEvent::ACTION_HOVER_ENTER - || action == MotionEvent::ACTION_HOVER_MOVE - || action == MotionEvent::ACTION_HOVER_EXIT) { + const int action = event.getAction(); + if ((action == MotionEvent::ACTION_HOVER_ENTER) + || (action == MotionEvent::ACTION_HOVER_MOVE) + || (action == MotionEvent::ACTION_HOVER_EXIT)) { if (dispatchHoverEvent(event)) { return true; } @@ -6184,29 +6212,31 @@ bool View::dispatchTouchEvent(MotionEvent&event){ if (mInputEventConsistencyVerifier) mInputEventConsistencyVerifier->onTouchEvent(event, 0); - if (actionMasked == MotionEvent::ACTION_UP || - actionMasked == MotionEvent::ACTION_CANCEL || - (actionMasked == MotionEvent::ACTION_DOWN && !result)) { + if ( (actionMasked == MotionEvent::ACTION_UP) || + (actionMasked == MotionEvent::ACTION_CANCEL) || + (actionMasked == MotionEvent::ACTION_DOWN && !result)) { stopNestedScroll(); } - if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { - result = true; - } + if(onFilterTouchEventForSecurity(event)){ + if (((mViewFlags & ENABLED_MASK) == ENABLED) && handleScrollBarDragging(event)) { + result = true; + } - if ( mListenerInfo && mListenerInfo->mOnTouchListener - && (mViewFlags & ENABLED_MASK) == ENABLED - && mListenerInfo->mOnTouchListener(*this, event)) { - result = true; - } + if ( mListenerInfo && mListenerInfo->mOnTouchListener + && ((mViewFlags & ENABLED_MASK) == ENABLED) + && mListenerInfo->mOnTouchListener(*this, event)) { + result = true; + } - if(!result&& onTouchEvent(event)){ - result=true; + if(!result&& onTouchEvent(event)){ + result=true; + } } if (!result && mInputEventConsistencyVerifier) mInputEventConsistencyVerifier->onUnhandledEvent(event, 0); - if (actionMasked == MotionEvent::ACTION_UP || - actionMasked == MotionEvent::ACTION_CANCEL || + if ( (actionMasked == MotionEvent::ACTION_UP) || + (actionMasked == MotionEvent::ACTION_CANCEL) || (actionMasked == MotionEvent::ACTION_DOWN && !result)) { stopNestedScroll(); } diff --git a/src/gui/view/view.h b/src/gui/view/view.h index abf8d4f0..b47bf444 100755 --- a/src/gui/view/view.h +++ b/src/gui/view/view.h @@ -236,16 +236,15 @@ public: SCROLLBARS_VERTICAL = 0x200 , SCROLLBARS_MASK = 0x300 , - CLIPCHILDREN = 0x400 , - TRANSPARENT = 0x800 , + FILTER_TOUCHES_WHEN_OBSCURED = 0x400,//CLIPCHILDREN = 0x400 ,TRANSPARENT = 0x800 , - FADING_EDGE_NONE =0x000000 , + FADING_EDGE_NONE = 0x000000 , FADING_EDGE_HORIZONTAL= 0x1000 , FADING_EDGE_VERTICAL = 0x2000 , FADING_EDGE_MASK = 0x3000 , CLICKABLE = 0x4000 , - DRAWING_CACHE_ENABLED = 0x8000 , + DRAWING_CACHE_ENABLED = 0x8000 , SAVE_DISABLED = 0x000010000, SAVE_DISABLED_MASK = 0x000010000, @@ -262,10 +261,10 @@ public: DRAWING_CACHE_QUALITY_AUTO = 0x00000000 , DRAWING_CACHE_QUALITY_MASK = 0x00180000 , - MEASURED_HEIGHT_STATE_SHIFT=16 , - MEASURED_STATE_TOO_SMALL=0x1000000 , - MEASURED_SIZE_MASK =0x00ffffff , - MEASURED_STATE_MASK=0xff000000 , + MEASURED_HEIGHT_STATE_SHIFT= 16 , + MEASURED_STATE_TOO_SMALL= 0x1000000 , + MEASURED_SIZE_MASK = 0x00ffffff , + MEASURED_STATE_MASK= 0xff000000 , //FocusDirection{ FOCUS_BACKWARD=0x01 , @@ -612,7 +611,10 @@ protected: virtual void dispatchCancelPendingInputEvents(); virtual void onCancelPendingInputEvents(); bool canReceivePointerEvents()const; + bool getFilterTouchesWhenObscured()const; + View& setFilterTouchesWhenObscured(bool enabled); virtual bool dispatchHoverEvent(MotionEvent&event); + virtual bool onFilterTouchEventForSecurity(MotionEvent& event); virtual bool dispatchTrackballEvent(MotionEvent& event); virtual bool dispatchCapturedPointerEvent(MotionEvent& event); virtual bool dispatchGenericPointerEvent(MotionEvent& event); diff --git a/src/gui/view/viewgroup.cc b/src/gui/view/viewgroup.cc index 1bcec2ea..568073ce 100755 --- a/src/gui/view/viewgroup.cc +++ b/src/gui/view/viewgroup.cc @@ -2899,134 +2899,136 @@ bool ViewGroup::dispatchTouchEvent(MotionEvent&ev){ } bool handled = false; - if (actionMasked == MotionEvent::ACTION_DOWN) { - cancelAndClearTouchTargets(&ev); - resetTouchState(); - } - // Check for interception. - bool intercepted=false; - if((actionMasked == MotionEvent::ACTION_DOWN)||mFirstTouchTarget){ - const bool disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; - if (!disallowIntercept) { - intercepted = onInterceptTouchEvent(ev); - ev.setAction(action); // restore action in case it was changed + if(onFilterTouchEventForSecurity(ev)){ + if (actionMasked == MotionEvent::ACTION_DOWN) { + cancelAndClearTouchTargets(&ev); + resetTouchState(); } - }else{ - intercepted=true; - } - - if (intercepted || mFirstTouchTarget != nullptr) { - ev.setTargetAccessibilityFocus(false); - } - // Check for cancelation. - const bool canceled = resetCancelNextUpFlag(this)|| actionMasked == MotionEvent::ACTION_CANCEL; + // Check for interception. + bool intercepted=false; + if((actionMasked == MotionEvent::ACTION_DOWN)||mFirstTouchTarget){ + const bool disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; + if (!disallowIntercept) { + intercepted = onInterceptTouchEvent(ev); + ev.setAction(action); // restore action in case it was changed + } + }else{ + intercepted=true; + } + + if (intercepted || mFirstTouchTarget != nullptr) { + ev.setTargetAccessibilityFocus(false); + } + // Check for cancelation. + const bool canceled = resetCancelNextUpFlag(this)|| actionMasked == MotionEvent::ACTION_CANCEL; - const bool split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; - TouchTarget* newTouchTarget = nullptr; - bool alreadyDispatchedToNewTouchTarget = false; + const bool split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; + TouchTarget* newTouchTarget = nullptr; + bool alreadyDispatchedToNewTouchTarget = false; - if(!canceled && !intercepted){ - if( (actionMasked == MotionEvent::ACTION_DOWN) || (split && (actionMasked == MotionEvent::ACTION_POINTER_DOWN)) - || (actionMasked == MotionEvent::ACTION_HOVER_MOVE) ){ - const int actionIndex = ev.getActionIndex(); // always 0 for down - const int idBitsToAssign = split ? (1 << ev.getPointerId(actionIndex)) : TouchTarget::ALL_POINTER_IDS; + if(!canceled && !intercepted){ + if( (actionMasked == MotionEvent::ACTION_DOWN) || (split && (actionMasked == MotionEvent::ACTION_POINTER_DOWN)) + || (actionMasked == MotionEvent::ACTION_HOVER_MOVE) ){ + const int actionIndex = ev.getActionIndex(); // always 0 for down + const int idBitsToAssign = split ? (1 << ev.getPointerId(actionIndex)) : TouchTarget::ALL_POINTER_IDS; - removePointersFromTouchTargets(idBitsToAssign); - const int childrenCount = mChildren.size(); - if ((newTouchTarget == nullptr) && childrenCount){ - const int x = ev.getXDispatchLocation(actionIndex); - const int y = ev.getYDispatchLocation(actionIndex); + removePointersFromTouchTargets(idBitsToAssign); + const int childrenCount = mChildren.size(); + if ((newTouchTarget == nullptr) && childrenCount){ + const int x = ev.getXDispatchLocation(actionIndex); + const int y = ev.getYDispatchLocation(actionIndex); - std::vectorpreorderedList = buildTouchDispatchChildList(); - const bool customOrder = preorderedList.empty() && isChildrenDrawingOrderEnabled(); - std::vector&children = mChildren; - for(int i = childrenCount-1;i >= 0;i--){ - const int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); - View* child = getAndVerifyPreorderedView(preorderedList, children, childIndex); - if (!canViewReceivePointerEvents(*child) || !isTransformedTouchPointInView(x, y,*child, nullptr)) { - ev.setTargetAccessibilityFocus(false); - continue; - } - - newTouchTarget = getTouchTarget(child); - if (newTouchTarget) { - // Child is already receiving touch within its bounds. - // Give it the new pointer in addition to the ones it is handling. - newTouchTarget->pointerIdBits |= idBitsToAssign; - break; - } - - resetCancelNextUpFlag(child); - if(dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)){ - mLastTouchDownTime = ev.getDownTime(); - if(preorderedList.size()){ - for(int j=0;jpreorderedList = buildTouchDispatchChildList(); + const bool customOrder = preorderedList.empty() && isChildrenDrawingOrderEnabled(); + std::vector&children = mChildren; + for(int i = childrenCount-1;i >= 0;i--){ + const int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); + View* child = getAndVerifyPreorderedView(preorderedList, children, childIndex); + if (!canViewReceivePointerEvents(*child) || !isTransformedTouchPointInView(x, y,*child, nullptr)) { + ev.setTargetAccessibilityFocus(false); + continue; } - mLastTouchDownX = ev.getX() ; - mLastTouchDownY = ev.getY() ; - newTouchTarget=addTouchTarget(child,idBitsToAssign); - alreadyDispatchedToNewTouchTarget = true; - break; + + newTouchTarget = getTouchTarget(child); + if (newTouchTarget) { + // Child is already receiving touch within its bounds. + // Give it the new pointer in addition to the ones it is handling. + newTouchTarget->pointerIdBits |= idBitsToAssign; + break; + } + + resetCancelNextUpFlag(child); + if(dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)){ + mLastTouchDownTime = ev.getDownTime(); + if(preorderedList.size()){ + for(int j=0;jnext) { - newTouchTarget = newTouchTarget->next; + if ( (newTouchTarget == nullptr) && mFirstTouchTarget) { + // Did not find a child to receive the event. + // Assign the pointer to the least recently added target. + newTouchTarget = mFirstTouchTarget; + while (newTouchTarget->next) { + newTouchTarget = newTouchTarget->next; + } + newTouchTarget->pointerIdBits |= idBitsToAssign; } - newTouchTarget->pointerIdBits |= idBitsToAssign; } } - } - - // Dispatch to touch targets. - if (mFirstTouchTarget == nullptr){ - handled = dispatchTransformedTouchEvent(ev, canceled, nullptr,TouchTarget::ALL_POINTER_IDS); - }else{ - TouchTarget* predecessor = nullptr; - TouchTarget* target = mFirstTouchTarget; - while (target ) { - TouchTarget* next = target->next; - if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { - handled = true; - } else { - const bool cancelChild = resetCancelNextUpFlag(target->child)|| intercepted; - if (dispatchTransformedTouchEvent(ev, cancelChild, target->child, target->pointerIdBits)) { + + // Dispatch to touch targets. + if (mFirstTouchTarget == nullptr){ + handled = dispatchTransformedTouchEvent(ev, canceled, nullptr,TouchTarget::ALL_POINTER_IDS); + }else{ + TouchTarget* predecessor = nullptr; + TouchTarget* target = mFirstTouchTarget; + while (target ) { + TouchTarget* next = target->next; + if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; - } - if (cancelChild) { - if (predecessor == nullptr) mFirstTouchTarget = next; - else predecessor->next = next; - target->recycle(); - target = next; - continue; - } + } else { + const bool cancelChild = resetCancelNextUpFlag(target->child)|| intercepted; + if (dispatchTransformedTouchEvent(ev, cancelChild, target->child, target->pointerIdBits)) { + handled = true; + } + if (cancelChild) { + if (predecessor == nullptr) mFirstTouchTarget = next; + else predecessor->next = next; + target->recycle(); + target = next; + continue; + } + } + predecessor = target; + target = next; } - 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) ) { - int actionIndex = ev.getActionIndex(); - int idBitsToRemove = 1 << ev.getPointerId(actionIndex); - removePointersFromTouchTargets(idBitsToRemove); - } + // 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) ) { + int actionIndex = ev.getActionIndex(); + int idBitsToRemove = 1 << ev.getPointerId(actionIndex); + removePointersFromTouchTargets(idBitsToRemove); + } + } if (!handled && mInputEventConsistencyVerifier) mInputEventConsistencyVerifier->onUnhandledEvent(ev, 1); return handled;