コード例 #1
0
ファイル: ViewGroup.cs プロジェクト: hakeemsm/XobotOS
		public override bool dispatchTouchEvent(android.view.MotionEvent ev)
		{
			if (mInputEventConsistencyVerifier != null)
			{
				mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
			}
			bool handled = false;
			if (onFilterTouchEventForSecurity(ev))
			{
				int action = ev.getAction();
				int actionMasked = action & android.view.MotionEvent.ACTION_MASK;
				// Handle an initial down.
				if (actionMasked == android.view.MotionEvent.ACTION_DOWN)
				{
					// Throw away all previous state when starting a new touch gesture.
					// The framework may have dropped the up or cancel event for the previous gesture
					// due to an app switch, ANR, or some other state change.
					cancelAndClearTouchTargets(ev);
					resetTouchState();
				}
				// Check for interception.
				bool intercepted;
				if (actionMasked == android.view.MotionEvent.ACTION_DOWN || mFirstTouchTarget != 
					null)
				{
					bool disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
					if (!disallowIntercept)
					{
						intercepted = onInterceptTouchEvent(ev);
						ev.setAction(action);
					}
					else
					{
						// restore action in case it was changed
						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;
				}
				// Check for cancelation.
				bool canceled = resetCancelNextUpFlag(this) || actionMasked == android.view.MotionEvent
					.ACTION_CANCEL;
				// Update list of touch targets for pointer down, if needed.
				bool split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
				android.view.ViewGroup.TouchTarget newTouchTarget = null;
				bool alreadyDispatchedToNewTouchTarget = false;
				if (!canceled && !intercepted)
				{
					if (actionMasked == android.view.MotionEvent.ACTION_DOWN || (split && actionMasked
						 == android.view.MotionEvent.ACTION_POINTER_DOWN) || actionMasked == android.view.MotionEvent
						.ACTION_HOVER_MOVE)
					{
						int actionIndex = ev.getActionIndex();
						// always 0 for down
						int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex) : android.view.ViewGroup
							.TouchTarget.ALL_POINTER_IDS;
						// Clean up earlier touch targets for this pointer id in case they
						// have become out of sync.
						removePointersFromTouchTargets(idBitsToAssign);
						int childrenCount = mChildrenCount;
						if (childrenCount != 0)
						{
							// Find a child that can receive the event.
							// Scan children from front to back.
							android.view.View[] children = mChildren;
							float x = ev.getX(actionIndex);
							float y = ev.getY(actionIndex);
							{
								for (int i = childrenCount - 1; i >= 0; i--)
								{
									android.view.View child = children[i];
									if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child
										, null))
									{
										continue;
									}
									newTouchTarget = getTouchTarget(child);
									if (newTouchTarget != null)
									{
										// 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))
									{
										// Child wants to receive touch within its bounds.
										mLastTouchDownTime = ev.getDownTime();
										mLastTouchDownIndex = i;
										mLastTouchDownX = ev.getX();
										mLastTouchDownY = ev.getY();
										newTouchTarget = addTouchTarget(child, idBitsToAssign);
										alreadyDispatchedToNewTouchTarget = true;
										break;
									}
								}
							}
						}
						if (newTouchTarget == null && mFirstTouchTarget != null)
						{
							// Did not find a child to receive the event.
							// Assign the pointer to the least recently added target.
							newTouchTarget = mFirstTouchTarget;
							while (newTouchTarget.next != null)
							{
								newTouchTarget = newTouchTarget.next;
							}
							newTouchTarget.pointerIdBits |= idBitsToAssign;
						}
					}
				}
				// Dispatch to touch targets.
				if (mFirstTouchTarget == null)
				{
					// No touch targets so treat this as an ordinary view.
					handled = dispatchTransformedTouchEvent(ev, canceled, null, android.view.ViewGroup
						.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.
					android.view.ViewGroup.TouchTarget predecessor = null;
					android.view.ViewGroup.TouchTarget target = mFirstTouchTarget;
					while (target != null)
					{
						android.view.ViewGroup.TouchTarget next = target.next;
						if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget)
						{
							handled = true;
						}
						else
						{
							bool 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 == android.view.MotionEvent.ACTION_UP || actionMasked
					 == android.view.MotionEvent.ACTION_HOVER_MOVE)
				{
					resetTouchState();
				}
				else
				{
					if (split && actionMasked == android.view.MotionEvent.ACTION_POINTER_UP)
					{
						int actionIndex = ev.getActionIndex();
						int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
						removePointersFromTouchTargets(idBitsToRemove);
					}
				}
			}
			if (!handled && mInputEventConsistencyVerifier != null)
			{
				mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
			}
			return handled;
		}
コード例 #2
0
ファイル: ViewGroup.cs プロジェクト: hakeemsm/XobotOS
		/// <summary>
		/// Transforms a motion event into the coordinate space of a particular child view,
		/// filters out irrelevant pointer ids, and overrides its action if necessary.
		/// </summary>
		/// <remarks>
		/// Transforms a motion event into the coordinate space of a particular child view,
		/// filters out irrelevant pointer ids, and overrides its action if necessary.
		/// If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
		/// </remarks>
		private bool dispatchTransformedTouchEvent(android.view.MotionEvent @event, bool 
			cancel, android.view.View child, int desiredPointerIdBits)
		{
			bool handled;
			// Canceling motions is a special case.  We don't need to perform any transformations
			// or filtering.  The important part is the action, not the contents.
			int oldAction = @event.getAction();
			if (cancel || oldAction == android.view.MotionEvent.ACTION_CANCEL)
			{
				@event.setAction(android.view.MotionEvent.ACTION_CANCEL);
				if (child == null)
				{
					handled = base.dispatchTouchEvent(@event);
				}
				else
				{
					handled = child.dispatchTouchEvent(@event);
				}
				@event.setAction(oldAction);
				return handled;
			}
			// Calculate the number of pointers to deliver.
			int oldPointerIdBits = @event.getPointerIdBits();
			int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
			// If for some reason we ended up in an inconsistent state where it looks like we
			// might produce a motion event with no pointers in it, then drop the event.
			if (newPointerIdBits == 0)
			{
				return false;
			}
			// If the number of pointers is the same and we don't need to perform any fancy
			// irreversible transformations, then we can reuse the motion event for this
			// dispatch as long as we are careful to revert any changes we make.
			// Otherwise we need to make a copy.
			android.view.MotionEvent transformedEvent;
			if (newPointerIdBits == oldPointerIdBits)
			{
				if (child == null || child.hasIdentityMatrix())
				{
					if (child == null)
					{
						handled = base.dispatchTouchEvent(@event);
					}
					else
					{
						float offsetX = mScrollX - child.mLeft;
						float offsetY = mScrollY - child.mTop;
						@event.offsetLocation(offsetX, offsetY);
						handled = child.dispatchTouchEvent(@event);
						@event.offsetLocation(-offsetX, -offsetY);
					}
					return handled;
				}
				transformedEvent = android.view.MotionEvent.obtain(@event);
			}
			else
			{
				transformedEvent = @event.split(newPointerIdBits);
			}
			// Perform any necessary transformations and dispatch.
			if (child == null)
			{
				handled = base.dispatchTouchEvent(transformedEvent);
			}
			else
			{
				float offsetX = mScrollX - child.mLeft;
				float offsetY = mScrollY - child.mTop;
				transformedEvent.offsetLocation(offsetX, offsetY);
				if (!child.hasIdentityMatrix())
				{
					transformedEvent.transform(child.getInverseMatrix());
				}
				handled = child.dispatchTouchEvent(transformedEvent);
			}
			// Done.
			transformedEvent.recycle();
			return handled;
		}
コード例 #3
0
ファイル: ViewGroup.cs プロジェクト: hakeemsm/XobotOS
		protected internal override bool dispatchHoverEvent(android.view.MotionEvent @event
			)
		{
			int action = @event.getAction();
			// First check whether the view group wants to intercept the hover event.
			bool interceptHover = onInterceptHoverEvent(@event);
			@event.setAction(action);
			// restore action in case it was changed
			android.view.MotionEvent eventNoHistory = @event;
			bool handled = false;
			// Send events to the hovered children and build a new list of hover targets until
			// one is found that handles the event.
			android.view.ViewGroup.HoverTarget firstOldHoverTarget = mFirstHoverTarget;
			mFirstHoverTarget = null;
			if (!interceptHover && action != android.view.MotionEvent.ACTION_HOVER_EXIT)
			{
				float x = @event.getX();
				float y = @event.getY();
				int childrenCount = mChildrenCount;
				if (childrenCount != 0)
				{
					android.view.View[] children = mChildren;
					android.view.ViewGroup.HoverTarget lastHoverTarget = null;
					{
						for (int i = childrenCount - 1; i >= 0; i--)
						{
							android.view.View child = children[i];
							if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child
								, null))
							{
								continue;
							}
							// Obtain a hover target for this child.  Dequeue it from the
							// old hover target list if the child was previously hovered.
							android.view.ViewGroup.HoverTarget hoverTarget = firstOldHoverTarget;
							bool wasHovered;
							{
								for (android.view.ViewGroup.HoverTarget predecessor = null; ; )
								{
									if (hoverTarget == null)
									{
										hoverTarget = android.view.ViewGroup.HoverTarget.obtain(child);
										wasHovered = false;
										break;
									}
									if (hoverTarget.child == child)
									{
										if (predecessor != null)
										{
											predecessor.next = hoverTarget.next;
										}
										else
										{
											firstOldHoverTarget = hoverTarget.next;
										}
										hoverTarget.next = null;
										wasHovered = true;
										break;
									}
									predecessor = hoverTarget;
									hoverTarget = hoverTarget.next;
								}
							}
							// Enqueue the hover target onto the new hover target list.
							if (lastHoverTarget != null)
							{
								lastHoverTarget.next = hoverTarget;
							}
							else
							{
								lastHoverTarget = hoverTarget;
								mFirstHoverTarget = hoverTarget;
							}
							// Dispatch the event to the child.
							if (action == android.view.MotionEvent.ACTION_HOVER_ENTER)
							{
								if (!wasHovered)
								{
									// Send the enter as is.
									handled |= dispatchTransformedGenericPointerEvent(@event, child);
								}
							}
							else
							{
								// enter
								if (action == android.view.MotionEvent.ACTION_HOVER_MOVE)
								{
									if (!wasHovered)
									{
										// Synthesize an enter from a move.
										eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
										eventNoHistory.setAction(android.view.MotionEvent.ACTION_HOVER_ENTER);
										handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
										// enter
										eventNoHistory.setAction(action);
										handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
									}
									else
									{
										// move
										// Send the move as is.
										handled |= dispatchTransformedGenericPointerEvent(@event, child);
									}
								}
							}
							if (handled)
							{
								break;
							}
						}
					}
				}
			}
			// Send exit events to all previously hovered children that are no longer hovered.
			while (firstOldHoverTarget != null)
			{
				android.view.View child = firstOldHoverTarget.child;
				// Exit the old hovered child.
				if (action == android.view.MotionEvent.ACTION_HOVER_EXIT)
				{
					// Send the exit as is.
					handled |= dispatchTransformedGenericPointerEvent(@event, child);
				}
				else
				{
					// exit
					// Synthesize an exit from a move or enter.
					// Ignore the result because hover focus has moved to a different view.
					if (action == android.view.MotionEvent.ACTION_HOVER_MOVE)
					{
						dispatchTransformedGenericPointerEvent(@event, child);
					}
					// move
					eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
					eventNoHistory.setAction(android.view.MotionEvent.ACTION_HOVER_EXIT);
					dispatchTransformedGenericPointerEvent(eventNoHistory, child);
					// exit
					eventNoHistory.setAction(action);
				}
				android.view.ViewGroup.HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
				firstOldHoverTarget.recycle();
				firstOldHoverTarget = nextOldHoverTarget;
			}
			// Send events to the view group itself if no children have handled it.
			bool newHoveredSelf = !handled;
			if (newHoveredSelf == mHoveredSelf)
			{
				if (newHoveredSelf)
				{
					// Send event to the view group as before.
					handled |= base.dispatchHoverEvent(@event);
				}
			}
			else
			{
				if (mHoveredSelf)
				{
					// Exit the view group.
					if (action == android.view.MotionEvent.ACTION_HOVER_EXIT)
					{
						// Send the exit as is.
						handled |= base.dispatchHoverEvent(@event);
					}
					else
					{
						// exit
						// Synthesize an exit from a move or enter.
						// Ignore the result because hover focus is moving to a different view.
						if (action == android.view.MotionEvent.ACTION_HOVER_MOVE)
						{
							base.dispatchHoverEvent(@event);
						}
						// move
						eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
						eventNoHistory.setAction(android.view.MotionEvent.ACTION_HOVER_EXIT);
						base.dispatchHoverEvent(eventNoHistory);
						// exit
						eventNoHistory.setAction(action);
					}
					mHoveredSelf = false;
				}
				if (newHoveredSelf)
				{
					// Enter the view group.
					if (action == android.view.MotionEvent.ACTION_HOVER_ENTER)
					{
						// Send the enter as is.
						handled |= base.dispatchHoverEvent(@event);
						// enter
						mHoveredSelf = true;
					}
					else
					{
						if (action == android.view.MotionEvent.ACTION_HOVER_MOVE)
						{
							// Synthesize an enter from a move.
							eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
							eventNoHistory.setAction(android.view.MotionEvent.ACTION_HOVER_ENTER);
							handled |= base.dispatchHoverEvent(eventNoHistory);
							// enter
							eventNoHistory.setAction(action);
							handled |= base.dispatchHoverEvent(eventNoHistory);
							// move
							mHoveredSelf = true;
						}
					}
				}
			}
			// Recycle the copy of the event that we made.
			if (eventNoHistory != @event)
			{
				eventNoHistory.recycle();
			}
			// Done.
			return handled;
		}