add View::onFilterTouchEventForSecurity

This commit is contained in:
侯歌 2024-07-10 17:15:12 +08:00
parent 18acce3218
commit 316f8996f3
3 changed files with 176 additions and 142 deletions

View File

@ -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();
}

View File

@ -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);

View File

@ -2899,133 +2899,135 @@ 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();
}
// 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;
}
}else{
intercepted=true;
}
if (intercepted || mFirstTouchTarget != nullptr) {
ev.setTargetAccessibilityFocus(false);
}
// Check for cancelation.
const bool canceled = resetCancelNextUpFlag(this)|| actionMasked == MotionEvent::ACTION_CANCEL;
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::vector<View*>preorderedList = buildTouchDispatchChildList();
const bool customOrder = preorderedList.empty() && isChildrenDrawingOrderEnabled();
std::vector<View*>&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;j<childrenCount;j++){
if(children[childIndex]==mChildren[j]){
mLastTouchDownIndex=j; break;
}
}
}else{
mLastTouchDownIndex = childIndex;
std::vector<View*>preorderedList = buildTouchDispatchChildList();
const bool customOrder = preorderedList.empty() && isChildrenDrawingOrderEnabled();
std::vector<View*>&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;j<childrenCount;j++){
if(children[childIndex]==mChildren[j]){
mLastTouchDownIndex=j; break;
}
}
}else{
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX() ;
mLastTouchDownY = ev.getY() ;
newTouchTarget=addTouchTarget(child,idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
ev.setTargetAccessibilityFocus(false);
}
ev.setTargetAccessibilityFocus(false);
preorderedList.clear();
}
preorderedList.clear();
}
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;
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);