diff --git a/api/current.txt b/api/current.txt index fd05e485b0a34..c7e6ee6ceec0c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -21174,7 +21174,6 @@ package android.view { method protected void onLayout(boolean, int, int, int, int); method protected void onMeasure(int, int); method protected void onOverScrolled(int, int, boolean, boolean); - method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); method protected void onRestoreInstanceState(android.os.Parcelable); method protected android.os.Parcelable onSaveInstanceState(); method protected void onScrollChanged(int, int, int, int); @@ -21586,7 +21585,6 @@ package android.view { method public boolean onInterceptTouchEvent(android.view.MotionEvent); method protected abstract void onLayout(boolean, int, int, int, int); method protected boolean onRequestFocusInDescendants(int, android.graphics.Rect); - method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public void recomputeViewAttributes(android.view.View); method public void removeAllViews(); method public void removeAllViewsInLayout(); @@ -21599,7 +21597,6 @@ package android.view { method public void requestChildFocus(android.view.View, android.view.View); method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean); method public void requestDisallowInterceptTouchEvent(boolean); - method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public void requestTransparentRegion(android.view.View); method public void scheduleLayoutAnimation(); method public void setAddStatesFromChildren(boolean); @@ -21686,7 +21683,6 @@ package android.view { method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean); method public abstract void requestDisallowInterceptTouchEvent(boolean); method public abstract void requestLayout(); - method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); @@ -22032,32 +22028,53 @@ package android.view { package android.view.accessibility { - public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable { - method public void appendRecord(android.view.accessibility.AccessibilityRecord); + public final class AccessibilityEvent implements android.os.Parcelable { method public int describeContents(); + method public int getAddedCount(); + method public java.lang.CharSequence getBeforeText(); + method public java.lang.CharSequence getClassName(); + method public java.lang.CharSequence getContentDescription(); + method public int getCurrentItemIndex(); method public long getEventTime(); method public int getEventType(); + method public int getFromIndex(); + method public int getItemCount(); method public java.lang.CharSequence getPackageName(); - method public android.view.accessibility.AccessibilityRecord getRecord(int); - method public int getRecordCount(); + method public android.os.Parcelable getParcelableData(); + method public int getRemovedCount(); + method public java.util.List getText(); method public void initFromParcel(android.os.Parcel); + method public boolean isChecked(); + method public boolean isEnabled(); + method public boolean isFullScreen(); + method public boolean isPassword(); method public static android.view.accessibility.AccessibilityEvent obtain(int); method public static android.view.accessibility.AccessibilityEvent obtain(); + method public void recycle(); + method public void setAddedCount(int); + method public void setBeforeText(java.lang.CharSequence); + method public void setChecked(boolean); + method public void setClassName(java.lang.CharSequence); + method public void setContentDescription(java.lang.CharSequence); + method public void setCurrentItemIndex(int); + method public void setEnabled(boolean); method public void setEventTime(long); method public void setEventType(int); + method public void setFromIndex(int); + method public void setFullScreen(boolean); + method public void setItemCount(int); method public void setPackageName(java.lang.CharSequence); + method public void setParcelableData(android.os.Parcelable); + method public void setPassword(boolean); + method public void setRemovedCount(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int INVALID_POSITION = -1; // 0xffffffff field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4 field public static final int TYPES_ALL_MASK = -1; // 0xffffffff field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40 - field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400 - field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200 field public static final int TYPE_VIEW_CLICKED = 1; // 0x1 field public static final int TYPE_VIEW_FOCUSED = 8; // 0x8 - field public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80 - field public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100 field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2 field public static final int TYPE_VIEW_SELECTED = 4; // 0x4 field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10 @@ -22071,58 +22088,11 @@ package android.view.accessibility { public final class AccessibilityManager { method public java.util.List getAccessibilityServiceList(); - method public java.util.List getEnabledAccessibilityServiceList(int); method public void interrupt(); method public boolean isEnabled(); method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent); } - public class AccessibilityRecord { - ctor protected AccessibilityRecord(); - method protected void clear(); - method public int getAddedCount(); - method public java.lang.CharSequence getBeforeText(); - method public boolean getBooleanProperty(int); - method public java.lang.CharSequence getClassName(); - method public java.lang.CharSequence getContentDescription(); - method public int getCurrentItemIndex(); - method public int getFromIndex(); - method public int getItemCount(); - method public android.os.Parcelable getParcelableData(); - method public int getRemovedCount(); - method public java.util.List getText(); - method public boolean isChecked(); - method public boolean isEnabled(); - method public boolean isFullScreen(); - method public boolean isPassword(); - method protected static android.view.accessibility.AccessibilityRecord obtain(); - method public void recycle(); - method public void setAddedCount(int); - method public void setBeforeText(java.lang.CharSequence); - method public void setChecked(boolean); - method public void setClassName(java.lang.CharSequence); - method public void setContentDescription(java.lang.CharSequence); - method public void setCurrentItemIndex(int); - method public void setEnabled(boolean); - method public void setFromIndex(int); - method public void setFullScreen(boolean); - method public void setItemCount(int); - method public void setParcelableData(android.os.Parcelable); - method public void setPassword(boolean); - method public void setRemovedCount(int); - field protected int mAddedCount; - field protected java.lang.CharSequence mBeforeText; - field protected int mBooleanProperties; - field protected java.lang.CharSequence mClassName; - field protected java.lang.CharSequence mContentDescription; - field protected int mCurrentItemIndex; - field protected int mFromIndex; - field protected int mItemCount; - field protected android.os.Parcelable mParcelableData; - field protected int mRemovedCount; - field protected final java.util.List mText; - } - } package android.view.animation { diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java index e14b97558e496..b5ca2c2a8c1ca 100644 --- a/core/java/android/view/InputEventConsistencyVerifier.java +++ b/core/java/android/view/InputEventConsistencyVerifier.java @@ -30,6 +30,7 @@ import android.util.Log; * @hide */ public final class InputEventConsistencyVerifier { + private static final String TAG = "InputEventConsistencyVerifier"; private static final boolean IS_ENG_BUILD = "eng".equals(Build.TYPE); // The number of recent events to log when a problem is detected. @@ -43,11 +44,6 @@ public final class InputEventConsistencyVerifier { // Consistency verifier flags. private final int mFlags; - // Tag for logging which a client can set to help distinguish the output - // from different verifiers since several can be active at the same time. - // If not provided defaults to the simple class name. - private final String mLogTag; - // The most recently checked event and the nesting level at which it was checked. // This is only set when the verifier is called from a nesting level greater than 0 // so that the verifier can detect when it has been asked to verify the same event twice. @@ -107,19 +103,8 @@ public final class InputEventConsistencyVerifier { * @param flags Flags to the verifier, or 0 if none. */ public InputEventConsistencyVerifier(Object caller, int flags) { - this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName()); - } - - /** - * Creates an input consistency verifier. - * @param caller The object to which the verifier is attached. - * @param flags Flags to the verifier, or 0 if none. - * @param logTag Tag for logging. If null defaults to the short class name. - */ - public InputEventConsistencyVerifier(Object caller, int flags, String logTag) { this.mCaller = caller; this.mFlags = flags; - this.mLogTag = (logTag != null) ? logTag : "InputEventConsistencyVerifier"; } /** @@ -611,7 +596,7 @@ public final class InputEventConsistencyVerifier { } } - Log.d(mLogTag, mViolationMessage.toString()); + Log.d(TAG, mViolationMessage.toString()); mViolationMessage.setLength(0); tainted = true; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4bc7f39a584c4..4a6289285d418 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3455,10 +3455,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if (!isShown()) { return; } - - // Populate these here since they are related to the View that - // sends the event and should not be modified while dispatching - // to descendants. event.setClassName(getClass().getName()); event.setPackageName(getContext().getPackageName()); event.setEnabled(isEnabled()); @@ -3474,37 +3470,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility dispatchPopulateAccessibilityEvent(event); - // In the beginning we called #isShown(), so we know that getParent() is not null. - getParent().requestSendAccessibilityEvent(this, event); + AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event); } /** - * Dispatches an {@link AccessibilityEvent} to the {@link View} children to be populated. - * This method first calls {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} - * on this view allowing it to populate information about itself and also decide - * whether to intercept the population i.e. to prevent its children from populating - * the event. + * Dispatches an {@link AccessibilityEvent} to the {@link View} children + * to be populated. * * @param event The event. * * @return True if the event population was completed. */ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - onPopulateAccessibilityEvent(event); return false; } - /** - * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} - * giving a chance to this View to populate the accessibility evnet with - * information about itself. - * - * @param event The accessibility event which to populate. - */ - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - - } - /** * Gets the {@link View} description. It briefly describes the view and is * primarily used for accessibility support. Set this property to enable @@ -5410,6 +5390,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * to receive the hover event. */ public boolean onHoverEvent(MotionEvent event) { + final int viewFlags = mViewFlags; + + if (((viewFlags & CLICKABLE) != CLICKABLE && + (viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) { + // Nothing to do if the view is not clickable. + return false; + } + + if ((viewFlags & ENABLED_MASK) == DISABLED) { + // A disabled view that is clickable still consumes the hover events, it just doesn't + // respond to them. + return true; + } + switch (event.getAction()) { case MotionEvent.ACTION_HOVER_ENTER: setHovered(true); @@ -5420,7 +5414,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility break; } - return false; + return true; } /** @@ -5442,13 +5436,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility if ((mPrivateFlags & HOVERED) == 0) { mPrivateFlags |= HOVERED; refreshDrawableState(); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); } } else { if ((mPrivateFlags & HOVERED) != 0) { mPrivateFlags &= ~HOVERED; refreshDrawableState(); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); } } } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 94eb429dad648..739758c8c79f1 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -19,6 +19,7 @@ package android.view; import android.app.AppGlobals; import android.content.Context; import android.content.res.Configuration; +import android.os.Bundle; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; @@ -154,13 +155,6 @@ public class ViewConfiguration { */ private static final int MAXIMUM_FLING_VELOCITY = 8000; - /** - * Distance between a touch up event denoting the end of a touch exploration - * gesture and the touch up event of a subsequent tap for the latter tap to be - * considered as a tap i.e. to perform a click. - */ - private static final int TOUCH_EXPLORATION_TAP_SLOP = 80; - /** * The maximum size of View's drawing cache, expressed in bytes. This size * should be at least equal to the size of the screen in ARGB888 format. @@ -191,7 +185,6 @@ public class ViewConfiguration { private final int mTouchSlop; private final int mPagingTouchSlop; private final int mDoubleTapSlop; - private final int mScaledTouchExplorationTapSlop; private final int mWindowTouchSlop; private final int mMaximumDrawingCacheSize; private final int mOverscrollDistance; @@ -213,7 +206,6 @@ public class ViewConfiguration { mTouchSlop = TOUCH_SLOP; mPagingTouchSlop = PAGING_TOUCH_SLOP; mDoubleTapSlop = DOUBLE_TAP_SLOP; - mScaledTouchExplorationTapSlop = TOUCH_EXPLORATION_TAP_SLOP; mWindowTouchSlop = WINDOW_TOUCH_SLOP; //noinspection deprecation mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE; @@ -250,7 +242,6 @@ public class ViewConfiguration { mTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f); mPagingTouchSlop = (int) (sizeAndDensity * PAGING_TOUCH_SLOP + 0.5f); mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f); - mScaledTouchExplorationTapSlop = (int) (density * TOUCH_EXPLORATION_TAP_SLOP + 0.5f); mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f); // Size of the screen in bytes, in ARGB_8888 format @@ -452,17 +443,6 @@ public class ViewConfiguration { return mDoubleTapSlop; } - /** - * @return Distance between a touch up event denoting the end of a touch exploration - * gesture and the touch up event of a subsequent tap for the latter tap to be - * considered as a tap i.e. to perform a click. - * - * @hide - */ - public int getScaledTouchExplorationTapSlop() { - return mScaledTouchExplorationTapSlop; - } - /** * @return Distance a touch must be outside the bounds of a window for it * to be counted as outside the window for purposes of dismissing that diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7b404b45f7292..08daa280b10a9 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -583,35 +583,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } - /** - * {@inheritDoc} - */ - public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { - ViewParent parent = getParent(); - if (parent == null) { - return false; - } - final boolean propagate = onRequestSendAccessibilityEvent(child, event); - if (!propagate) { - return false; - } - return parent.requestSendAccessibilityEvent(this, event); - } - - /** - * Called when a child has requested sending an {@link AccessibilityEvent} and - * gives an opportunity to its parent to augment the event. - * - * @param child The child which requests sending the event. - * @param event The event to be sent. - * @return True if the event should be sent. - * - * @see #requestSendAccessibilityEvent(View, AccessibilityEvent) - */ - public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { - return true; - } - /** * {@inheritDoc} */ @@ -1245,8 +1216,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild); eventNoHistory.setAction(action); + mHoveredChild = null; - } else { + } else if (action == MotionEvent.ACTION_HOVER_MOVE) { // Pointer is still within the child. handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild); } @@ -1306,17 +1278,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return handled; } - @Override - public boolean onHoverEvent(MotionEvent event) { - // Handle the event only if leaf. This guarantees that - // the leafs (or any custom class that returns true from - // this method) will get a change to process the hover. - if (getChildCount() == 0) { - return super.onHoverEvent(event); - } - return false; - } - private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) { if (event.getHistorySize() == 0) { return event; @@ -2130,16 +2091,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - // We first get a chance to populate the event. - onPopulateAccessibilityEvent(event); - // Let our children have a shot in populating the event. + boolean populated = false; for (int i = 0, count = getChildCount(); i < count; i++) { - boolean handled = getChildAt(i).dispatchPopulateAccessibilityEvent(event); - if (handled) { - return handled; - } + populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event); } - return false; + return populated; } /** diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 655df391ed4fc..d7d4c3f02d0d1 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -17,7 +17,6 @@ package android.view; import android.graphics.Rect; -import android.view.accessibility.AccessibilityEvent; /** * Defines the responsibilities for a class that will be a parent of a View. @@ -223,22 +222,4 @@ public interface ViewParent { */ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate); - - /** - * Called by a child to request from its parent to send an {@link AccessibilityEvent}. - * The child has already populated a record for itself in the event and is delegating - * to its parent to send the event. The parent can optionally add a record for itself. - *

- * Note: An accessibility event is fired by an individual view which populates the - * event with a record for its state and requests from its parent to perform - * the sending. The parent can optionally add a record for itself before - * dispatching the request to its parent. A parent can also choose not to - * respect the request for sending the event. The accessibility event is sent - * by the topmost view in the view tree. - * - * @param child The child which requests sending the event. - * @param event The event to be sent. - * @return True if the event was sent. - */ - public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index f02dabac340da..4104b070f4a15 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -3530,14 +3530,6 @@ public final class ViewRoot extends Handler implements ViewParent, public void childDrawableStateChanged(View child) { } - public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { - if (mView == null) { - return false; - } - AccessibilityManager.getInstance(child.mContext).sendAccessibilityEvent(event); - return true; - } - void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 11c93929b23ec..9af19b8796a9f 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -21,26 +21,13 @@ import android.os.Parcelable; import android.text.TextUtils; import java.util.ArrayList; +import java.util.List; /** * This class represents accessibility events that are sent by the system when * something notable happens in the user interface. For example, when a * {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc. *

- * An accessibility event is fired by an individual view which populates the event with - * a record for its state and requests from its parent to send the event to interested - * parties. The parent can optionally add a record for itself before dispatching a similar - * request to its parent. A parent can also choose not to respect the request for sending - * an event. The accessibility event is sent by the topmost view in the view tree. - * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore - * all records in an accessibility event to obtain more information about the context - * in which the event was fired. - *

- * A client can add, remove, and modify records. The getters and setters for individual - * properties operate on the current record which can be explicitly set by the client. By - * default current is the first record. Thus, querying a record would require setting - * it as the current one and interacting with the property getters and setters. - *

* This class represents various semantically different accessibility event * types. Each event type has associated a set of related properties. In other * words, each event type is characterized via a subset of the properties exposed @@ -158,7 +145,7 @@ import java.util.ArrayList; * @see android.view.accessibility.AccessibilityManager * @see android.accessibilityservice.AccessibilityService */ -public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable { +public final class AccessibilityEvent implements Parcelable { /** * Invalid selection/focus position. @@ -219,26 +206,6 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040; - /** - * Represents the event of a hover enter over a {@link android.view.View}. - */ - public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080; - - /** - * Represents the event of a hover exit over a {@link android.view.View}. - */ - public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100; - - /** - * Represents the event of starting a touch exploration gesture. - */ - public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200; - - /** - * Represents the event of ending a touch exploration gesture. - */ - public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400; - /** * Mask for {@link AccessibilityEvent} all types. * @@ -252,53 +219,116 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int TYPES_ALL_MASK = 0xFFFFFFFF; - private static final int MAX_POOL_SIZE = 10; + private static final int MAX_POOL_SIZE = 2; private static final Object mPoolLock = new Object(); private static AccessibilityEvent sPool; private static int sPoolSize; + private static final int CHECKED = 0x00000001; + private static final int ENABLED = 0x00000002; + private static final int PASSWORD = 0x00000004; + private static final int FULL_SCREEN = 0x00000080; + private AccessibilityEvent mNext; - private boolean mIsInPool; private int mEventType; - private CharSequence mPackageName; + private int mBooleanProperties; + private int mCurrentItemIndex; + private int mItemCount; + private int mFromIndex; + private int mAddedCount; + private int mRemovedCount; + private long mEventTime; - private final ArrayList mRecords = new ArrayList(); + private CharSequence mClassName; + private CharSequence mPackageName; + private CharSequence mContentDescription; + private CharSequence mBeforeText; + + private Parcelable mParcelableData; + + private final List mText = new ArrayList(); + + private boolean mIsInPool; /* * Hide constructor from clients. */ private AccessibilityEvent() { - + mCurrentItemIndex = INVALID_POSITION; } /** - * Gets the number of records contained in the event. + * Gets if the source is checked. * - * @return The number of records. + * @return True if the view is checked, false otherwise. */ - public int getRecordCount() { - return mRecords.size(); + public boolean isChecked() { + return getBooleanProperty(CHECKED); } /** - * Appends an {@link AccessibilityRecord} to the end of event records. + * Sets if the source is checked. * - * @param record The record to append. + * @param isChecked True if the view is checked, false otherwise. */ - public void appendRecord(AccessibilityRecord record) { - mRecords.add(record); + public void setChecked(boolean isChecked) { + setBooleanProperty(CHECKED, isChecked); } /** - * Gets the records at a given index. + * Gets if the source is enabled. * - * @param index The index. - * @return The records at the specified index. + * @return True if the view is enabled, false otherwise. */ - public AccessibilityRecord getRecord(int index) { - return mRecords.get(index); + public boolean isEnabled() { + return getBooleanProperty(ENABLED); + } + + /** + * Sets if the source is enabled. + * + * @param isEnabled True if the view is enabled, false otherwise. + */ + public void setEnabled(boolean isEnabled) { + setBooleanProperty(ENABLED, isEnabled); + } + + /** + * Gets if the source is a password field. + * + * @return True if the view is a password field, false otherwise. + */ + public boolean isPassword() { + return getBooleanProperty(PASSWORD); + } + + /** + * Sets if the source is a password field. + * + * @param isPassword True if the view is a password field, false otherwise. + */ + public void setPassword(boolean isPassword) { + setBooleanProperty(PASSWORD, isPassword); + } + + /** + * Sets if the source is taking the entire screen. + * + * @param isFullScreen True if the source is full screen, false otherwise. + */ + public void setFullScreen(boolean isFullScreen) { + setBooleanProperty(FULL_SCREEN, isFullScreen); + } + + /** + * Gets if the source is taking the entire screen. + * + * @return True if the source is full screen, false otherwise. + */ + public boolean isFullScreen() { + return getBooleanProperty(FULL_SCREEN); } /** @@ -319,6 +349,96 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mEventType = eventType; } + /** + * Gets the number of items that can be visited. + * + * @return The number of items. + */ + public int getItemCount() { + return mItemCount; + } + + /** + * Sets the number of items that can be visited. + * + * @param itemCount The number of items. + */ + public void setItemCount(int itemCount) { + mItemCount = itemCount; + } + + /** + * Gets the index of the source in the list of items the can be visited. + * + * @return The current item index. + */ + public int getCurrentItemIndex() { + return mCurrentItemIndex; + } + + /** + * Sets the index of the source in the list of items that can be visited. + * + * @param currentItemIndex The current item index. + */ + public void setCurrentItemIndex(int currentItemIndex) { + mCurrentItemIndex = currentItemIndex; + } + + /** + * Gets the index of the first character of the changed sequence. + * + * @return The index of the first character. + */ + public int getFromIndex() { + return mFromIndex; + } + + /** + * Sets the index of the first character of the changed sequence. + * + * @param fromIndex The index of the first character. + */ + public void setFromIndex(int fromIndex) { + mFromIndex = fromIndex; + } + + /** + * Gets the number of added characters. + * + * @return The number of added characters. + */ + public int getAddedCount() { + return mAddedCount; + } + + /** + * Sets the number of added characters. + * + * @param addedCount The number of added characters. + */ + public void setAddedCount(int addedCount) { + mAddedCount = addedCount; + } + + /** + * Gets the number of removed characters. + * + * @return The number of removed characters. + */ + public int getRemovedCount() { + return mRemovedCount; + } + + /** + * Sets the number of removed characters. + * + * @param removedCount The number of removed characters. + */ + public void setRemovedCount(int removedCount) { + mRemovedCount = removedCount; + } + /** * Gets the time in which this event was sent. * @@ -337,6 +457,24 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mEventTime = eventTime; } + /** + * Gets the class name of the source. + * + * @return The class name. + */ + public CharSequence getClassName() { + return mClassName; + } + + /** + * Sets the class name of the source. + * + * @param className The lass name. + */ + public void setClassName(CharSequence className) { + mClassName = className; + } + /** * Gets the package name of the source. * @@ -355,6 +493,70 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par mPackageName = packageName; } + /** + * Gets the text of the event. The index in the list represents the priority + * of the text. Specifically, the lower the index the higher the priority. + * + * @return The text. + */ + public List getText() { + return mText; + } + + /** + * Sets the text before a change. + * + * @return The text before the change. + */ + public CharSequence getBeforeText() { + return mBeforeText; + } + + /** + * Sets the text before a change. + * + * @param beforeText The text before the change. + */ + public void setBeforeText(CharSequence beforeText) { + mBeforeText = beforeText; + } + + /** + * Gets the description of the source. + * + * @return The description. + */ + public CharSequence getContentDescription() { + return mContentDescription; + } + + /** + * Sets the description of the source. + * + * @param contentDescription The description. + */ + public void setContentDescription(CharSequence contentDescription) { + mContentDescription = contentDescription; + } + + /** + * Gets the {@link Parcelable} data. + * + * @return The parcelable data. + */ + public Parcelable getParcelableData() { + return mParcelableData; + } + + /** + * Sets the {@link Parcelable} data of the event. + * + * @param parcelableData The parcelable data. + */ + public void setParcelableData(Parcelable parcelableData) { + mParcelableData = parcelableData; + } + /** * Returns a cached instance if such is available or a new one is * instantiated with type property set. @@ -393,11 +595,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par *

* Note: You must not touch the object after calling this function. */ - @Override public void recycle() { if (mIsInPool) { return; } + clear(); synchronized (mPoolLock) { if (sPoolSize <= MAX_POOL_SIZE) { @@ -412,15 +614,44 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Clears the state of this instance. */ - @Override - protected void clear() { - super.clear(); + private void clear() { mEventType = 0; - mPackageName = null; + mBooleanProperties = 0; + mCurrentItemIndex = INVALID_POSITION; + mItemCount = 0; + mFromIndex = 0; + mAddedCount = 0; + mRemovedCount = 0; mEventTime = 0; - while (!mRecords.isEmpty()) { - AccessibilityRecord record = mRecords.remove(0); - record.recycle(); + mClassName = null; + mPackageName = null; + mContentDescription = null; + mBeforeText = null; + mParcelableData = null; + mText.clear(); + } + + /** + * Gets the value of a boolean property. + * + * @param property The property. + * @return The value. + */ + private boolean getBooleanProperty(int property) { + return (mBooleanProperties & property) == property; + } + + /** + * Sets a boolean property. + * + * @param property The property. + * @param value The value. + */ + private void setBooleanProperty(int property, boolean value) { + if (value) { + mBooleanProperties |= property; + } else { + mBooleanProperties &= ~property; } } @@ -431,82 +662,38 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public void initFromParcel(Parcel parcel) { mEventType = parcel.readInt(); - mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + mBooleanProperties = parcel.readInt(); + mCurrentItemIndex = parcel.readInt(); + mItemCount = parcel.readInt(); + mFromIndex = parcel.readInt(); + mAddedCount = parcel.readInt(); + mRemovedCount = parcel.readInt(); mEventTime = parcel.readLong(); - readAccessibilityRecordFromParcel(this, parcel); - - // Read the records. - final int recordCount = parcel.readInt(); - for (int i = 0; i < recordCount; i++) { - AccessibilityRecord record = AccessibilityRecord.obtain(); - readAccessibilityRecordFromParcel(record, parcel); - mRecords.add(record); - } + mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); + mParcelableData = parcel.readParcelable(null); + parcel.readList(mText, null); } - /** - * Reads an {@link AccessibilityRecord} from a parcel. - * - * @param record The record to initialize. - * @param parcel The parcel to read from. - */ - private void readAccessibilityRecordFromParcel(AccessibilityRecord record, - Parcel parcel) { - record.mBooleanProperties = parcel.readInt(); - record.mCurrentItemIndex = parcel.readInt(); - record.mItemCount = parcel.readInt(); - record.mFromIndex = parcel.readInt(); - record.mAddedCount = parcel.readInt(); - record.mRemovedCount = parcel.readInt(); - record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - record.mParcelableData = parcel.readParcelable(null); - parcel.readList(record.mText, null); - } - - /** - * {@inheritDoc} - */ public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mEventType); - TextUtils.writeToParcel(mPackageName, parcel, 0); + parcel.writeInt(mBooleanProperties); + parcel.writeInt(mCurrentItemIndex); + parcel.writeInt(mItemCount); + parcel.writeInt(mFromIndex); + parcel.writeInt(mAddedCount); + parcel.writeInt(mRemovedCount); parcel.writeLong(mEventTime); - writeAccessibilityRecordToParcel(this, parcel, flags); - - // Write the records. - final int recordCount = getRecordCount(); - parcel.writeInt(recordCount); - for (int i = 0; i < recordCount; i++) { - AccessibilityRecord record = mRecords.get(i); - writeAccessibilityRecordToParcel(record, parcel, flags); - } + TextUtils.writeToParcel(mClassName, parcel, 0); + TextUtils.writeToParcel(mPackageName, parcel, 0); + TextUtils.writeToParcel(mContentDescription, parcel, 0); + TextUtils.writeToParcel(mBeforeText, parcel, 0); + parcel.writeParcelable(mParcelableData, flags); + parcel.writeList(mText); } - /** - * Writes an {@link AccessibilityRecord} to a parcel. - * - * @param record The record to write. - * @param parcel The parcel to which to write. - */ - private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel, - int flags) { - parcel.writeInt(record.mBooleanProperties); - parcel.writeInt(record.mCurrentItemIndex); - parcel.writeInt(record.mItemCount); - parcel.writeInt(record.mFromIndex); - parcel.writeInt(record.mAddedCount); - parcel.writeInt(record.mRemovedCount); - TextUtils.writeToParcel(record.mClassName, parcel, flags); - TextUtils.writeToParcel(record.mContentDescription, parcel, flags); - TextUtils.writeToParcel(record.mBeforeText, parcel, flags); - parcel.writeParcelable(record.mParcelableData, flags); - parcel.writeList(record.mText); - } - - /** - * {@inheritDoc} - */ public int describeContents() { return 0; } @@ -514,21 +701,24 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par @Override public String toString() { StringBuilder builder = new StringBuilder(); + builder.append(super.toString()); builder.append("; EventType: " + mEventType); builder.append("; EventTime: " + mEventTime); + builder.append("; ClassName: " + mClassName); builder.append("; PackageName: " + mPackageName); - builder.append(" \n{\n"); - builder.append(super.toString()); - builder.append("\n"); - for (int i = 0; i < mRecords.size(); i++) { - AccessibilityRecord record = mRecords.get(i); - builder.append(" Record "); - builder.append(i); - builder.append(":"); - builder.append(record.toString()); - builder.append("\n"); - } - builder.append("}\n"); + builder.append("; Text: " + mText); + builder.append("; ContentDescription: " + mContentDescription); + builder.append("; ItemCount: " + mItemCount); + builder.append("; CurrentItemIndex: " + mCurrentItemIndex); + builder.append("; IsEnabled: " + isEnabled()); + builder.append("; IsPassword: " + isPassword()); + builder.append("; IsChecked: " + isChecked()); + builder.append("; IsFullScreen: " + isFullScreen()); + builder.append("; BeforeText: " + mBeforeText); + builder.append("; FromIndex: " + mFromIndex); + builder.append("; AddedCount: " + mAddedCount); + builder.append("; RemovedCount: " + mRemovedCount); + builder.append("; ParcelableData: " + mParcelableData); return builder.toString(); } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index dd7719364a318..22cb0d482bf8a 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -16,8 +16,6 @@ package android.view.accessibility; -import android.accessibilityservice.AccessibilityService; -import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.content.pm.ServiceInfo; import android.os.Binder; @@ -46,8 +44,6 @@ import java.util.List; * @see android.content.Context#getSystemService */ public final class AccessibilityManager { - private static final boolean DEBUG = false; - private static final String LOG_TAG = "AccessibilityManager"; static final Object sInstanceSync = new Object(); @@ -168,7 +164,7 @@ public final class AccessibilityManager { long identityToken = Binder.clearCallingIdentity(); doRecycle = mService.sendAccessibilityEvent(event); Binder.restoreCallingIdentity(identityToken); - if (DEBUG) { + if (false) { Log.i(LOG_TAG, event + " sent"); } } catch (RemoteException re) { @@ -189,7 +185,7 @@ public final class AccessibilityManager { } try { mService.interrupt(); - if (DEBUG) { + if (false) { Log.i(LOG_TAG, "Requested interrupt from all services"); } } catch (RemoteException re) { @@ -206,33 +202,7 @@ public final class AccessibilityManager { List services = null; try { services = mService.getAccessibilityServiceList(); - if (DEBUG) { - Log.i(LOG_TAG, "Installed AccessibilityServices " + services); - } - } catch (RemoteException re) { - Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); - } - return Collections.unmodifiableList(services); - } - - /** - * Returns the {@link ServiceInfo}s of the enabled accessibility services - * for a given feedback type. - * - * @param feedbackType The type of feedback. - * @return An unmodifiable list with {@link ServiceInfo}s. - * - * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE - * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC - * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN - * @see AccessibilityServiceInfo#FEEDBACK_VISUAL - * @see AccessibilityServiceInfo#FEEDBACK_GENERIC - */ - public List getEnabledAccessibilityServiceList(int feedbackType) { - List services = null; - try { - services = mService.getEnabledAccessibilityServiceList(feedbackType); - if (DEBUG) { + if (false) { Log.i(LOG_TAG, "Installed AccessibilityServices " + services); } } catch (RemoteException re) { diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java deleted file mode 100644 index e095f435bfd63..0000000000000 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view.accessibility; - -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.List; - -/** - * Represents a record in an accessibility event. This class encapsulates - * the information for a {@link android.view.View}. Note that not all properties - * are applicable to all view types. For detailed information please refer to - * {@link AccessibilityEvent}. - * - * @see AccessibilityEvent - */ -public class AccessibilityRecord { - - private static final int INVALID_POSITION = -1; - - private static final int PROPERTY_CHECKED = 0x00000001; - private static final int PROPERTY_ENABLED = 0x00000002; - private static final int PROPERTY_PASSWORD = 0x00000004; - private static final int PROPERTY_FULL_SCREEN = 0x00000080; - - private static final int MAX_POOL_SIZE = 10; - private static final Object mPoolLock = new Object(); - private static AccessibilityRecord sPool; - private static int sPoolSize; - - private AccessibilityRecord mNext; - private boolean mIsInPool; - - protected int mBooleanProperties; - protected int mCurrentItemIndex; - protected int mItemCount; - protected int mFromIndex; - protected int mAddedCount; - protected int mRemovedCount; - - protected CharSequence mClassName; - protected CharSequence mContentDescription; - protected CharSequence mBeforeText; - protected Parcelable mParcelableData; - - protected final List mText = new ArrayList(); - - /* - * Hide constructor. - */ - protected AccessibilityRecord() { - - } - - /** - * Gets if the source is checked. - * - * @return True if the view is checked, false otherwise. - */ - public boolean isChecked() { - return getBooleanProperty(PROPERTY_CHECKED); - } - - /** - * Sets if the source is checked. - * - * @param isChecked True if the view is checked, false otherwise. - */ - public void setChecked(boolean isChecked) { - setBooleanProperty(PROPERTY_CHECKED, isChecked); - } - - /** - * Gets if the source is enabled. - * - * @return True if the view is enabled, false otherwise. - */ - public boolean isEnabled() { - return getBooleanProperty(PROPERTY_ENABLED); - } - - /** - * Sets if the source is enabled. - * - * @param isEnabled True if the view is enabled, false otherwise. - */ - public void setEnabled(boolean isEnabled) { - setBooleanProperty(PROPERTY_ENABLED, isEnabled); - } - - /** - * Gets if the source is a password field. - * - * @return True if the view is a password field, false otherwise. - */ - public boolean isPassword() { - return getBooleanProperty(PROPERTY_PASSWORD); - } - - /** - * Sets if the source is a password field. - * - * @param isPassword True if the view is a password field, false otherwise. - */ - public void setPassword(boolean isPassword) { - setBooleanProperty(PROPERTY_PASSWORD, isPassword); - } - - /** - * Sets if the source is taking the entire screen. - * - * @param isFullScreen True if the source is full screen, false otherwise. - */ - public void setFullScreen(boolean isFullScreen) { - setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen); - } - - /** - * Gets if the source is taking the entire screen. - * - * @return True if the source is full screen, false otherwise. - */ - public boolean isFullScreen() { - return getBooleanProperty(PROPERTY_FULL_SCREEN); - } - - /** - * Gets the number of items that can be visited. - * - * @return The number of items. - */ - public int getItemCount() { - return mItemCount; - } - - /** - * Sets the number of items that can be visited. - * - * @param itemCount The number of items. - */ - public void setItemCount(int itemCount) { - mItemCount = itemCount; - } - - /** - * Gets the index of the source in the list of items the can be visited. - * - * @return The current item index. - */ - public int getCurrentItemIndex() { - return mCurrentItemIndex; - } - - /** - * Sets the index of the source in the list of items that can be visited. - * - * @param currentItemIndex The current item index. - */ - public void setCurrentItemIndex(int currentItemIndex) { - mCurrentItemIndex = currentItemIndex; - } - - /** - * Gets the index of the first character of the changed sequence. - * - * @return The index of the first character. - */ - public int getFromIndex() { - return mFromIndex; - } - - /** - * Sets the index of the first character of the changed sequence. - * - * @param fromIndex The index of the first character. - */ - public void setFromIndex(int fromIndex) { - mFromIndex = fromIndex; - } - - /** - * Gets the number of added characters. - * - * @return The number of added characters. - */ - public int getAddedCount() { - return mAddedCount; - } - - /** - * Sets the number of added characters. - * - * @param addedCount The number of added characters. - */ - public void setAddedCount(int addedCount) { - mAddedCount = addedCount; - } - - /** - * Gets the number of removed characters. - * - * @return The number of removed characters. - */ - public int getRemovedCount() { - return mRemovedCount; - } - - /** - * Sets the number of removed characters. - * - * @param removedCount The number of removed characters. - */ - public void setRemovedCount(int removedCount) { - mRemovedCount = removedCount; - } - - /** - * Gets the class name of the source. - * - * @return The class name. - */ - public CharSequence getClassName() { - return mClassName; - } - - /** - * Sets the class name of the source. - * - * @param className The lass name. - */ - public void setClassName(CharSequence className) { - mClassName = className; - } - - /** - * Gets the text of the event. The index in the list represents the priority - * of the text. Specifically, the lower the index the higher the priority. - * - * @return The text. - */ - public List getText() { - return mText; - } - - /** - * Sets the text before a change. - * - * @return The text before the change. - */ - public CharSequence getBeforeText() { - return mBeforeText; - } - - /** - * Sets the text before a change. - * - * @param beforeText The text before the change. - */ - public void setBeforeText(CharSequence beforeText) { - mBeforeText = beforeText; - } - - /** - * Gets the description of the source. - * - * @return The description. - */ - public CharSequence getContentDescription() { - return mContentDescription; - } - - /** - * Sets the description of the source. - * - * @param contentDescription The description. - */ - public void setContentDescription(CharSequence contentDescription) { - mContentDescription = contentDescription; - } - - /** - * Gets the {@link Parcelable} data. - * - * @return The parcelable data. - */ - public Parcelable getParcelableData() { - return mParcelableData; - } - - /** - * Sets the {@link Parcelable} data of the event. - * - * @param parcelableData The parcelable data. - */ - public void setParcelableData(Parcelable parcelableData) { - mParcelableData = parcelableData; - } - - /** - * Gets the value of a boolean property. - * - * @param property The property. - * @return The value. - */ - public boolean getBooleanProperty(int property) { - return (mBooleanProperties & property) == property; - } - - /** - * Sets a boolean property. - * - * @param property The property. - * @param value The value. - */ - private void setBooleanProperty(int property, boolean value) { - if (value) { - mBooleanProperties |= property; - } else { - mBooleanProperties &= ~property; - } - } - - /** - * Returns a cached instance if such is available or a new one is - * instantiated. - * - * @return An instance. - */ - protected static AccessibilityRecord obtain() { - synchronized (mPoolLock) { - if (sPool != null) { - AccessibilityRecord record = sPool; - sPool = sPool.mNext; - sPoolSize--; - record.mNext = null; - record.mIsInPool = false; - return record; - } - return new AccessibilityRecord(); - } - } - - /** - * Return an instance back to be reused. - *

- * Note: You must not touch the object after calling this function. - */ - public void recycle() { - if (mIsInPool) { - return; - } - clear(); - synchronized (mPoolLock) { - if (sPoolSize <= MAX_POOL_SIZE) { - mNext = sPool; - sPool = this; - mIsInPool = true; - sPoolSize++; - } - } - } - - /** - * Clears the state of this instance. - */ - protected void clear() { - mBooleanProperties = 0; - mCurrentItemIndex = INVALID_POSITION; - mItemCount = 0; - mFromIndex = 0; - mAddedCount = 0; - mRemovedCount = 0; - mClassName = null; - mContentDescription = null; - mBeforeText = null; - mParcelableData = null; - mText.clear(); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(" [ ClassName: " + mClassName); - builder.append("; Text: " + mText); - builder.append("; ContentDescription: " + mContentDescription); - builder.append("; ItemCount: " + mItemCount); - builder.append("; CurrentItemIndex: " + mCurrentItemIndex); - builder.append("; IsEnabled: " + getBooleanProperty(PROPERTY_ENABLED)); - builder.append("; IsPassword: " + getBooleanProperty(PROPERTY_PASSWORD)); - builder.append("; IsChecked: " + getBooleanProperty(PROPERTY_CHECKED)); - builder.append("; IsFullScreen: " + getBooleanProperty(PROPERTY_FULL_SCREEN)); - builder.append("; BeforeText: " + mBeforeText); - builder.append("; FromIndex: " + mFromIndex); - builder.append("; AddedCount: " + mAddedCount); - builder.append("; RemovedCount: " + mRemovedCount); - builder.append("; ParcelableData: " + mParcelableData); - builder.append(" ]"); - return builder.toString(); - } -} diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index aaaae327cb641..7633569d5312a 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -35,7 +35,5 @@ interface IAccessibilityManager { List getAccessibilityServiceList(); - List getEnabledAccessibilityServiceList(int feedbackType); - void interrupt(); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index d63d421fb3b59..6cb5c35339d5e 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -55,7 +55,6 @@ import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.ViewTreeObserver; -import android.view.accessibility.AccessibilityEvent; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; @@ -2556,17 +2555,6 @@ public abstract class AbsListView extends AdapterView implements Te return false; } - @Override - public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { - // Add a record for ourselves as well. - AccessibilityEvent record = AccessibilityEvent.obtain(); - // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent - record.setClassName(getClass().getName()); - child.dispatchPopulateAccessibilityEvent(record); - event.appendRecord(record); - return true; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return false; diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 060f1a9b2bc07..f16efbdeb7be1 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -876,6 +876,7 @@ public abstract class AdapterView extends ViewGroup { @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + boolean populated = false; // This is an exceptional case which occurs when a window gets the // focus and sends a focus event via its focused child to announce // current focus/selection. AdapterView fires selection but not focus @@ -884,27 +885,22 @@ public abstract class AdapterView extends ViewGroup { event.setEventType(AccessibilityEvent.TYPE_VIEW_SELECTED); } - // We first get a chance to populate the event. - onPopulateAccessibilityEvent(event); - - // We send selection events only from AdapterView to avoid - // generation of such event for each child. + // we send selection events only from AdapterView to avoid + // generation of such event for each child View selectedView = getSelectedView(); if (selectedView != null) { - return selectedView.dispatchPopulateAccessibilityEvent(event); + populated = selectedView.dispatchPopulateAccessibilityEvent(event); } - return false; - } - - @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - View selectedView = getSelectedView(); - if (selectedView != null) { - event.setEnabled(selectedView.isEnabled()); + if (!populated) { + if (selectedView != null) { + event.setEnabled(selectedView.isEnabled()); + } + event.setItemCount(getCount()); + event.setCurrentItemIndex(getSelectedItemPosition()); } - event.setItemCount(getCount()); - event.setCurrentItemIndex(getSelectedItemPosition()); + + return populated; } @Override diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index bd595a568fc8e..bf636079987ac 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -199,8 +199,11 @@ public class CheckedTextView extends TextView implements Checkable { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - event.setChecked(mChecked); + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + boolean populated = super.dispatchPopulateAccessibilityEvent(event); + if (!populated) { + event.setChecked(mChecked); + } + return populated; } } diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index f050d41e3c55f..0df45cca6a65a 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -208,18 +208,22 @@ public abstract class CompoundButton extends Button implements Checkable { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + boolean populated = super.dispatchPopulateAccessibilityEvent(event); - int resourceId = 0; - if (mChecked) { - resourceId = R.string.accessibility_compound_button_selected; - } else { - resourceId = R.string.accessibility_compound_button_unselected; + if (!populated) { + int resourceId = 0; + if (mChecked) { + resourceId = R.string.accessibility_compound_button_selected; + } else { + resourceId = R.string.accessibility_compound_button_unselected; + } + String state = getResources().getString(resourceId); + event.getText().add(state); + event.setChecked(mChecked); } - String state = getResources().getString(resourceId); - event.getText().add(state); - event.setChecked(mChecked); + + return populated; } @Override diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 30fb927cc3cc8..7210e219b3003 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -353,14 +353,13 @@ public class DatePicker extends FrameLayout { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - - final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR; String selectedDateUtterance = DateUtils.formatDateTime(mContext, mCurrentDate.getTimeInMillis(), flags); event.getText().add(selectedDateUtterance); + return true; } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 5618dbe25e06e..d76a956b8c678 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1998,32 +1998,36 @@ public class ListView extends AbsListView { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + boolean populated = super.dispatchPopulateAccessibilityEvent(event); // If the item count is less than 15 then subtract disabled items from the count and // position. Otherwise ignore disabled items. - int itemCount = 0; - int currentItemIndex = getSelectedItemPosition(); + if (!populated) { + int itemCount = 0; + int currentItemIndex = getSelectedItemPosition(); - ListAdapter adapter = getAdapter(); - if (adapter != null) { - final int count = adapter.getCount(); - if (count < 15) { - for (int i = 0; i < count; i++) { - if (adapter.isEnabled(i)) { - itemCount++; - } else if (i <= currentItemIndex) { - currentItemIndex--; + ListAdapter adapter = getAdapter(); + if (adapter != null) { + final int count = adapter.getCount(); + if (count < 15) { + for (int i = 0; i < count; i++) { + if (adapter.isEnabled(i)) { + itemCount++; + } else if (i <= currentItemIndex) { + currentItemIndex--; + } } + } else { + itemCount = count; } - } else { - itemCount = count; } + + event.setItemCount(itemCount); + event.setCurrentItemIndex(currentItemIndex); } - event.setItemCount(itemCount); - event.setCurrentItemIndex(currentItemIndex); + return populated; } /** diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 96d41a0ed0b1f..8db34d91d74fe 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -1027,10 +1027,12 @@ public class ProgressBar extends View { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - event.setItemCount(mMax); - event.setCurrentItemIndex(mProgress); + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + if (!super.dispatchPopulateAccessibilityEvent(event)) { + event.setItemCount(mMax); + event.setCurrentItemIndex(mProgress); + } + return true; } /** diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index 31ec7853c8048..6f76dd0d2b757 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -427,19 +427,12 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - onPopulateAccessibilityEvent(event); - // Dispatch only to the selected tab. - if (mSelectedTab != -1) { - return getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event); - } - return false; - } - - @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); event.setItemCount(getTabCount()); event.setCurrentItemIndex(mSelectedTab); + if (mSelectedTab != -1) { + getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event); + } + return true; } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 83f3c6b301b72..8110d8ef26037 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7896,9 +7896,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { if (!isShown()) { - return; + return false; } final boolean isPassword = hasPasswordTransformationMethod(); @@ -7914,6 +7914,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { event.setPassword(isPassword); } + return false; } void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 423e735c787bf..029d69020c78b 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -409,9 +409,7 @@ public class TimePicker extends FrameLayout { } @Override - public void onPopulateAccessibilityEvent(AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(event); - + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { int flags = DateUtils.FORMAT_SHOW_TIME; if (mIs24HourView) { flags |= DateUtils.FORMAT_24HOUR; @@ -423,6 +421,7 @@ public class TimePicker extends FrameLayout { String selectedDateUtterance = DateUtils.formatDateTime(mContext, mTempCalendar.getTimeInMillis(), flags); event.getText().add(selectedDateUtterance); + return true; } private void updateHourControl() { diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java index 8ba0a0b67ef4c..ced8feb450da4 100644 --- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -20,8 +20,8 @@ import com.android.server.wm.InputFilter; import android.content.Context; import android.util.Slog; -import android.view.InputDevice; import android.view.InputEvent; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowManagerPolicy; @@ -32,35 +32,10 @@ import android.view.WindowManagerPolicy; */ public class AccessibilityInputFilter extends InputFilter { private static final String TAG = "AccessibilityInputFilter"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private final Context mContext; - /** - * This is an interface for explorers that take a {@link MotionEvent} - * stream and perform touch exploration of the screen content. - */ - public interface Explorer { - /** - * Handles a {@link MotionEvent}. - * - * @param event The event to handle. - * @param policyFlags The policy flags associated with the event. - */ - public void onMotionEvent(MotionEvent event, int policyFlags); - - /** - * Requests that the explorer clears its internal state. - * - * @param event The last received event. - * @param policyFlags The policy flags associated with the event. - */ - public void clear(MotionEvent event, int policyFlags); - } - - private TouchExplorer mTouchExplorer; - private int mTouchscreenSourceDeviceId; - public AccessibilityInputFilter(Context context) { super(context.getMainLooper()); mContext = context; @@ -85,27 +60,27 @@ public class AccessibilityInputFilter extends InputFilter { @Override public void onInputEvent(InputEvent event, int policyFlags) { if (DEBUG) { - Slog.d(TAG, "Received event: " + event + ", policyFlags=0x" - + Integer.toHexString(policyFlags)); + Slog.d(TAG, "Accessibility input filter received input event: " + + event + ", policyFlags=0x" + Integer.toHexString(policyFlags)); } - if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { - MotionEvent motionEvent = (MotionEvent) event; - int deviceId = event.getDeviceId(); - if (mTouchscreenSourceDeviceId != deviceId) { - mTouchscreenSourceDeviceId = deviceId; - if (mTouchExplorer != null) { - mTouchExplorer.clear(motionEvent, policyFlags); - } else { - mTouchExplorer = new TouchExplorer(this, mContext); + + // To prove that this is working as intended, we will silently transform + // Q key presses into non-repeating Z's as part of this stub implementation. + // TODO: Replace with the real thing. + if (event instanceof KeyEvent) { + final KeyEvent keyEvent = (KeyEvent)event; + if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_Q) { + if (keyEvent.getRepeatCount() == 0) { + sendInputEvent(new KeyEvent(keyEvent.getDownTime(), keyEvent.getEventTime(), + keyEvent.getAction(), KeyEvent.KEYCODE_Z, keyEvent.getRepeatCount(), + keyEvent.getMetaState(), keyEvent.getDeviceId(), keyEvent.getScanCode(), + keyEvent.getFlags(), keyEvent.getSource()), + policyFlags | WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); } + return; } - if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) { - mTouchExplorer.onMotionEvent(motionEvent, policyFlags); - } else { - mTouchExplorer.clear(motionEvent, policyFlags); - } - } else { - super.onInputEvent(event, policyFlags); } + + super.onInputEvent(event, policyFlags); } } diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 1ad80470f7170..7a483aad37573 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -56,7 +56,6 @@ import android.view.accessibility.IAccessibilityManagerClient; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -75,8 +74,6 @@ import java.util.Set; public class AccessibilityManagerService extends IAccessibilityManager.Stub implements HandlerCaller.Callback { - private static final boolean DEBUG = false; - private static final String LOG_TAG = "AccessibilityManagerService"; private static int sIdCounter = 0; @@ -105,9 +102,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':'); - private final SparseArray> mFeedbackTypeToEnabledServicesMap = - new SparseArray>(); - private PackageManager mPackageManager; private int mHandledFeedbackTypes = 0; @@ -217,6 +211,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } manageServicesLocked(); + updateInputFilterLocked(); } return; @@ -257,6 +252,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub unbindAllServicesLocked(); } updateClientsLocked(); + updateInputFilterLocked(); } } }); @@ -304,16 +300,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - public List getEnabledAccessibilityServiceList(int feedbackType) { - synchronized (mLock) { - List enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType); - if (enabledServices == null) { - return Collections.emptyList(); - } - return enabledServices; - } - } - public void interrupt() { synchronized (mLock) { for (int i = 0, count = mServices.size(); i < count; i++) { @@ -353,8 +339,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } service.mNotificationTimeout = info.notificationTimeout; service.mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0; - - updateStateOnEnabledService(service); } return; default: @@ -465,7 +449,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub try { listener.onAccessibilityEvent(event); - if (DEBUG) { + if (false) { Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); } } catch (RemoteException re) { @@ -485,11 +469,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * @return True if the service was removed, false otherwise. */ private boolean removeDeadServiceLocked(Service service) { - if (DEBUG) { + if (false) { Slog.i(LOG_TAG, "Dead service " + service.mService + " removed"); } mHandler.removeMessages(service.mId); - updateStateOnDisabledService(service); return mServices.remove(service); } @@ -610,7 +593,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (isEnabled) { if (enabledServices.contains(componentName)) { if (service == null) { - service = new Service(componentName, intalledService); + service = new Service(componentName); } service.bind(); } else if (!enabledServices.contains(componentName)) { @@ -660,47 +643,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - /** - * Updates the set of enabled services for a given feedback type and - * if more than one of them provides spoken feedback enables touch - * exploration. - * - * @param service An enable service. - */ - private void updateStateOnEnabledService(Service service) { - int feedbackType = service.mFeedbackType; - List enabledServices = mFeedbackTypeToEnabledServicesMap.get(feedbackType); - if (enabledServices == null) { - enabledServices = new ArrayList(); - mFeedbackTypeToEnabledServicesMap.put(feedbackType, enabledServices); - } - enabledServices.add(service.mServiceInfo); - - // We enable touch exploration if at least one - // enabled service provides spoken feedback. - if (enabledServices.size() > 0 - && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { - updateClientsLocked(); - updateInputFilterLocked(); - } - } - - private void updateStateOnDisabledService(Service service) { - List enabledServices = - mFeedbackTypeToEnabledServicesMap.get(service.mFeedbackType); - if (enabledServices == null) { - return; - } - enabledServices.remove(service.mServiceInfo); - // We disable touch exploration if no - // enabled service provides spoken feedback. - if (enabledServices.isEmpty() - && service.mFeedbackType == AccessibilityServiceInfo.FEEDBACK_SPOKEN) { - updateClientsLocked(); - updateInputFilterLocked(); - } - } - /** * This class represents an accessibility service. It stores all per service * data required for the service management, provides API for starting/stopping the @@ -712,8 +654,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub class Service extends IAccessibilityServiceConnection.Stub implements ServiceConnection { int mId = 0; - ServiceInfo mServiceInfo; - IBinder mService; IEventListener mServiceInterface; @@ -738,10 +678,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final SparseArray mPendingEvents = new SparseArray(); - Service(ComponentName componentName, ServiceInfo serviceInfo) { + Service(ComponentName componentName) { mId = sIdCounter++; mComponentName = componentName; - mServiceInfo = serviceInfo; mIntent = new Intent().setComponent(mComponentName); mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, com.android.internal.R.string.accessibility_binding_label); @@ -773,7 +712,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mContext.unbindService(this); mComponentNameToServiceMap.remove(mComponentName); mServices.remove(this); - updateStateOnDisabledService(this); return true; } return false; diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java deleted file mode 100644 index 4ba6060ca47f0..0000000000000 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ /dev/null @@ -1,1540 +0,0 @@ -/* - ** Copyright 2011, The Android Open Source Project - ** - ** Licensed under the Apache License, Version 2.0 (the "License"); - ** you may not use this file except in compliance with the License. - ** You may obtain a copy of the License at - ** - ** http://www.apache.org/licenses/LICENSE-2.0 - ** - ** Unless required by applicable law or agreed to in writing, software - ** distributed under the License is distributed on an "AS IS" BASIS, - ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ** See the License for the specific language governing permissions and - ** limitations under the License. - */ - -package com.android.server.accessibility; - -import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END; -import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START; - -import com.android.server.accessibility.AccessibilityInputFilter.Explorer; -import com.android.server.wm.InputFilter; - -import android.content.Context; -import android.os.Handler; -import android.os.SystemClock; -import android.util.Slog; -import android.util.SparseArray; -import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.view.WindowManagerPolicy; -import android.view.MotionEvent.PointerCoords; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; - -import java.util.Arrays; - -/** - * This class is a strategy for performing touch exploration. It - * transforms the motion event stream by modifying, adding, replacing, - * and consuming certain events. The interaction model is: - * - *

    - *
  1. 1. One finger moving around performs touch exploration.
  2. - *
  3. 2. Two close fingers moving in the same direction perform a drag.
  4. - *
  5. 3. Multi-finger gestures are delivered to view hierarchy.
  6. - *
  7. 4. Pointers that have not moved more than a specified distance after they - * went down are considered inactive.
  8. - *
  9. 5. Two fingers moving too far from each other or in different directions - * are considered a multi-finger gesture.
  10. - *
  11. 6. Tapping on the last touch explored location within given time and - * distance slop performs a click.
  12. - *
  13. 7. Tapping and holding for a while on the last touch explored location within - * given time and distance slop performs a long press.
  14. - *
      - * - * @hide - */ -public class TouchExplorer implements Explorer { - private static final boolean DEBUG = false; - - // Tag for logging received events. - private static final String LOG_TAG_RECEIVED = "TouchExplorer-RECEIVED"; - // Tag for logging injected events. - private static final String LOG_TAG_INJECTED = "TouchExplorer-INJECTED"; - // Tag for logging the current state. - private static final String LOG_TAG_STATE = "TouchExplorer-STATE"; - - // States this explorer can be in. - private static final int STATE_TOUCH_EXPLORING = 0x00000001; - private static final int STATE_DRAGGING = 0x00000002; - private static final int STATE_DELEGATING = 0x00000004; - - // Human readable symbolic names for the states of the explorer. - private static final SparseArray sStateSymbolicNames = new SparseArray(); - static { - SparseArray symbolicNames = sStateSymbolicNames; - symbolicNames.append(STATE_TOUCH_EXPLORING, "STATE_TOUCH_EXPLORING"); - symbolicNames.append(STATE_DRAGGING, "STATE_DRAGING"); - symbolicNames.append(STATE_DELEGATING, "STATE_DELEGATING"); - } - - // Invalid pointer ID. - private static final int INVALID_POINTER_ID = -1; - - // The coefficient by which to multiply - // ViewConfiguration.#getScaledTouchExplorationTapSlop() - // to compute #mDraggingDistance. - private static final int COEFFICIENT_DRAGGING_DISTANCE = 2; - - // The time slop in milliseconds for activating an item after it has - // been touch explored. Tapping on an item within this slop will perform - // a click and tapping and holding down a long press. - private static final long ACTIVATION_TIME_SLOP = 2000; - - // This constant captures the current implementation detail that - // pointer IDs are between 0 and 31 inclusive (subject to change). - // (See MAX_POINTER_ID in frameworks/base/include/ui/Input.h) - private static final int MAX_POINTER_COUNT = 32; - - // The minimum of the cosine between the vectors of two moving - // pointers so they can be considered moving in the same direction. - private static final float MIN_ANGLE_COS = 0.866025404f; // cos(pi/6) - - // The delay for sending a hover enter event. - private static final long DELAY_SEND_HOVER_MOVE = 200; - - // Temporary array for storing pointer IDs. - private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT]; - - // Temporary array for mapping new to old pointer IDs while filtering inactive pointers. - private final int [] mTempNewToOldPointerIndexMap = new int[MAX_POINTER_COUNT]; - - // Temporary array for storing PointerCoords - private final PointerCoords[] mTempPointerCoords= new PointerCoords[MAX_POINTER_COUNT]; - - // The maximal distance between two pointers so they are - // considered to be performing a drag operation. - private final float mDraggingDistance; - - // The distance from the last touch explored location tapping within - // which would perform a click and tapping and holding a long press. - private final int mTouchExplorationTapSlop; - - // Context handle for accessing resources. - private final Context mContext; - - // The InputFilter this tracker is associated with i.e. the filter - // which delegates event processing to this touch explorer. - private final InputFilter mInputFilter; - - // Helper class for tracking pointers on the screen, for example which - // pointers are down, which are active, etc. - private final PointerTracker mPointerTracker; - - // Handle to the accessibility manager for firing accessibility events - // announcing touch exploration gesture start and end. - private final AccessibilityManager mAccessibilityManager; - - // The last event that was received while performing touch exploration. - private MotionEvent mLastTouchExploreEvent; - - // The current state of the touch explorer. - private int mCurrentState = STATE_TOUCH_EXPLORING; - - // Flag whether a touch exploration gesture is in progress. - private boolean mTouchExploreGestureInProgress; - - // The ID of the pointer used for dragging. - private int mDraggingPointerId; - - // Handler for performing asynchronous operations. - private final Handler mHandler; - - // Command for delayed sending of a hover event. - private final SendHoverDelayed mSendHoverDelayed; - - /** - * Creates a new instance. - * - * @param inputFilter The input filter associated with this explorer. - * @param context A context handle for accessing resources. - */ - public TouchExplorer(InputFilter inputFilter, Context context) { - mInputFilter = inputFilter; - mTouchExplorationTapSlop = - ViewConfiguration.get(context).getScaledTouchExplorationTapSlop(); - mDraggingDistance = mTouchExplorationTapSlop * COEFFICIENT_DRAGGING_DISTANCE; - mPointerTracker = new PointerTracker(context); - mContext = context; - mHandler = new Handler(context.getMainLooper()); - mSendHoverDelayed = new SendHoverDelayed(); - mAccessibilityManager = AccessibilityManager.getInstance(context); - - // Populate the temporary array with PointerCorrds to be reused. - for (int i = 0, count = mTempPointerCoords.length; i < count; i++) { - mTempPointerCoords[i] = new PointerCoords(); - } - } - - public void clear(MotionEvent event, int policyFlags) { - sendUpForInjectedDownPointers(event, policyFlags); - clear(); - } - - /** - * {@inheritDoc} - */ - public void onMotionEvent(MotionEvent event, int policyFlags) { - if (DEBUG) { - Slog.d(LOG_TAG_RECEIVED, "Received event: " + event + ", policyFlags=0x" - + Integer.toHexString(policyFlags)); - Slog.d(LOG_TAG_STATE, sStateSymbolicNames.get(mCurrentState)); - } - - // Keep track of the pointers's state. - mPointerTracker.onReceivedMotionEvent(event); - - switch(mCurrentState) { - case STATE_TOUCH_EXPLORING: { - handleMotionEventStateTouchExploring(event, policyFlags); - } break; - case STATE_DRAGGING: { - handleMotionEventStateDragging(event, policyFlags); - } break; - case STATE_DELEGATING: { - handleMotionEventStateDelegating(event, policyFlags); - } break; - default: { - throw new IllegalStateException("Illegal state: " + mCurrentState); - } - } - } - - /** - * Handles a motion event in touch exploring state. - * - * @param event The event to be handled. - * @param policyFlags The policy flags associated with the event. - */ - private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) { - PointerTracker pointerTracker = mPointerTracker; - final int activePointerCount = pointerTracker.getActivePointerCount(); - - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - // Send a hover for every finger down so the user gets feedback - // where she is currently touching. - mSendHoverDelayed.forceSendAndRemove(); - mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 0, policyFlags, - DELAY_SEND_HOVER_MOVE); - } break; - case MotionEvent.ACTION_POINTER_DOWN: { - switch (activePointerCount) { - case 0: { - throw new IllegalStateException("The must always be one active pointer in" - + "touch exploring state!"); - } - case 1: { - // Schedule a hover event which will lead to firing an - // accessibility event from the hovered view. - mSendHoverDelayed.remove(); - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIndex = event.findPointerIndex(pointerId); - final int lastAction = pointerTracker.getLastInjectedHoverAction(); - // If a schedules hover enter for another pointer is delivered we send move. - final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER) - ? MotionEvent.ACTION_HOVER_MOVE - : MotionEvent.ACTION_HOVER_ENTER; - mSendHoverDelayed.post(event, action, pointerIndex, policyFlags, - DELAY_SEND_HOVER_MOVE); - - if (mLastTouchExploreEvent == null) { - break; - } - - // If more pointers down on the screen since the last touch - // exploration we discard the last cached touch explore event. - if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) { - mLastTouchExploreEvent = null; - } - } break; - default: { - /* do nothing - let the code for ACTION_MOVE decide what to do */ - } break; - } - } break; - case MotionEvent.ACTION_MOVE: { - switch (activePointerCount) { - case 0: { - /* do nothing - no active pointers so we swallow the event */ - } break; - case 1: { - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIndex = event.findPointerIndex(pointerId); - - // Detect touch exploration gesture start by having one active pointer - // that moved more than a given distance. - if (!mTouchExploreGestureInProgress) { - final float deltaX = pointerTracker.getReceivedPointerDownX(pointerId) - - event.getX(pointerIndex); - final float deltaY = pointerTracker.getReceivedPointerDownY(pointerId) - - event.getY(pointerIndex); - final double moveDelta = Math.hypot(deltaX, deltaY); - - if (moveDelta > mTouchExplorationTapSlop) { - mTouchExploreGestureInProgress = true; - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START); - // Make sure the scheduled down/move event is sent. - mSendHoverDelayed.forceSendAndRemove(); - sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex, - policyFlags); - } - } else { - // Touch exploration gesture in progress so send a hover event. - sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex, - policyFlags); - } - - // Detect long press on the last touch explored position. - if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null) { - - // If the down was not in the time slop => nothing else to do. - final long pointerDownTime = - pointerTracker.getReceivedPointerDownTime(pointerId); - final long lastExploreTime = mLastTouchExploreEvent.getEventTime(); - final long deltaTimeExplore = pointerDownTime - lastExploreTime; - if (deltaTimeExplore > ACTIVATION_TIME_SLOP) { - mLastTouchExploreEvent = null; - break; - } - - // If the pointer moved more than the tap slop => nothing else to do. - final float deltaX = mLastTouchExploreEvent.getX(pointerIndex) - - event.getX(pointerIndex); - final float deltaY = mLastTouchExploreEvent.getY(pointerIndex) - - event.getY(pointerIndex); - final float moveDelta = (float) Math.hypot(deltaX, deltaY); - if (moveDelta > mTouchExplorationTapSlop) { - mLastTouchExploreEvent = null; - break; - } - - // If down for long enough we get a long press. - final long deltaTimeMove = event.getEventTime() - pointerDownTime; - if (deltaTimeMove > ViewConfiguration.getLongPressTimeout()) { - mCurrentState = STATE_DELEGATING; - // Make sure the scheduled hover exit is delivered. - mSendHoverDelayed.forceSendAndRemove(); - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - sendMotionEvent(event, policyFlags); - mTouchExploreGestureInProgress = false; - mLastTouchExploreEvent = null; - } - } - } break; - case 2: { - // Make sure the scheduled hover enter is delivered. - mSendHoverDelayed.forceSendAndRemove(); - // We want to no longer hover over the location so subsequent - // touch at the same spot will generate a hover enter. - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIndex = event.findPointerIndex(pointerId); - sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, - policyFlags); - - if (isDraggingGesture(event)) { - // Two pointers moving in the same direction within - // a given distance perform a drag. - mCurrentState = STATE_DRAGGING; - if (mTouchExploreGestureInProgress) { - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); - mTouchExploreGestureInProgress = false; - } - mDraggingPointerId = pointerTracker.getPrimaryActivePointerId(); - sendDragEvent(event, MotionEvent.ACTION_DOWN, policyFlags); - } else { - // Two pointers moving arbitrary are delegated to the view hierarchy. - mCurrentState = STATE_DELEGATING; - if (mTouchExploreGestureInProgress) { - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); - mTouchExploreGestureInProgress = false; - } - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } - } break; - default: { - // Make sure the scheduled hover enter is delivered. - mSendHoverDelayed.forceSendAndRemove(); - // We want to no longer hover over the location so subsequent - // touch at the same spot will generate a hover enter. - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIndex = event.findPointerIndex(pointerId); - sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, - policyFlags); - - // More than two pointers are delegated to the view hierarchy. - mCurrentState = STATE_DELEGATING; - mSendHoverDelayed.remove(); - if (mTouchExploreGestureInProgress) { - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); - mTouchExploreGestureInProgress = false; - } - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } - } - } break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: { - switch (activePointerCount) { - case 0: { - // If the pointer that went up was not active we have nothing to do. - if (!pointerTracker.wasLastReceivedUpPointerActive()) { - break; - } - - // If touch exploring announce the end of the gesture. - if (mTouchExploreGestureInProgress) { - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); - mTouchExploreGestureInProgress = false; - } - - // Detect whether to activate i.e. click on the last explored location. - if (mLastTouchExploreEvent != null) { - final int pointerId = pointerTracker.getLastReceivedUpPointerId(); - - // If the down was not in the time slop => nothing else to do. - final long eventTime = - pointerTracker.getLastReceivedUpPointerDownTime(); - final long exploreTime = mLastTouchExploreEvent.getEventTime(); - final long deltaTime = eventTime - exploreTime; - if (deltaTime > ACTIVATION_TIME_SLOP) { - mSendHoverDelayed.forceSendAndRemove(); - scheduleHoverExit(event, policyFlags); - mLastTouchExploreEvent = MotionEvent.obtain(event); - break; - } - - // If the pointer moved more than the tap slop => nothing else to do. - final int pointerIndex = event.findPointerIndex(pointerId); - final float deltaX = pointerTracker.getLastReceivedUpPointerDownX() - - event.getX(pointerIndex); - final float deltaY = pointerTracker.getLastReceivedUpPointerDownY() - - event.getY(pointerIndex); - final float deltaMove = (float) Math.hypot(deltaX, deltaY); - if (deltaMove > mTouchExplorationTapSlop) { - mSendHoverDelayed.forceSendAndRemove(); - scheduleHoverExit(event, policyFlags); - mLastTouchExploreEvent = MotionEvent.obtain(event); - break; - } - - // All preconditions are met, so click the last explored location. - mSendHoverDelayed.forceSendAndRemove(); - sendActionDownAndUp(mLastTouchExploreEvent, policyFlags); - mLastTouchExploreEvent = null; - } else { - mSendHoverDelayed.forceSendAndRemove(); - scheduleHoverExit(event, policyFlags); - mLastTouchExploreEvent = MotionEvent.obtain(event); - } - } break; - } - } break; - case MotionEvent.ACTION_CANCEL: { - final int lastAction = pointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIndex = event.findPointerIndex(pointerId); - sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex, - policyFlags); - } - clear(); - } break; - } - } - - /** - * Handles a motion event in dragging state. - * - * @param event The event to be handled. - * @param policyFlags The policy flags associated with the event. - */ - private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - throw new IllegalStateException("Dragging state can be reached only if two " - + "pointers are already down"); - } - case MotionEvent.ACTION_POINTER_DOWN: { - // We are in dragging state so we have two pointers and another one - // goes down => delegate the three pointers to the view hierarchy - mCurrentState = STATE_DELEGATING; - sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } break; - case MotionEvent.ACTION_MOVE: { - final int activePointerCount = mPointerTracker.getActivePointerCount(); - switch (activePointerCount) { - case 2: { - if (isDraggingGesture(event)) { - // If still dragging send a drag event. - sendDragEvent(event, MotionEvent.ACTION_MOVE, policyFlags); - } else { - // The two pointers are moving either in different directions or - // no close enough => delegate the gesture to the view hierarchy. - mCurrentState = STATE_DELEGATING; - // Send an event to the end of the drag gesture. - sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); - // Deliver all active pointers to the view hierarchy. - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } - } break; - default: { - mCurrentState = STATE_DELEGATING; - // Send an event to the end of the drag gesture. - sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); - // Deliver all active pointers to the view hierarchy. - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } - } - } break; - case MotionEvent.ACTION_POINTER_UP: { - mCurrentState = STATE_TOUCH_EXPLORING; - // Send an event to the end of the drag gesture. - sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags); - } break; - case MotionEvent.ACTION_CANCEL: { - clear(); - } break; - } - } - - /** - * Handles a motion event in delegating state. - * - * @param event The event to be handled. - * @param policyFlags The policy flags associated with the event. - */ - public void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - throw new IllegalStateException("Delegating state can only be reached if " - + "there is at least one pointer down!"); - } - case MotionEvent.ACTION_UP: { - mCurrentState = STATE_TOUCH_EXPLORING; - } break; - case MotionEvent.ACTION_MOVE: { - // Check whether some other pointer became active because they have moved - // a given distance and if such exist send them to the view hierarchy - final int notInjectedCount = mPointerTracker.getNotInjectedActivePointerCount(); - if (notInjectedCount > 0) { - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - } - } break; - case MotionEvent.ACTION_POINTER_UP: { - // No active pointers => go to initial state. - if (mPointerTracker.getActivePointerCount() == 0) { - mCurrentState = STATE_TOUCH_EXPLORING; - } - } break; - case MotionEvent.ACTION_CANCEL: { - clear(); - } break; - } - // Deliver the event striping out inactive pointers. - sendMotionEventStripInactivePointers(event, policyFlags); - } - - /** - * Schedules a hover up event so subsequent poking on the same location after - * the scheduled delay will perform exploration. - * - * @param prototype The prototype from which to create the injected events. - * @param policyFlags The policy flags associated with the event. - */ - private void scheduleHoverExit(MotionEvent prototype, - int policyFlags) { - final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); - final int pointerIndex = prototype.findPointerIndex(pointerId); - // We want to no longer hover over the location so subsequent - // touch at the same spot will generate a hover enter. - mSendHoverDelayed.post(prototype, MotionEvent.ACTION_HOVER_EXIT, - pointerIndex, policyFlags, ACTIVATION_TIME_SLOP); - } - - /** - * Sends down events to the view hierarchy for all active pointers which are - * not already being delivered i.e. pointers that are not yet injected. - * - * @param prototype The prototype from which to create the injected events. - * @param policyFlags The policy flags associated with the event. - */ - private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - PointerTracker pointerTracker = mPointerTracker; - int[] pointerIds = mTempPointerIds; - int pointerDataIndex = 0; - - final int pinterCount = prototype.getPointerCount(); - for (int i = 0; i < pinterCount; i++) { - final int pointerId = prototype.getPointerId(i); - - // Skip inactive pointers. - if (!pointerTracker.isActivePointer(pointerId)) { - continue; - } - // Skip already delivered pointers. - if (pointerTracker.isInjectedPointerDown(pointerId)) { - continue; - } - - // Populate and inject an event for the current pointer. - pointerIds[pointerDataIndex] = pointerId; - prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); - - final long downTime = pointerTracker.getLastInjectedDownEventTime(); - final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, pointerDataIndex); - final int pointerCount = pointerDataIndex + 1; - final long pointerDownTime = SystemClock.uptimeMillis(); - - MotionEvent event = MotionEvent.obtain(downTime, pointerDownTime, - action, pointerCount, pointerIds, pointerCoords, prototype.getMetaState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - sendMotionEvent(event, policyFlags); - event.recycle(); - - pointerDataIndex++; - } - } - - /** - * Sends up events to the view hierarchy for all active pointers which are - * already being delivered i.e. pointers that are injected. - * - * @param prototype The prototype from which to create the injected events. - * @param policyFlags The policy flags associated with the event. - */ - private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) { - PointerTracker pointerTracker = mPointerTracker; - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; - int pointerDataIndex = 0; - - final int pointerCount = prototype.getPointerCount(); - for (int i = 0; i < pointerCount; i++) { - final int pointerId = prototype.getPointerId(i); - - // Skip non injected down pointers. - if (!pointerTracker.isInjectedPointerDown(pointerId)) { - continue; - } - - // Populate and inject event. - pointerIds[pointerDataIndex] = pointerId; - prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); - - final long downTime = pointerTracker.getLastInjectedDownEventTime(); - final int action = computeInjectionAction(MotionEvent.ACTION_UP, pointerDataIndex); - final int newPointerCount = pointerDataIndex + 1; - final long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, - newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - - sendMotionEvent(event, policyFlags); - event.recycle(); - - pointerDataIndex++; - } - } - - /** - * Sends a motion event by first stripping the inactive pointers. - * - * @param prototype The prototype from which to create the injected event. - * @param policyFlags The policy flags associated with the event. - */ - private void sendMotionEventStripInactivePointers(MotionEvent prototype, int policyFlags) { - PointerTracker pointerTracker = mPointerTracker; - - // All pointers active therefore we just inject the event as is. - if (prototype.getPointerCount() == pointerTracker.getActivePointerCount()) { - sendMotionEvent(prototype, policyFlags); - return; - } - - // No active pointers and the one that just went up was not - // active, therefore we have nothing to do. - if (pointerTracker.getActivePointerCount() == 0 - && !pointerTracker.wasLastReceivedUpPointerActive()) { - return; - } - - // Filter out inactive pointers from the event and inject it. - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; - int [] newToOldPointerIndexMap = mTempNewToOldPointerIndexMap; - int newPointerIndex = 0; - int actionIndex = prototype.getActionIndex(); - - final int oldPointerCount = prototype.getPointerCount(); - for (int oldPointerIndex = 0; oldPointerIndex < oldPointerCount; oldPointerIndex++) { - final int pointerId = prototype.getPointerId(oldPointerIndex); - - // If the pointer is inactive or the pointer that just went up - // was inactive we strip the pointer data from the event. - if (!pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) { - if (oldPointerIndex <= prototype.getActionIndex()) { - actionIndex--; - } - continue; - } - - newToOldPointerIndexMap[newPointerIndex] = oldPointerIndex; - pointerIds[newPointerIndex] = pointerId; - prototype.getPointerCoords(oldPointerIndex, pointerCoords[newPointerIndex]); - - newPointerIndex++; - } - - // If we skipped all pointers => nothing to do. - if (newPointerIndex == 0) { - return; - } - - // Populate and inject the event. - final long downTime = pointerTracker.getLastInjectedDownEventTime(); - final int action = computeInjectionAction(prototype.getActionMasked(), actionIndex); - final int newPointerCount = newPointerIndex; - MotionEvent prunedEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, - newPointerCount, pointerIds, pointerCoords, prototype.getMetaState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(),prototype.getFlags()); - - // Add the filtered history. - final int historySize = prototype.getHistorySize(); - for (int historyIndex = 0; historyIndex < historySize; historyIndex++) { - for (int pointerIndex = 0; pointerIndex < newPointerCount; pointerIndex++) { - final int oldPointerIndex = newToOldPointerIndexMap[pointerIndex]; - prototype.getPointerCoords(oldPointerIndex, pointerCoords[pointerIndex]); - } - final long historicalTime = prototype.getHistoricalEventTime(historyIndex); - prunedEvent.addBatch(historicalTime, pointerCoords, 0); - } - - sendMotionEvent(prunedEvent, policyFlags); - prunedEvent.recycle(); - } - - /** - * Sends a dragging event from a two pointer event. The two pointers are - * merged into one and delivered to the view hierarchy. Through the entire - * drag gesture the pointer id delivered to the view hierarchy is the same. - * - * @param prototype The prototype from which to create the injected event. - * @param action The dragging action that is to be injected. - * @param policyFlags The policy flags associated with the event. - */ - private void sendDragEvent(MotionEvent prototype, int action, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; - final int pointerId = mDraggingPointerId; - final int pointerIndex = prototype.findPointerIndex(pointerId); - - // Populate the event with the date of the dragging pointer and inject it. - pointerIds[0] = pointerId; - prototype.getPointerCoords(pointerIndex, pointerCoords[0]); - - MotionEvent event = MotionEvent.obtain(prototype.getDownTime(), - prototype.getEventTime(), action, 1, pointerIds, pointerCoords, - prototype.getMetaState(), prototype.getXPrecision(), prototype.getYPrecision(), - prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(), - prototype.getFlags()); - - sendMotionEvent(event, policyFlags); - event.recycle(); - } - - /** - * Sends an up and down events. - * - * @param prototype The prototype from which to create the injected events. - * @param policyFlags The policy flags associated with the event. - */ - private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; - final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); - final int pointerIndex = prototype.findPointerIndex(pointerId); - - // Send down. - pointerIds[0] = pointerId; - prototype.getPointerCoords(pointerIndex, pointerCoords[0]); - - final long downTime = SystemClock.uptimeMillis(); - - MotionEvent downEvent = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, - 1, mTempPointerIds, mTempPointerCoords, prototype.getMetaState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - - // Clone the down event before recycling it. - MotionEvent upEvent = MotionEvent.obtain(downEvent); - - sendMotionEvent(downEvent, policyFlags); - downEvent.recycle(); - - // Send up. - upEvent.setAction(MotionEvent.ACTION_UP); - sendMotionEvent(upEvent, policyFlags); - upEvent.recycle(); - } - - /** - * Sends a hover event. - * - * @param prototype The prototype from which to create the injected event. - * @param action The hover action. - * @param pointerIndex The action pointer index. - * @param policyFlags The policy flags associated with the event. - */ - private void sendHoverEvent(MotionEvent prototype, int action, int pointerIndex, int - policyFlags) { - PointerCoords[] pointerCoords = mTempPointerCoords; - int[] pointerIds = mTempPointerIds; - - // Keep only data relevant to a hover event. - pointerIds[0] = prototype.getPointerId(pointerIndex); - pointerCoords[0].clear(); - pointerCoords[0].x = prototype.getX(pointerIndex); - pointerCoords[0].y = prototype.getY(pointerIndex); - - final long downTime = mPointerTracker.getLastInjectedDownEventTime(); - - // Populate and inject a hover event. - MotionEvent hoverEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action, - 1, pointerIds, pointerCoords, 0, 0, 0, prototype.getDeviceId(), 0, - prototype.getSource(), 0); - - sendMotionEvent(hoverEvent, policyFlags); - hoverEvent.recycle(); - } - - /** - * Computes the action for an injected event based on a masked action - * and a pointer index. - * - * @param actionMasked The masked action. - * @param pointerIndex The index of the pointer which has changed. - * @return The action to be used for injection. - */ - private int computeInjectionAction(int actionMasked, int pointerIndex) { - switch (actionMasked) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: { - PointerTracker pointerTracker = mPointerTracker; - // Compute the action based on how many down pointers are injected. - if (pointerTracker.getInjectedPointerDownCount() == 0) { - return MotionEvent.ACTION_DOWN; - } else { - return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) - | MotionEvent.ACTION_POINTER_DOWN; - } - } - case MotionEvent.ACTION_POINTER_UP: { - PointerTracker pointerTracker = mPointerTracker; - // Compute the action based on how many down pointers are injected. - if (pointerTracker.getInjectedPointerDownCount() == 1) { - return MotionEvent.ACTION_UP; - } else { - return (pointerIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT) - | MotionEvent.ACTION_POINTER_UP; - } - } - default: - return actionMasked; - } - } - - /** - * Determines whether a two pointer gesture is a dragging one. - * - * @param event The event with the pointer data. - * @return True if the gesture is a dragging one. - */ - private boolean isDraggingGesture(MotionEvent event) { - PointerTracker pointerTracker = mPointerTracker; - int[] pointerIds = mTempPointerIds; - pointerTracker.populateActivePointerIds(pointerIds); - - final int firstPtrIndex = event.findPointerIndex(pointerIds[0]); - final int secondPtrIndex = event.findPointerIndex(pointerIds[1]); - - final float firstPtrX = event.getX(firstPtrIndex); - final float firstPtrY = event.getY(firstPtrIndex); - final float secondPtrX = event.getX(secondPtrIndex); - final float secondPtrY = event.getY(secondPtrIndex); - - // Check if the pointers are close enough. - final float deltaX = firstPtrX - secondPtrX; - final float deltaY = firstPtrY - secondPtrY; - final float deltaMove = (float) Math.hypot(deltaX, deltaY); - if (deltaMove > mDraggingDistance) { - return false; - } - - // Check if the pointers are moving in the same direction. - final float firstDeltaX = - firstPtrX - pointerTracker.getReceivedPointerDownX(firstPtrIndex); - final float firstDeltaY = - firstPtrY - pointerTracker.getReceivedPointerDownY(firstPtrIndex); - final float firstMagnitude = - (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY); - final float firstXNormalized = - (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX; - final float firstYNormalized = - (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY; - - final float secondDeltaX = - secondPtrX - pointerTracker.getReceivedPointerDownX(secondPtrIndex); - final float secondDeltaY = - secondPtrY - pointerTracker.getReceivedPointerDownY(secondPtrIndex); - final float secondMagnitude = - (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY); - final float secondXNormalized = - (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX; - final float secondYNormalized = - (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY; - - final float angleCos = - firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized; - - if (angleCos < MIN_ANGLE_COS) { - return false; - } - - return true; - } - - /** - * Sends an event announcing the start/end of a touch exploration gesture. - * - * @param eventType The type of the event to send. - */ - private void sendAccessibilityEvent(int eventType) { - AccessibilityEvent event = AccessibilityEvent.obtain(eventType); - event.setPackageName(mContext.getPackageName()); - event.setClassName(getClass().getName()); - mAccessibilityManager.sendAccessibilityEvent(event); - } - - /** - * Sends a motion event to the input filter for injection. - * - * @param event The event to send. - * @param policyFlags The policy flags associated with the event. - */ - private void sendMotionEvent(MotionEvent event, int policyFlags) { - if (DEBUG) { - Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x" - + Integer.toHexString(policyFlags)); - } - // Make sure that the user will see the event. - policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; - mPointerTracker.onInjectedMotionEvent(event); - mInputFilter.sendInputEvent(event, policyFlags); - } - - /** - * Clears the internal state of this explorer. - */ - private void clear() { - mSendHoverDelayed.remove(); - mPointerTracker.clear(); - mLastTouchExploreEvent = null; - mCurrentState = STATE_TOUCH_EXPLORING; - mTouchExploreGestureInProgress = false; - mDraggingPointerId = INVALID_POINTER_ID; - } - - /** - * Helper class for tracking pointers and more specifically which of - * them are currently down, which are active, and which are delivered - * to the view hierarchy. The enclosing {@link TouchExplorer} uses the - * pointer state reported by this class to perform touch exploration. - *

      - * The main purpose of this class is to allow the touch explorer to - * disregard pointers put down by accident by the user and not being - * involved in the interaction. For example, a blind user grabs the - * device with her left hand such that she touches the screen and she - * uses her right hand's index finger to explore the screen content. - * In this scenario the touches generated by the left hand are to be - * ignored. - */ - class PointerTracker { - private static final String LOG_TAG = "PointerTracker"; - - // The coefficient by which to multiply - // ViewConfiguration.#getScaledTouchSlop() - // to compute #mThresholdActivePointer. - private static final int COEFFICIENT_ACTIVE_POINTER = 2; - - // Pointers that moved less than mThresholdActivePointer - // are considered active i.e. are ignored. - private final double mThresholdActivePointer; - - // Keep track of where and when a pointer went down. - private final float[] mReceivedPointerDownX = new float[MAX_POINTER_COUNT]; - private final float[] mReceivedPointerDownY = new float[MAX_POINTER_COUNT]; - private final long[] mReceivedPointerDownTime = new long[MAX_POINTER_COUNT]; - - // Which pointers are down. - private int mReceivedPointersDown; - - // Which down pointers are active. - private int mActivePointers; - - // Primary active pointer which is either the first that went down - // or if it goes up the next active that most recently went down. - private int mPrimaryActivePointerId; - - // Flag indicating that there is at least one active pointer moving. - private boolean mHasMovingActivePointer; - - // Keep track of which pointers sent to the system are down. - private int mInjectedPointersDown; - - // Keep track of the last up pointer data. - private float mLastReceivedUpPointerDownX; - private float mLastReveivedUpPointerDownY; - private long mLastReceivedUpPointerDownTime; - private int mLastReceivedUpPointerId; - private boolean mLastReceivedUpPointerActive; - - // The time of the last injected down. - private long mLastInjectedDownEventTime; - - // The action of the last injected hover event. - private int mLastInjectedHoverEventAction = MotionEvent.ACTION_HOVER_EXIT; - - /** - * Creates a new instance. - * - * @param context Context for looking up resources. - */ - public PointerTracker(Context context) { - mThresholdActivePointer = - ViewConfiguration.get(context).getScaledTouchSlop() * COEFFICIENT_ACTIVE_POINTER; - } - - /** - * Clears the internals state. - */ - public void clear() { - Arrays.fill(mReceivedPointerDownX, 0); - Arrays.fill(mReceivedPointerDownY, 0); - Arrays.fill(mReceivedPointerDownTime, 0); - mReceivedPointersDown = 0; - mActivePointers = 0; - mPrimaryActivePointerId = 0; - mHasMovingActivePointer = false; - mInjectedPointersDown = 0; - mLastReceivedUpPointerDownX = 0; - mLastReveivedUpPointerDownY = 0; - mLastReceivedUpPointerDownTime = 0; - mLastReceivedUpPointerId = 0; - mLastReceivedUpPointerActive = false; - } - - /** - * Processes a received {@link MotionEvent} event. - * - * @param event The event to process. - */ - public void onReceivedMotionEvent(MotionEvent event) { - final int action = event.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - // New gesture so restart tracking injected down pointers. - mInjectedPointersDown = 0; - handleReceivedPointerDown(0, event); - } break; - case MotionEvent.ACTION_POINTER_DOWN: { - handleReceivedPointerDown(event.getActionIndex(), event); - } break; - case MotionEvent.ACTION_MOVE: { - handleReceivedPointerMove(event); - } break; - case MotionEvent.ACTION_UP: { - handleReceivedPointerUp(0, event); - } break; - case MotionEvent.ACTION_POINTER_UP: { - handleReceivedPointerUp(event.getActionIndex(), event); - } break; - } - if (DEBUG) { - Slog.i(LOG_TAG, "Received pointer: " + toString()); - } - } - - /** - * Processes an injected {@link MotionEvent} event. - * - * @param event The event to process. - */ - public void onInjectedMotionEvent(MotionEvent event) { - final int action = event.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - handleInjectedPointerDown(0, event); - } break; - case MotionEvent.ACTION_POINTER_DOWN: { - handleInjectedPointerDown(event.getActionIndex(), event); - } break; - case MotionEvent.ACTION_UP: { - handleInjectedPointerUp(0, event); - } break; - case MotionEvent.ACTION_POINTER_UP: { - handleInjectedPointerUp(event.getActionIndex(), event); - } break; - case MotionEvent.ACTION_HOVER_ENTER: - case MotionEvent.ACTION_HOVER_MOVE: - case MotionEvent.ACTION_HOVER_EXIT: { - mLastInjectedHoverEventAction = event.getActionMasked(); - } break; - } - if (DEBUG) { - Slog.i(LOG_TAG, "Injected pointer: " + toString()); - } - } - - /** - * @return The number of received pointers that are down. - */ - public int getReceivedPointerDownCount() { - return Integer.bitCount(mReceivedPointersDown); - } - - /** - * @return The number of down input pointers that are active. - */ - public int getActivePointerCount() { - return Integer.bitCount(mActivePointers); - } - - /** - * Whether an received pointer is down. - * - * @param pointerId The unique pointer id. - * @return True if the pointer is down. - */ - public boolean isReceivedPointerDown(int pointerId) { - final int pointerFlag = (1 << pointerId); - return (mReceivedPointersDown & pointerFlag) != 0; - } - - /** - * Whether an injected pointer is down. - * - * @param pointerId The unique pointer id. - * @return True if the pointer is down. - */ - public boolean isInjectedPointerDown(int pointerId) { - final int pointerFlag = (1 << pointerId); - return (mInjectedPointersDown & pointerFlag) != 0; - } - - /** - * @return The number of down pointers injected to the view hierarchy. - */ - public int getInjectedPointerDownCount() { - return Integer.bitCount(mInjectedPointersDown); - } - - /** - * Whether an input pointer is active. - * - * @param pointerId The unique pointer id. - * @return True if the pointer is active. - */ - public boolean isActivePointer(int pointerId) { - final int pointerFlag = (1 << pointerId); - return (mActivePointers & pointerFlag) != 0; - } - - /** - * @param pointerId The unique pointer id. - * @return The X coordinate where the pointer went down. - */ - public float getReceivedPointerDownX(int pointerId) { - return mReceivedPointerDownX[pointerId]; - } - - /** - * @param pointerId The unique pointer id. - * @return The Y coordinate where the pointer went down. - */ - public float getReceivedPointerDownY(int pointerId) { - return mReceivedPointerDownY[pointerId]; - } - - /** - * @param pointerId The unique pointer id. - * @return The time when the pointer went down. - */ - public long getReceivedPointerDownTime(int pointerId) { - return mReceivedPointerDownTime[pointerId]; - } - - /** - * @return The id of the primary pointer. - */ - public int getPrimaryActivePointerId() { - if (mPrimaryActivePointerId == INVALID_POINTER_ID) { - mPrimaryActivePointerId = findPrimaryActivePointer(); - } - return mPrimaryActivePointerId; - } - - /** - * @return The X coordinate where the last up received pointer went down. - */ - public float getLastReceivedUpPointerDownX() { - return mLastReceivedUpPointerDownX; - } - - /** - * @return The Y coordinate where the last up received pointer went down. - */ - public float getLastReceivedUpPointerDownY() { - return mLastReveivedUpPointerDownY; - } - - /** - * @return The time when the last up received pointer went down. - */ - public long getLastReceivedUpPointerDownTime() { - return mLastReceivedUpPointerDownTime; - } - - /** - * @return The id of the last received pointer that went up. - */ - public int getLastReceivedUpPointerId() { - return mLastReceivedUpPointerId; - } - - /** - * @return Whether the last received pointer that went up was active. - */ - public boolean wasLastReceivedUpPointerActive() { - return mLastReceivedUpPointerActive; - } - - /** - * @return The time of the last injected down event. - */ - public long getLastInjectedDownEventTime() { - return mLastInjectedDownEventTime; - } - - /** - * @return The action of the last injected hover event. - */ - public int getLastInjectedHoverAction() { - return mLastInjectedHoverEventAction; - } - - /** - * Populates the active pointer IDs to the given array. - *

      - * Note: The client is responsible for providing large enough array. - * - * @param outPointerIds The array to which to write the active pointers. - */ - public void populateActivePointerIds(int[] outPointerIds) { - int index = 0; - for (int idBits = mActivePointers; idBits != 0; ) { - final int id = Integer.numberOfTrailingZeros(idBits); - idBits &= ~(1 << id); - outPointerIds[index] = id; - index++; - } - } - - /** - * @return The number of non injected active pointers. - */ - public int getNotInjectedActivePointerCount() { - final int pointerState = mActivePointers & ~mInjectedPointersDown; - return Integer.bitCount(pointerState); - } - - /** - * @param pointerId The unique pointer id. - * @return Whether the pointer is active or was the last active than went up. - */ - private boolean isActiveOrWasLastActiveUpPointer(int pointerId) { - return (isActivePointer(pointerId) - || (mLastReceivedUpPointerId == pointerId - && mLastReceivedUpPointerActive)); - } - - /** - * Handles a received pointer down event. - * - * @param pointerIndex The index of the pointer that has changed. - * @param event The event to be handled. - */ - private void handleReceivedPointerDown(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final int pointerFlag = (1 << pointerId); - - mLastReceivedUpPointerId = 0; - mLastReceivedUpPointerDownX = 0; - mLastReveivedUpPointerDownY = 0; - mLastReceivedUpPointerDownTime = 0; - mLastReceivedUpPointerActive = false; - - mReceivedPointersDown |= pointerFlag; - mReceivedPointerDownX[pointerId] = event.getX(pointerIndex); - mReceivedPointerDownY[pointerId] = event.getY(pointerIndex); - mReceivedPointerDownTime[pointerId] = event.getEventTime(); - - if (!mHasMovingActivePointer) { - // If still no moving active pointers every - // down pointer is the only active one. - mActivePointers = pointerFlag; - mPrimaryActivePointerId = pointerId; - } else { - // If at least one moving active pointer every - // subsequent down pointer is active. - mActivePointers |= pointerFlag; - } - } - - /** - * Handles a received pointer move event. - * - * @param event The event to be handled. - */ - private void handleReceivedPointerMove(MotionEvent event) { - detectActivePointers(event); - } - - /** - * Handles a received pointer up event. - * - * @param pointerIndex The index of the pointer that has changed. - * @param event The event to be handled. - */ - private void handleReceivedPointerUp(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final int pointerFlag = (1 << pointerId); - - mLastReceivedUpPointerId = pointerId; - mLastReceivedUpPointerDownX = getReceivedPointerDownX(pointerId); - mLastReveivedUpPointerDownY = getReceivedPointerDownY(pointerId); - mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId); - mLastReceivedUpPointerActive = isActivePointer(pointerId); - - mReceivedPointersDown &= ~pointerFlag; - mActivePointers &= ~pointerFlag; - mReceivedPointerDownX[pointerId] = 0; - mReceivedPointerDownY[pointerId] = 0; - mReceivedPointerDownTime[pointerId] = 0; - - if (mActivePointers == 0) { - mHasMovingActivePointer = false; - } - if (mPrimaryActivePointerId == pointerId) { - mPrimaryActivePointerId = INVALID_POINTER_ID; - } - } - - /** - * Handles a injected pointer down event. - * - * @param pointerIndex The index of the pointer that has changed. - * @param event The event to be handled. - */ - private void handleInjectedPointerDown(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final int pointerFlag = (1 << pointerId); - mInjectedPointersDown |= pointerFlag; - mLastInjectedDownEventTime = event.getEventTime(); - } - - /** - * Handles a injected pointer up event. - * - * @param pointerIndex The index of the pointer that has changed. - * @param event The event to be handled. - */ - private void handleInjectedPointerUp(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final int pointerFlag = (1 << pointerId); - mInjectedPointersDown &= ~pointerFlag; - } - - /** - * Detects the active pointers in an event. - * - * @param event The event to examine. - */ - private void detectActivePointers(MotionEvent event) { - for (int i = 0, count = event.getPointerCount(); i < count; i++) { - final int pointerId = event.getPointerId(i); - if (mHasMovingActivePointer) { - // If already active => nothing to do. - if (isActivePointer(pointerId)) { - continue; - } - } - // Active pointers are ones that moved more than a given threshold. - final float pointerDeltaMove = computePointerDeltaMove(i, event); - if (pointerDeltaMove > mThresholdActivePointer) { - final int pointerFlag = (1 << pointerId); - mActivePointers |= pointerFlag; - mHasMovingActivePointer = true; - } - } - } - - /** - * @return The primary active pointer. - */ - private int findPrimaryActivePointer() { - int primaryActivePointerId = INVALID_POINTER_ID; - long minDownTime = Long.MAX_VALUE; - // Find the active pointer that went down first. - for (int i = 0, count = mReceivedPointerDownTime.length; i < count; i++) { - if (isActivePointer(i)) { - final long downPointerTime = mReceivedPointerDownTime[i]; - if (downPointerTime < minDownTime) { - minDownTime = downPointerTime; - primaryActivePointerId = i; - } - } - } - return primaryActivePointerId; - } - - /** - * Computes the move for a given action pointer index since the - * corresponding pointer went down. - * - * @param pointerIndex The action pointer index. - * @param event The event to examine. - * @return The distance the pointer has moved. - */ - private float computePointerDeltaMove(int pointerIndex, MotionEvent event) { - final int pointerId = event.getPointerId(pointerIndex); - final float deltaX = event.getX(pointerIndex) - mReceivedPointerDownX[pointerId]; - final float deltaY = event.getY(pointerIndex) - mReceivedPointerDownY[pointerId]; - return (float) Math.hypot(deltaX, deltaY); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("========================="); - builder.append("\nDown pointers #"); - builder.append(getReceivedPointerDownCount()); - builder.append(" [ "); - for (int i = 0; i < MAX_POINTER_COUNT; i++) { - if (isReceivedPointerDown(i)) { - builder.append(i); - builder.append(" "); - } - } - builder.append("]"); - builder.append("\nActive pointers #"); - builder.append(getActivePointerCount()); - builder.append(" [ "); - for (int i = 0; i < MAX_POINTER_COUNT; i++) { - if (isActivePointer(i)) { - builder.append(i); - builder.append(" "); - } - } - builder.append("]"); - builder.append("\nPrimary active pointer id [ "); - builder.append(getPrimaryActivePointerId()); - builder.append(" ]"); - builder.append("\n========================="); - return builder.toString(); - } - } - - /** - * Class for delayed sending of hover events. - */ - private final class SendHoverDelayed implements Runnable { - private static final String LOG_TAG = "SendHoverEnterOrExitDelayed"; - - private MotionEvent mEvent; - private int mAction; - private int mPointerIndex; - private int mPolicyFlags; - - public void post(MotionEvent prototype, int action, int pointerIndex, int policyFlags, - long delay) { - remove(); - mEvent = MotionEvent.obtain(prototype); - mAction = action; - mPointerIndex = pointerIndex; - mPolicyFlags = policyFlags; - mHandler.postDelayed(this, delay); - } - - public void remove() { - mHandler.removeCallbacks(this); - clear(); - } - - private boolean isPenidng() { - return (mEvent != null); - } - - private void clear() { - if (!isPenidng()) { - return; - } - mEvent.recycle(); - mEvent = null; - mAction = 0; - mPointerIndex = -1; - mPolicyFlags = 0; - } - - public void forceSendAndRemove() { - if (isPenidng()) { - run(); - remove(); - } - } - - public void run() { - if (DEBUG) { - if (mAction == MotionEvent.ACTION_HOVER_ENTER) { - Slog.d(LOG_TAG, "Injecting: " + MotionEvent.ACTION_HOVER_ENTER); - } else if (mAction == MotionEvent.ACTION_HOVER_MOVE) { - Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_MOVE"); - } else if (mAction == MotionEvent.ACTION_HOVER_EXIT) { - Slog.d(LOG_TAG, "Injecting: MotionEvent.ACTION_HOVER_EXIT"); - } - } - - sendHoverEvent(mEvent, mAction, mPointerIndex, mPolicyFlags); - clear(); - } - } -} diff --git a/services/java/com/android/server/wm/InputFilter.java b/services/java/com/android/server/wm/InputFilter.java index 8f0001aec30b1..7e1ab079cceb6 100644 --- a/services/java/com/android/server/wm/InputFilter.java +++ b/services/java/com/android/server/wm/InputFilter.java @@ -105,13 +105,11 @@ public abstract class InputFilter { private final InputEventConsistencyVerifier mInboundInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, - InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, - "InputFilter#InboundInputEventConsistencyVerifier") : null; + InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null; private final InputEventConsistencyVerifier mOutboundInputEventConsistencyVerifier = InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, - InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT, - "InputFilter#OutboundInputEventConsistencyVerifier") : null; + InputEventConsistencyVerifier.FLAG_RAW_DEVICE_INPUT) : null; /** * Creates the input filter.