Merge "Add suuport for splitting touch events across windows." into gingerbread
This commit is contained in:
@ -23,19 +23,12 @@ import android.view.KeyEvent;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.TextView.CursorController;
|
|
||||||
|
|
||||||
// XXX this doesn't extend MetaKeyKeyListener because the signatures
|
// XXX this doesn't extend MetaKeyKeyListener because the signatures
|
||||||
// don't match. Need to figure that out. Meanwhile the meta keys
|
// don't match. Need to figure that out. Meanwhile the meta keys
|
||||||
// won't work in fields that don't take input.
|
// won't work in fields that don't take input.
|
||||||
|
|
||||||
public class ArrowKeyMovementMethod implements MovementMethod {
|
public class ArrowKeyMovementMethod implements MovementMethod {
|
||||||
/**
|
|
||||||
* An optional controller for the cursor.
|
|
||||||
* Use {@link #setCursorController(CursorController)} to set this field.
|
|
||||||
*/
|
|
||||||
private CursorController mCursorController;
|
|
||||||
|
|
||||||
private boolean isCap(Spannable buffer) {
|
private boolean isCap(Spannable buffer) {
|
||||||
return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
|
return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
|
||||||
(MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0));
|
(MetaKeyKeyListener.getMetaState(buffer, MetaKeyKeyListener.META_SELECTING) != 0));
|
||||||
@ -192,21 +185,10 @@ public class ArrowKeyMovementMethod implements MovementMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
|
public boolean onTrackballEvent(TextView widget, Spannable text, MotionEvent event) {
|
||||||
if (mCursorController != null) {
|
|
||||||
mCursorController.hide();
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
|
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
|
||||||
if (mCursorController != null) {
|
|
||||||
return onTouchEventCursor(widget, buffer, event);
|
|
||||||
} else {
|
|
||||||
return onTouchEventStandard(widget, buffer, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean onTouchEventStandard(TextView widget, Spannable buffer, MotionEvent event) {
|
|
||||||
int initialScrollX = -1, initialScrollY = -1;
|
int initialScrollX = -1, initialScrollY = -1;
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
initialScrollX = Touch.getInitialScrollX(widget, buffer);
|
initialScrollX = Touch.getInitialScrollX(widget, buffer);
|
||||||
@ -278,49 +260,6 @@ public class ArrowKeyMovementMethod implements MovementMethod {
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean onTouchEventCursor(TextView widget, Spannable buffer, MotionEvent event) {
|
|
||||||
if (widget.isFocused() && !widget.didTouchFocusSelect()) {
|
|
||||||
switch (event.getActionMasked()) {
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
widget.cancelLongPress();
|
|
||||||
|
|
||||||
// Offset the current touch position (from controller to cursor)
|
|
||||||
final float x = event.getX() + mCursorController.getOffsetX();
|
|
||||||
final float y = event.getY() + mCursorController.getOffsetY();
|
|
||||||
mCursorController.updatePosition((int) x, (int) y);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
case MotionEvent.ACTION_CANCEL:
|
|
||||||
mCursorController = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the cursor controller.
|
|
||||||
*
|
|
||||||
* When set, this object can be used to handle touch events, that can be translated into cursor
|
|
||||||
* updates.
|
|
||||||
*
|
|
||||||
* {@link MotionEvent#ACTION_MOVE} events will call back the
|
|
||||||
* {@link CursorController#updatePosition(int, int)} controller's method, passing the current
|
|
||||||
* finger coordinates (offset by {@link CursorController#getOffsetX()} and
|
|
||||||
* {@link CursorController#getOffsetY()}) as parameters.
|
|
||||||
*
|
|
||||||
* When the gesture is finished (on a {@link MotionEvent#ACTION_UP} or
|
|
||||||
* {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null.
|
|
||||||
*
|
|
||||||
* @param cursorController A cursor controller implementation
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public void setCursorController(CursorController cursorController) {
|
|
||||||
mCursorController = cursorController;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canSelectArbitrarily() {
|
public boolean canSelectArbitrarily() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -584,6 +584,19 @@ public interface WindowManager extends ViewManager {
|
|||||||
*/
|
*/
|
||||||
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
|
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
|
||||||
|
|
||||||
|
/** Window flag: when set the window will accept for touch events
|
||||||
|
* outside of its bounds to be sent to other windows that also
|
||||||
|
* support split touch. When this flag is not set, the first pointer
|
||||||
|
* that goes down determines the window to which all subsequent touches
|
||||||
|
* go until all pointers go up. When this flag is set, each pointer
|
||||||
|
* (not necessarily the first) that goes down determines the window
|
||||||
|
* to which all subsequent touches of that pointer will go until that
|
||||||
|
* pointer goes up thereby enabling touches with multiple pointers
|
||||||
|
* to be split across multiple windows.
|
||||||
|
*
|
||||||
|
* {@hide} */
|
||||||
|
public static final int FLAG_SPLIT_TOUCH = 0x00800000;
|
||||||
|
|
||||||
/** Window flag: *sigh* The lock screen wants to continue running its
|
/** Window flag: *sigh* The lock screen wants to continue running its
|
||||||
* animation while it is fading. A kind-of hack to allow this. Maybe
|
* animation while it is fading. A kind-of hack to allow this. Maybe
|
||||||
* in the future we just make this the default behavior.
|
* in the future we just make this the default behavior.
|
||||||
|
@ -85,6 +85,7 @@ public class PopupWindow {
|
|||||||
private boolean mTouchable = true;
|
private boolean mTouchable = true;
|
||||||
private boolean mOutsideTouchable = false;
|
private boolean mOutsideTouchable = false;
|
||||||
private boolean mClippingEnabled = true;
|
private boolean mClippingEnabled = true;
|
||||||
|
private boolean mSplitTouchEnabled;
|
||||||
|
|
||||||
private OnTouchListener mTouchInterceptor;
|
private OnTouchListener mTouchInterceptor;
|
||||||
|
|
||||||
@ -564,6 +565,36 @@ public class PopupWindow {
|
|||||||
mClippingEnabled = enabled;
|
mClippingEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Indicates whether the popup window supports splitting touches.</p>
|
||||||
|
*
|
||||||
|
* @return true if the touch splitting is enabled, false otherwise
|
||||||
|
*
|
||||||
|
* @see #setSplitTouchEnabled(boolean)
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isSplitTouchEnabled() {
|
||||||
|
return mSplitTouchEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Allows the popup window to split touches across other windows that also
|
||||||
|
* support split touch. When this flag is not set, the first pointer
|
||||||
|
* that goes down determines the window to which all subsequent touches
|
||||||
|
* go until all pointers go up. When this flag is set, each pointer
|
||||||
|
* (not necessarily the first) that goes down determines the window
|
||||||
|
* to which all subsequent touches of that pointer will go until that
|
||||||
|
* pointer goes up thereby enabling touches with multiple pointers
|
||||||
|
* to be split across multiple windows.</p>
|
||||||
|
*
|
||||||
|
* @param enabled true if the split touches should be enabled, false otherwise
|
||||||
|
* @see #isSplitTouchEnabled()
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void setSplitTouchEnabled(boolean enabled) {
|
||||||
|
mSplitTouchEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Change the width and height measure specs that are given to the
|
* <p>Change the width and height measure specs that are given to the
|
||||||
* window manager by the popup. By default these are 0, meaning that
|
* window manager by the popup. By default these are 0, meaning that
|
||||||
@ -889,6 +920,9 @@ public class PopupWindow {
|
|||||||
if (!mClippingEnabled) {
|
if (!mClippingEnabled) {
|
||||||
curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||||
}
|
}
|
||||||
|
if (mSplitTouchEnabled) {
|
||||||
|
curFlags |= WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
|
||||||
|
}
|
||||||
return curFlags;
|
return curFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7601,16 +7601,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A CursorController instance can be used to control a cursor in the text.
|
* A CursorController instance can be used to control a cursor in the text.
|
||||||
*
|
* It is not used outside of {@link TextView}.
|
||||||
* It can be passed to an {@link ArrowKeyMovementMethod} which can intercepts events
|
|
||||||
* and send them to this object instead of the cursor.
|
|
||||||
*
|
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public interface CursorController {
|
private interface CursorController {
|
||||||
/* Cursor fade-out animation duration, in milliseconds. */
|
|
||||||
static final int FADE_OUT_DURATION = 400;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
|
* Makes the cursor controller visible on screen. Will be drawn by {@link #draw(Canvas)}.
|
||||||
* See also {@link #hide()}.
|
* See also {@link #hide()}.
|
||||||
@ -7631,22 +7625,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
/**
|
/**
|
||||||
* Update the controller's position.
|
* Update the controller's position.
|
||||||
*/
|
*/
|
||||||
public void updatePosition(int x, int y);
|
public void updatePosition(HandleView handle, int x, int y);
|
||||||
|
|
||||||
public void updatePosition();
|
public void updatePosition();
|
||||||
|
|
||||||
/**
|
|
||||||
* The controller and the cursor's positions can be link by a fixed offset,
|
|
||||||
* computed when the controller is touched, and then maintained as it moves
|
|
||||||
* @return Horizontal offset between the controller and the cursor.
|
|
||||||
*/
|
|
||||||
public float getOffsetX();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Vertical offset between the controller and the cursor.
|
|
||||||
*/
|
|
||||||
public float getOffsetY();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
|
* This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
|
||||||
* a chance to become active and/or visible.
|
* a chance to become active and/or visible.
|
||||||
@ -7670,6 +7652,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
mDrawable = handle;
|
mDrawable = handle;
|
||||||
mContainer = new PopupWindow(TextView.this.mContext, null,
|
mContainer = new PopupWindow(TextView.this.mContext, null,
|
||||||
com.android.internal.R.attr.textSelectHandleWindowStyle);
|
com.android.internal.R.attr.textSelectHandleWindowStyle);
|
||||||
|
mContainer.setSplitTouchEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -7768,7 +7751,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
TextView.this.getLocationOnScreen(coords);
|
TextView.this.getLocationOnScreen(coords);
|
||||||
final int x = (int) (rawX - coords[0] + 0.5f);
|
final int x = (int) (rawX - coords[0] + 0.5f);
|
||||||
final int y = (int) (rawY - coords[1] + 0.5f);
|
final int y = (int) (rawY - coords[1] + 0.5f);
|
||||||
mController.updatePosition(x, y);
|
mController.updatePosition(this, x, y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
@ -7802,13 +7785,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InsertionPointCursorController implements CursorController {
|
private class InsertionPointCursorController implements CursorController {
|
||||||
private static final int DELAY_BEFORE_FADE_OUT = 4100;
|
private static final int DELAY_BEFORE_FADE_OUT = 4100;
|
||||||
|
|
||||||
// The cursor controller image
|
// The cursor controller image
|
||||||
private final HandleView mHandle;
|
private final HandleView mHandle;
|
||||||
// Offset between finger hot point on cursor controller and actual cursor
|
|
||||||
private float mOffsetX, mOffsetY;
|
|
||||||
|
|
||||||
private final Runnable mHider = new Runnable() {
|
private final Runnable mHider = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -7841,7 +7822,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
return mHandle.isShowing();
|
return mHandle.isShowing();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePosition(int x, int y) {
|
public void updatePosition(HandleView handle, int x, int y) {
|
||||||
final int previousOffset = getSelectionStart();
|
final int previousOffset = getSelectionStart();
|
||||||
int offset = getHysteresisOffset(x, y, previousOffset);
|
int offset = getHysteresisOffset(x, y, previousOffset);
|
||||||
|
|
||||||
@ -7865,24 +7846,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
mHandle.positionAtCursor(offset, true);
|
mHandle.positionAtCursor(offset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getOffsetX() {
|
|
||||||
return mOffsetX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getOffsetY() {
|
|
||||||
return mOffsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectionModifierCursorController implements CursorController {
|
private class SelectionModifierCursorController implements CursorController {
|
||||||
// The cursor controller images
|
// The cursor controller images
|
||||||
private HandleView mStartHandle, mEndHandle;
|
private HandleView mStartHandle, mEndHandle;
|
||||||
// Offset between finger hot point on active cursor controller and actual cursor
|
|
||||||
private float mOffsetX, mOffsetY;
|
|
||||||
// The offsets of that last touch down event. Remembered to start selection there.
|
// The offsets of that last touch down event. Remembered to start selection there.
|
||||||
private int mMinTouchOffset, mMaxTouchOffset;
|
private int mMinTouchOffset, mMaxTouchOffset;
|
||||||
// Whether selection anchors are active
|
// Whether selection anchors are active
|
||||||
@ -7916,15 +7887,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePosition(int x, int y) {
|
public void updatePosition(HandleView handle, int x, int y) {
|
||||||
int selectionStart = getSelectionStart();
|
int selectionStart = getSelectionStart();
|
||||||
int selectionEnd = getSelectionEnd();
|
int selectionEnd = getSelectionEnd();
|
||||||
|
|
||||||
final int previousOffset = mStartHandle.isDragging() ? selectionStart : selectionEnd;
|
final int previousOffset = handle == mStartHandle ? selectionStart : selectionEnd;
|
||||||
int offset = getHysteresisOffset(x, y, previousOffset);
|
int offset = getHysteresisOffset(x, y, previousOffset);
|
||||||
|
|
||||||
// Handle the case where start and end are swapped, making sure start <= end
|
// Handle the case where start and end are swapped, making sure start <= end
|
||||||
if (mStartHandle.isDragging()) {
|
if (handle == mStartHandle) {
|
||||||
if (offset <= selectionEnd) {
|
if (offset <= selectionEnd) {
|
||||||
if (selectionStart == offset) {
|
if (selectionStart == offset) {
|
||||||
return; // no change, no need to redraw;
|
return; // no change, no need to redraw;
|
||||||
@ -8021,14 +7992,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
return mMaxTouchOffset;
|
return mMaxTouchOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getOffsetX() {
|
|
||||||
return mOffsetX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getOffsetY() {
|
|
||||||
return mOffsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true iff this controller is currently used to move the selection start.
|
* @return true iff this controller is currently used to move the selection start.
|
||||||
*/
|
*/
|
||||||
|
@ -40,9 +40,17 @@ enum {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum number of pointers supported per motion event.
|
* Maximum number of pointers supported per motion event.
|
||||||
|
* Smallest number of pointers is 1.
|
||||||
*/
|
*/
|
||||||
#define MAX_POINTERS 10
|
#define MAX_POINTERS 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum pointer id value supported in a motion event.
|
||||||
|
* Smallest pointer id is 0.
|
||||||
|
* (This is limited by our use of BitSet32 to track pointer assignments.)
|
||||||
|
*/
|
||||||
|
#define MAX_POINTER_ID 31
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Declare a concrete type for the NDK's input event forward declaration.
|
* Declare a concrete type for the NDK's input event forward declaration.
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
#include <utils/Looper.h>
|
#include <utils/Looper.h>
|
||||||
#include <utils/Pool.h>
|
#include <utils/Pool.h>
|
||||||
|
#include <utils/BitSet.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -89,17 +90,13 @@ struct InputTarget {
|
|||||||
* AMOTION_EVENT_ACTION_OUTSIDE to this target. */
|
* AMOTION_EVENT_ACTION_OUTSIDE to this target. */
|
||||||
FLAG_OUTSIDE = 0x02,
|
FLAG_OUTSIDE = 0x02,
|
||||||
|
|
||||||
/* This flag indicates that a KeyEvent or MotionEvent is being canceled.
|
|
||||||
* In the case of a key event, it should be delivered with flag
|
|
||||||
* AKEY_EVENT_FLAG_CANCELED set.
|
|
||||||
* In the case of a motion event, it should be delivered with action
|
|
||||||
* AMOTION_EVENT_ACTION_CANCEL instead. */
|
|
||||||
FLAG_CANCEL = 0x04,
|
|
||||||
|
|
||||||
/* This flag indicates that the target of a MotionEvent is partly or wholly
|
/* This flag indicates that the target of a MotionEvent is partly or wholly
|
||||||
* obscured by another visible window above it. The motion event should be
|
* obscured by another visible window above it. The motion event should be
|
||||||
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
|
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
|
||||||
FLAG_WINDOW_IS_OBSCURED = 0x08,
|
FLAG_WINDOW_IS_OBSCURED = 0x04,
|
||||||
|
|
||||||
|
/* This flag indicates that a motion event is being split across multiple windows. */
|
||||||
|
FLAG_SPLIT = 0x08,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The input channel to be targeted.
|
// The input channel to be targeted.
|
||||||
@ -111,6 +108,13 @@ struct InputTarget {
|
|||||||
// The x and y offset to add to a MotionEvent as it is delivered.
|
// The x and y offset to add to a MotionEvent as it is delivered.
|
||||||
// (ignored for KeyEvents)
|
// (ignored for KeyEvents)
|
||||||
float xOffset, yOffset;
|
float xOffset, yOffset;
|
||||||
|
|
||||||
|
// The window type of the input target.
|
||||||
|
int32_t windowType;
|
||||||
|
|
||||||
|
// The subset of pointer ids to include in motion events dispatched to this input target
|
||||||
|
// if FLAG_SPLIT is set.
|
||||||
|
BitSet32 pointerIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -143,7 +147,7 @@ struct InputWindow {
|
|||||||
FLAG_SHOW_WALLPAPER = 0x00100000,
|
FLAG_SHOW_WALLPAPER = 0x00100000,
|
||||||
FLAG_TURN_SCREEN_ON = 0x00200000,
|
FLAG_TURN_SCREEN_ON = 0x00200000,
|
||||||
FLAG_DISMISS_KEYGUARD = 0x00400000,
|
FLAG_DISMISS_KEYGUARD = 0x00400000,
|
||||||
FLAG_IMMERSIVE = 0x00800000,
|
FLAG_SPLIT_TOUCH = 0x00800000,
|
||||||
FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
|
FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
|
||||||
FLAG_COMPATIBLE_WINDOW = 0x20000000,
|
FLAG_COMPATIBLE_WINDOW = 0x20000000,
|
||||||
FLAG_SYSTEM_ERROR = 0x40000000,
|
FLAG_SYSTEM_ERROR = 0x40000000,
|
||||||
@ -276,7 +280,7 @@ public:
|
|||||||
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
|
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
|
||||||
|
|
||||||
/* Poke user activity for an event dispatched to a window. */
|
/* Poke user activity for an event dispatched to a window. */
|
||||||
virtual void pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) = 0;
|
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
|
||||||
|
|
||||||
/* Checks whether a given application pid/uid has permission to inject input events
|
/* Checks whether a given application pid/uid has permission to inject input events
|
||||||
* into other applications.
|
* into other applications.
|
||||||
@ -415,6 +419,16 @@ private:
|
|||||||
T* prev;
|
T* prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct InjectionState {
|
||||||
|
mutable int32_t refCount;
|
||||||
|
|
||||||
|
int32_t injectorPid;
|
||||||
|
int32_t injectorUid;
|
||||||
|
int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
|
||||||
|
bool injectionIsAsync; // set to true if injection is not waiting for the result
|
||||||
|
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
|
||||||
|
};
|
||||||
|
|
||||||
struct EventEntry : Link<EventEntry> {
|
struct EventEntry : Link<EventEntry> {
|
||||||
enum {
|
enum {
|
||||||
TYPE_SENTINEL,
|
TYPE_SENTINEL,
|
||||||
@ -423,21 +437,14 @@ private:
|
|||||||
TYPE_MOTION
|
TYPE_MOTION
|
||||||
};
|
};
|
||||||
|
|
||||||
int32_t refCount;
|
mutable int32_t refCount;
|
||||||
int32_t type;
|
int32_t type;
|
||||||
nsecs_t eventTime;
|
nsecs_t eventTime;
|
||||||
|
InjectionState* injectionState;
|
||||||
int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING
|
|
||||||
bool injectionIsAsync; // set to true if injection is not waiting for the result
|
|
||||||
int32_t injectorPid; // -1 if not injected
|
|
||||||
int32_t injectorUid; // -1 if not injected
|
|
||||||
|
|
||||||
bool dispatchInProgress; // initially false, set to true while dispatching
|
bool dispatchInProgress; // initially false, set to true while dispatching
|
||||||
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
|
|
||||||
|
|
||||||
inline bool isInjected() { return injectorPid >= 0; }
|
inline bool isInjected() { return injectionState != NULL; }
|
||||||
|
|
||||||
void recycle();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConfigurationChangedEntry : EventEntry {
|
struct ConfigurationChangedEntry : EventEntry {
|
||||||
@ -463,8 +470,6 @@ private:
|
|||||||
INTERCEPT_KEY_RESULT_CONTINUE,
|
INTERCEPT_KEY_RESULT_CONTINUE,
|
||||||
};
|
};
|
||||||
InterceptKeyResult interceptKeyResult; // set based on the interception result
|
InterceptKeyResult interceptKeyResult; // set based on the interception result
|
||||||
|
|
||||||
void recycle();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MotionSample {
|
struct MotionSample {
|
||||||
@ -521,6 +526,10 @@ private:
|
|||||||
inline bool hasForegroundTarget() const {
|
inline bool hasForegroundTarget() const {
|
||||||
return targetFlags & InputTarget::FLAG_FOREGROUND;
|
return targetFlags & InputTarget::FLAG_FOREGROUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isSplit() const {
|
||||||
|
return targetFlags & InputTarget::FLAG_SPLIT;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A command entry captures state and behavior for an action to be performed in the
|
// A command entry captures state and behavior for an action to be performed in the
|
||||||
@ -555,7 +564,6 @@ private:
|
|||||||
KeyEntry* keyEntry;
|
KeyEntry* keyEntry;
|
||||||
sp<InputChannel> inputChannel;
|
sp<InputChannel> inputChannel;
|
||||||
sp<InputApplicationHandle> inputApplicationHandle;
|
sp<InputApplicationHandle> inputApplicationHandle;
|
||||||
int32_t windowType;
|
|
||||||
int32_t userActivityEventType;
|
int32_t userActivityEventType;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -611,6 +619,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
Allocator();
|
Allocator();
|
||||||
|
|
||||||
|
InjectionState* obtainInjectionState(int32_t injectorPid, int32_t injectorUid);
|
||||||
ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime);
|
ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime);
|
||||||
KeyEntry* obtainKeyEntry(nsecs_t eventTime,
|
KeyEntry* obtainKeyEntry(nsecs_t eventTime,
|
||||||
int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
|
int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
|
||||||
@ -626,6 +635,7 @@ private:
|
|||||||
int32_t targetFlags, float xOffset, float yOffset);
|
int32_t targetFlags, float xOffset, float yOffset);
|
||||||
CommandEntry* obtainCommandEntry(Command command);
|
CommandEntry* obtainCommandEntry(Command command);
|
||||||
|
|
||||||
|
void releaseInjectionState(InjectionState* injectionState);
|
||||||
void releaseEventEntry(EventEntry* entry);
|
void releaseEventEntry(EventEntry* entry);
|
||||||
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
|
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
|
||||||
void releaseKeyEntry(KeyEntry* entry);
|
void releaseKeyEntry(KeyEntry* entry);
|
||||||
@ -633,10 +643,13 @@ private:
|
|||||||
void releaseDispatchEntry(DispatchEntry* entry);
|
void releaseDispatchEntry(DispatchEntry* entry);
|
||||||
void releaseCommandEntry(CommandEntry* entry);
|
void releaseCommandEntry(CommandEntry* entry);
|
||||||
|
|
||||||
|
void recycleKeyEntry(KeyEntry* entry);
|
||||||
|
|
||||||
void appendMotionSample(MotionEntry* motionEntry,
|
void appendMotionSample(MotionEntry* motionEntry,
|
||||||
nsecs_t eventTime, const PointerCoords* pointerCoords);
|
nsecs_t eventTime, const PointerCoords* pointerCoords);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Pool<InjectionState> mInjectionStatePool;
|
||||||
Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
|
Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
|
||||||
Pool<KeyEntry> mKeyEntryPool;
|
Pool<KeyEntry> mKeyEntryPool;
|
||||||
Pool<MotionEntry> mMotionEntryPool;
|
Pool<MotionEntry> mMotionEntryPool;
|
||||||
@ -645,6 +658,7 @@ private:
|
|||||||
Pool<CommandEntry> mCommandEntryPool;
|
Pool<CommandEntry> mCommandEntryPool;
|
||||||
|
|
||||||
void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
|
void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
|
||||||
|
void releaseEventEntryInjectionState(EventEntry* entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Tracks dispatched key and motion event state so that cancelation events can be
|
/* Tracks dispatched key and motion event state so that cancelation events can be
|
||||||
@ -823,6 +837,7 @@ private:
|
|||||||
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
|
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
|
||||||
|
|
||||||
Condition mInjectionSyncFinishedCondition;
|
Condition mInjectionSyncFinishedCondition;
|
||||||
|
void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
|
||||||
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
|
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
|
||||||
|
|
||||||
// Throttling state.
|
// Throttling state.
|
||||||
@ -858,23 +873,37 @@ private:
|
|||||||
// Dispatch state.
|
// Dispatch state.
|
||||||
bool mDispatchEnabled;
|
bool mDispatchEnabled;
|
||||||
bool mDispatchFrozen;
|
bool mDispatchFrozen;
|
||||||
|
|
||||||
Vector<InputWindow> mWindows;
|
Vector<InputWindow> mWindows;
|
||||||
Vector<InputWindow*> mWallpaperWindows;
|
|
||||||
|
const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel);
|
||||||
|
|
||||||
// Focus tracking for keys, trackball, etc.
|
// Focus tracking for keys, trackball, etc.
|
||||||
InputWindow* mFocusedWindow;
|
const InputWindow* mFocusedWindow;
|
||||||
|
|
||||||
// Focus tracking for touch.
|
// Focus tracking for touch.
|
||||||
bool mTouchDown;
|
struct TouchedWindow {
|
||||||
InputWindow* mTouchedWindow; // primary target for current down
|
const InputWindow* window;
|
||||||
bool mTouchedWindowIsObscured; // true if other windows may obscure the target
|
int32_t targetFlags;
|
||||||
Vector<InputWindow*> mTouchedWallpaperWindows; // wallpaper targets
|
BitSet32 pointerIds;
|
||||||
struct OutsideTarget {
|
sp<InputChannel> channel;
|
||||||
InputWindow* window;
|
|
||||||
bool obscured;
|
|
||||||
};
|
};
|
||||||
Vector<OutsideTarget> mTempTouchedOutsideTargets; // temporary outside touch targets
|
struct TouchState {
|
||||||
Vector<sp<InputChannel> > mTempTouchedWallpaperChannels; // temporary wallpaper targets
|
bool down;
|
||||||
|
bool split;
|
||||||
|
Vector<TouchedWindow> windows;
|
||||||
|
|
||||||
|
TouchState();
|
||||||
|
~TouchState();
|
||||||
|
void reset();
|
||||||
|
void copyFrom(const TouchState& other);
|
||||||
|
void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
|
||||||
|
void removeOutsideTouchWindows();
|
||||||
|
const InputWindow* getFirstForegroundWindow();
|
||||||
|
};
|
||||||
|
|
||||||
|
TouchState mTouchState;
|
||||||
|
TouchState mTempTouchState;
|
||||||
|
|
||||||
// Focused application.
|
// Focused application.
|
||||||
InputApplication* mFocusedApplication;
|
InputApplication* mFocusedApplication;
|
||||||
@ -899,8 +928,6 @@ private:
|
|||||||
// The input targets that were most recently identified for dispatch.
|
// The input targets that were most recently identified for dispatch.
|
||||||
bool mCurrentInputTargetsValid; // false while targets are being recomputed
|
bool mCurrentInputTargetsValid; // false while targets are being recomputed
|
||||||
Vector<InputTarget> mCurrentInputTargets;
|
Vector<InputTarget> mCurrentInputTargets;
|
||||||
int32_t mCurrentInputWindowType;
|
|
||||||
sp<InputChannel> mCurrentInputChannel;
|
|
||||||
|
|
||||||
enum InputTargetWaitCause {
|
enum InputTargetWaitCause {
|
||||||
INPUT_TARGET_WAIT_CAUSE_NONE,
|
INPUT_TARGET_WAIT_CAUSE_NONE,
|
||||||
@ -915,7 +942,7 @@ private:
|
|||||||
|
|
||||||
// Finding targets for input events.
|
// Finding targets for input events.
|
||||||
void resetTargetsLocked();
|
void resetTargetsLocked();
|
||||||
void commitTargetsLocked(const InputWindow* window);
|
void commitTargetsLocked();
|
||||||
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
|
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
|
||||||
const InputApplication* application, const InputWindow* window,
|
const InputApplication* application, const InputWindow* window,
|
||||||
nsecs_t* nextWakeupTime);
|
nsecs_t* nextWakeupTime);
|
||||||
@ -924,19 +951,19 @@ private:
|
|||||||
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
|
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
|
||||||
void resetANRTimeoutsLocked();
|
void resetANRTimeoutsLocked();
|
||||||
|
|
||||||
int32_t findFocusedWindowLocked(nsecs_t currentTime, const EventEntry* entry,
|
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
|
||||||
nsecs_t* nextWakeupTime, InputWindow** outWindow);
|
nsecs_t* nextWakeupTime);
|
||||||
int32_t findTouchedWindowLocked(nsecs_t currentTime, const MotionEntry* entry,
|
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
|
||||||
nsecs_t* nextWakeupTime, InputWindow** outWindow);
|
nsecs_t* nextWakeupTime);
|
||||||
|
|
||||||
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags);
|
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
|
||||||
|
BitSet32 pointerIds);
|
||||||
void addMonitoringTargetsLocked();
|
void addMonitoringTargetsLocked();
|
||||||
void pokeUserActivityLocked(nsecs_t eventTime, int32_t windowType, int32_t eventType);
|
bool shouldPokeUserActivityForCurrentInputTargetsLocked();
|
||||||
bool checkInjectionPermission(const InputWindow* window,
|
void pokeUserActivityLocked(nsecs_t eventTime, int32_t eventType);
|
||||||
int32_t injectorPid, int32_t injectorUid);
|
bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
|
||||||
bool isWindowObscuredLocked(const InputWindow* window);
|
bool isWindowObscuredLocked(const InputWindow* window);
|
||||||
bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
|
bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
|
||||||
void releaseTouchedWindowLocked();
|
|
||||||
String8 getApplicationWindowLabelLocked(const InputApplication* application,
|
String8 getApplicationWindowLabelLocked(const InputApplication* application,
|
||||||
const InputWindow* window);
|
const InputWindow* window);
|
||||||
|
|
||||||
@ -955,6 +982,9 @@ private:
|
|||||||
void drainOutboundQueueLocked(Connection* connection);
|
void drainOutboundQueueLocked(Connection* connection);
|
||||||
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
static int handleReceiveCallback(int receiveFd, int events, void* data);
|
||||||
|
|
||||||
|
// Splitting motion events across windows.
|
||||||
|
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
|
||||||
|
|
||||||
// Dump state.
|
// Dump state.
|
||||||
void dumpDispatchStateLocked(String8& dump);
|
void dumpDispatchStateLocked(String8& dump);
|
||||||
void logDispatchStateLocked();
|
void logDispatchStateLocked();
|
||||||
|
@ -549,10 +549,6 @@ public:
|
|||||||
const int32_t* keyCodes, uint8_t* outFlags);
|
const int32_t* keyCodes, uint8_t* outFlags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Maximum pointer id value supported.
|
|
||||||
* (This is limited by our use of BitSet32 to track pointer assignments.) */
|
|
||||||
static const uint32_t MAX_POINTER_ID = 31;
|
|
||||||
|
|
||||||
Mutex mLock;
|
Mutex mLock;
|
||||||
|
|
||||||
struct VirtualKey {
|
struct VirtualKey {
|
||||||
|
@ -38,6 +38,9 @@ struct BitSet32 {
|
|||||||
// Clears the bit set.
|
// Clears the bit set.
|
||||||
inline void clear() { value = 0; }
|
inline void clear() { value = 0; }
|
||||||
|
|
||||||
|
// Returns the number of marked bits in the set.
|
||||||
|
inline uint32_t count() const { return __builtin_popcount(value); }
|
||||||
|
|
||||||
// Returns true if the bit set does not contain any marked bits.
|
// Returns true if the bit set does not contain any marked bits.
|
||||||
inline bool isEmpty() const { return ! value; }
|
inline bool isEmpty() const { return ! value; }
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -3366,7 +3366,7 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
|
|||||||
if (id > MAX_POINTER_ID) {
|
if (id > MAX_POINTER_ID) {
|
||||||
#if DEBUG_POINTERS
|
#if DEBUG_POINTERS
|
||||||
LOGD("Pointers: Ignoring driver provided pointer id %d because "
|
LOGD("Pointers: Ignoring driver provided pointer id %d because "
|
||||||
"it is larger than max supported id %d for optimizations",
|
"it is larger than max supported id %d",
|
||||||
id, MAX_POINTER_ID);
|
id, MAX_POINTER_ID);
|
||||||
#endif
|
#endif
|
||||||
havePointerIds = false;
|
havePointerIds = false;
|
||||||
|
@ -207,7 +207,7 @@ public:
|
|||||||
virtual int32_t getMaxEventsPerSecond();
|
virtual int32_t getMaxEventsPerSecond();
|
||||||
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
|
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
|
||||||
const KeyEvent* keyEvent, uint32_t policyFlags);
|
const KeyEvent* keyEvent, uint32_t policyFlags);
|
||||||
virtual void pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType);
|
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
|
||||||
virtual bool checkInjectEventsPermissionNonReentrant(
|
virtual bool checkInjectEventsPermissionNonReentrant(
|
||||||
int32_t injectorPid, int32_t injectorUid);
|
int32_t injectorPid, int32_t injectorUid);
|
||||||
|
|
||||||
@ -973,11 +973,9 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
|
|||||||
return consumed && ! error;
|
return consumed && ! error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t windowType, int32_t eventType) {
|
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
|
||||||
if (windowType != InputWindow::TYPE_KEYGUARD) {
|
|
||||||
android_server_PowerManagerService_userActivity(eventTime, eventType);
|
android_server_PowerManagerService_userActivity(eventTime, eventType);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
|
bool NativeInputManager::checkInjectEventsPermissionNonReentrant(
|
||||||
|
Reference in New Issue
Block a user