For archiving in this thread, here is the patch that we have done at
Always Innovating. It works great on Gingerbread.
From a721f7e2ab6e680257cc9cb5ecaee6238e615ff2 Mon Sep 17 00:00:00 2001
From: Gregoire Gentil <gregoire@gregoire-laptop.(none)>
Date: Tue, 15 Mar 2011 22:00:26 +0000
Subject: Adding support of cursor on Gingerbread
---
diff --git a/preprocess/gingerbread/patches/cursor.patch b/preprocess/
gingerbread/patches/cursor.patch
new file mode 100644
index 0000000..09c2673
--- a/dev/null
+++ b/preprocess/gingerbread/patches/cursor.patch
@@ -0,0 +1,518 @@
+--- a/frameworks/base/libs/ui/EventHub.cpp 2011-02-23
18:28:26.856910001 -0800
++++ b/frameworks/base/libs/ui/EventHub.cpp 2011-02-23
18:30:09.006909999 -0800
+@@ -719,7 +719,10 @@
+ LOGV("Getting relative controllers...");
+ if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)),
rel_bitmask) >= 0) {
+ if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y,
rel_bitmask)) {
+- device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
++ if (test_bit(BTN_LEFT, key_bitmask) &&
test_bit(BTN_RIGHT, key_bitmask))
++ device->classes |= INPUT_DEVICE_CLASS_MOUSE;
++ else
++ device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
+ }
+ }
+ }
+--- a/frameworks/base/include/ui/EventHub.h 2011-02-23
18:28:18.846910002 -0800
++++ b/frameworks/base/include/ui/EventHub.h 2011-02-25
19:27:08.626910002 -0800
+@@ -119,6 +119,9 @@
+
+ /* The input device has switches. */
+ INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
++
++ /* The input device is a mouse. */
++ INPUT_DEVICE_CLASS_MOUSE = 0x00000100,
+ };
+
+ /*
+--- a/frameworks/base/libs/ui/InputReader.cpp 2011-02-23
18:43:07.506909997 -0800
++++ b/frameworks/base/libs/ui/InputReader.cpp 2011-02-28
19:12:15.754663005 -0800
+@@ -340,6 +340,11 @@
+ device->addMapper(new TrackballInputMapper(device,
associatedDisplayId));
+ }
+
++ // Mouse-like devices.
++ if (classes & INPUT_DEVICE_CLASS_MOUSE) {
++ device->addMapper(new MouseInputMapper(device,
associatedDisplayId));
++ }
++
+ // Touchscreen-like devices.
+ if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
+ device->addMapper(new MultiTouchInputMapper(device,
associatedDisplayId));
+@@ -3128,6 +3133,207 @@
+ }
+
+
++// --- MouseInputMapper ---
++
++MouseInputMapper::MouseInputMapper(InputDevice* device, int32_t
associatedDisplayId) :
++ InputMapper(device),
mAssociatedDisplayId(associatedDisplayId) {
++ initializeLocked();
++}
++
++MouseInputMapper::~MouseInputMapper() {
++}
++
++uint32_t MouseInputMapper::getSources() {
++ return AINPUT_SOURCE_MOUSE;
++}
++
++void MouseInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
++ InputMapper::populateDeviceInfo(info);
++}
++
++void MouseInputMapper::dump(String8& dump) {
++ { // acquire lock
++ AutoMutex _l(mLock);
++ dump.append(INDENT2 "Mouse Input Mapper:\n");
++ dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n",
mAssociatedDisplayId);
++ dump.appendFormat(INDENT3 "Down: %s\n",
toString(mLocked.down));
++ dump.appendFormat(INDENT3 "DownTime: %lld\n",
mLocked.downTime);
++ } // release lock
++}
++
++void MouseInputMapper::initializeLocked() {
++ mAccumulator.clear();
++
++ mLocked.down = false;
++ mLocked.downTime = 0;
++
++ int32_t screenWidth;
++ int32_t screenHeight;
++ if (mAssociatedDisplayId < 0 || ! getPolicy()-
>getDisplayInfo(mAssociatedDisplayId, &screenWidth, &screenHeight,
NULL)) {
++ mAccumulator.absX = 0;
++ mAccumulator.absY = 0;
++ }else{
++ mAccumulator.absX = screenWidth/2;
++ mAccumulator.absY = screenHeight/2;
++ }
++}
++
++void MouseInputMapper::reset() {
++ for (;;) {
++ { // acquire lock
++ AutoMutex _l(mLock);
++
++ if (! mLocked.down) {
++ initializeLocked();
++ break; // done
++ }
++ } // release lock
++
++ // Synthesize trackball button up event on reset.
++ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
++ mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
++ mAccumulator.btnMouse = false;
++ sync(when);
++ }
++
++ InputMapper::reset();
++}
++
++void MouseInputMapper::process(const RawEvent* rawEvent) {
++ switch (rawEvent->type) {
++ case EV_KEY:
++ switch (rawEvent->scanCode) {
++ case BTN_MOUSE:
++ mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
++ mAccumulator.btnMouse = rawEvent->value != 0;
++ sync(rawEvent->when);
++ break;
++ case BTN_RIGHT:
++ // Not handled.
++ break;
++ case BTN_MIDDLE:
++ // Not handled.
++ break;
++ }
++ break;
++
++ case EV_REL:
++ switch (rawEvent->scanCode) {
++ case REL_X:
++ mAccumulator.fields |= Accumulator::FIELD_REL_X;
++ mAccumulator.relX = rawEvent->value;
++ break;
++ case REL_Y:
++ mAccumulator.fields |= Accumulator::FIELD_REL_Y;
++ mAccumulator.relY = rawEvent->value;
++ break;
++ }
++ break;
++
++ case EV_SYN:
++ switch (rawEvent->scanCode) {
++ case SYN_REPORT:
++ sync(rawEvent->when);
++ break;
++ }
++ break;
++ }
++}
++
++void MouseInputMapper::sync(nsecs_t when) {
++ uint32_t fields = mAccumulator.fields;
++ if (fields == 0) {
++ return; // no new state changes, so nothing to do
++ }
++
++ int motionEventAction;
++ PointerCoords pointerCoords;
++ nsecs_t downTime;
++ { // acquire lock
++ AutoMutex _l(mLock);
++
++ bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
++ if (downChanged) {
++ if (mAccumulator.btnMouse) {
++ mLocked.down = true;
++ mLocked.downTime = when;
++ } else {
++ mLocked.down = false;
++ }
++ motionEventAction = mLocked.down ?
AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
++ } else {
++ motionEventAction = AMOTION_EVENT_ACTION_MOVE;
++ }
++
++ downTime = mLocked.downTime;
++
++ float x = fields & Accumulator::FIELD_REL_X ?
mAccumulator.relX : 0.0f;
++ float y = fields & Accumulator::FIELD_REL_Y ?
mAccumulator.relY : 0.0f;
++
++ int32_t screenWidth;
++ int32_t screenHeight;
++ int32_t orientation;
++ if (mAssociatedDisplayId < 0 || ! getPolicy()-
>getDisplayInfo(mAssociatedDisplayId, &screenWidth, &screenHeight,
&orientation)) {
++ return;
++ }
++
++ float temp;
++ switch (orientation) {
++ case InputReaderPolicyInterface::ROTATION_90:
++ temp = x;
++ x = y;
++ y = - temp;
++ temp = screenHeight;
++ screenHeight = screenWidth;
++ screenWidth = temp;
++ break;
++
++ case InputReaderPolicyInterface::ROTATION_180:
++ x = - x;
++ y = - y;
++ break;
++
++ case InputReaderPolicyInterface::ROTATION_270:
++ temp = x;
++ x = - y;
++ y = temp;
++ temp = screenHeight;
++ screenHeight = screenWidth;
++ screenWidth = temp;
++ break;
++ }
++
++ mAccumulator.absX = (mAccumulator.absX + x) > screenWidth ?
screenWidth -1 : ((mAccumulator.absX + x) < 0 ? 0 : mAccumulator.absX
+ x);
++ mAccumulator.absY = (mAccumulator.absY + y) > screenHeight ?
screenHeight -1 : ((mAccumulator.absY + y) < 0 ? 0 : mAccumulator.absY
+ y);
++ pointerCoords.x = mAccumulator.absX;
++ pointerCoords.y = mAccumulator.absY;
++ pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f;
++ pointerCoords.size = 0;
++ pointerCoords.touchMajor = 0;
++ pointerCoords.touchMinor = 0;
++ pointerCoords.toolMajor = 0;
++ pointerCoords.toolMinor = 0;
++ pointerCoords.orientation = 0;
++
++ } // release lock
++
++ int32_t metaState = mContext->getGlobalMetaState();
++ int32_t pointerId = 0;
++ getDispatcher()->notifyMotion(when, getDeviceId(),
AINPUT_SOURCE_MOUSE, 0,
++ motionEventAction, 0, metaState,
AMOTION_EVENT_EDGE_FLAG_NONE,
++ 1, &pointerId, &pointerCoords, 1, 1, downTime);
++ mAccumulator.clear();
++}
++
++int32_t MouseInputMapper::getScanCodeState(uint32_t sourceMask,
int32_t scanCode) {
++ if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) {
++ return getEventHub()->getScanCodeState(getDeviceId(),
scanCode);
++ } else {
++ return AKEY_STATE_UNKNOWN;
++ }
++}
++
++
+ // --- SingleTouchInputMapper ---
+
+ SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device,
int32_t associatedDisplayId) :
+--- a/frameworks/base/include/ui/InputReader.h 2011-02-23
18:52:36.096910001 -0800
++++ b/frameworks/base/include/ui/InputReader.h 2011-02-28
13:00:02.434663005 -0800
+@@ -489,6 +489,53 @@
+ void sync(nsecs_t when);
+ };
+
++class MouseInputMapper : public InputMapper {
++public:
++ MouseInputMapper(InputDevice* device, int32_t
associatedDisplayId);
++ virtual ~MouseInputMapper();
++
++ virtual uint32_t getSources();
++ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
++ virtual void dump(String8& dump);
++ virtual void reset();
++ virtual void process(const RawEvent* rawEvent);
++
++ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t
scanCode);
++
++private:
++ Mutex mLock;
++
++ int32_t mAssociatedDisplayId;
++
++ struct Accumulator {
++ enum {
++ FIELD_BTN_MOUSE = 1,
++ FIELD_REL_X = 2,
++ FIELD_REL_Y = 4,
++ };
++
++ uint32_t fields;
++
++ bool btnMouse;
++ int32_t relX;
++ int32_t relY;
++ int32_t absX;
++ int32_t absY;
++
++ inline void clear() {
++ fields = 0;
++ }
++ } mAccumulator;
++
++ struct LockedState {
++ bool down;
++ nsecs_t downTime;
++ } mLocked;
++
++ void initializeLocked();
++
++ void sync(nsecs_t when);
++};
+
+ class TouchInputMapper : public InputMapper {
+ public:
+--- a/frameworks/base/libs/ui/InputDispatcher.cpp 2011-02-24
14:02:25.786910001 -0800
++++ b/frameworks/base/libs/ui/InputDispatcher.cpp 2011-02-28
18:03:27.134662999 -0800
+@@ -731,17 +731,19 @@
+ return true;
+ }
+
+- bool isPointerEvent = entry->source &
AINPUT_SOURCE_CLASS_POINTER;
++ bool isTouchEvent = ! ((entry->source &
AINPUT_SOURCE_TOUCHSCREEN) ^ AINPUT_SOURCE_TOUCHSCREEN);
++ bool isMouseEvent = ! ((entry->source & AINPUT_SOURCE_MOUSE) ^
AINPUT_SOURCE_MOUSE);
++ bool isDownEvent = (entry->action & AMOTION_EVENT_ACTION_MASK)
== AMOTION_EVENT_ACTION_DOWN;
+
+ // Identify targets.
+ if (! mCurrentInputTargetsValid) {
+ int32_t injectionResult;
+- if (isPointerEvent) {
+- // Pointer event. (eg. touchscreen)
++ if (isTouchEvent || (isMouseEvent && (isDownEvent ||
mTouchState.down))) {
++ // Touch-like event. (eg. touchscreen or mouse drag-n-
drop )
+ injectionResult =
findTouchedWindowTargetsLocked(currentTime,
+ entry, nextWakeupTime);
+ } else {
+- // Non touch event. (eg. trackball)
++ // Non touch event. (eg. trackball or mouse simple
move)
+ injectionResult =
findFocusedWindowTargetsLocked(currentTime,
+ entry, nextWakeupTime);
+ }
+--- a/frameworks/base/core/java/android/view/ViewRoot.java 2011-02-23
11:33:20.516910002 -0800
++++ b/frameworks/base/core/java/android/view/ViewRoot.java 2011-02-28
18:16:23.994663005 -0800
+@@ -215,6 +215,8 @@
+
+ final ViewConfiguration mViewConfiguration;
+
++ static IWindowManager wm;
++
+ /**
+ * see {@link #playSoundEffect(int)}
+ */
+@@ -227,9 +229,8 @@
+ if (!mInitialized) {
+ try {
+ InputMethodManager imm =
InputMethodManager.getInstance(mainLooper);
+- sWindowSession =
IWindowManager.Stub.asInterface(
+- ServiceManager.getService("window"))
+- .openSession(imm.getClient(),
imm.getInputContext());
++ wm =
IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
++ sWindowSession = wm.openSession(imm.getClient(),
imm.getInputContext());
+ mInitialized = true;
+ } catch (RemoteException e) {
+ }
+@@ -2174,6 +2175,7 @@
+ mTranslator.translateEventInScreenToAppWindow(event);
+ }
+
++ boolean isMouse = ((event.getSource() &
InputDevice.SOURCE_MOUSE) ^ InputDevice.SOURCE_MOUSE) == 0;
+ boolean handled;
+ if (mView != null && mAdded) {
+
+@@ -2837,7 +2839,15 @@
+
+ private void dispatchMotion(MotionEvent event, boolean sendDone)
{
+ int source = event.getSource();
+- if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
++ if (((source & InputDevice.SOURCE_MOUSE) ^
InputDevice.SOURCE_MOUSE) == 0) {
++ try{
++ wm.moveMouseSurface((int)event.getX() -
(int)event.getXOffset(),
++ (int)event.getY() -
(int)event.getYOffset());
++ }catch (RemoteException e){
++ Log.e(TAG,"RemoteException thrown in
moveMouseSurface");
++ }
++ dispatchPointer(event, sendDone);
++ }else if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0)
{
+ dispatchPointer(event, sendDone);
+ } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) !=
0) {
+ dispatchTrackball(event, sendDone);
+--- a/frameworks/base/services/java/com/android/server/
WindowManagerService.java 2011-02-28 18:24:48.934663006 -0800
++++ b/frameworks/base/services/java/com/android/server/
WindowManagerService.java 2011-02-28 18:38:17.594662998 -0800
+@@ -60,6 +60,7 @@
+ import android.graphics.Canvas;
+ import android.graphics.Matrix;
+ import android.graphics.Paint;
++import android.graphics.Path;
+ import android.graphics.PixelFormat;
+ import android.graphics.Rect;
+ import android.graphics.Region;
+@@ -372,6 +373,13 @@
+ boolean mBlurShown;
+ Watermark mWatermark;
+
++ Surface mMouseSurface;
++ int mShowMouse = 0;
++ private int mMlx;
++ private int mMly;
++ int mMlw;
++ int mMlh;
++
+ int mTransactionSequence = 0;
+
+ final float[] mTmpFloats = new float[9];
+@@ -5400,6 +5408,31 @@
+ }
+ }
+
++ public boolean moveMouseSurface(int x, int y){
++ if (mMouseSurface != null && (x != 0 || y != 0)) {
++ synchronized(mWindowMap) {
++ Surface.openTransaction();
++ WindowState top =
++ (WindowState)mWindows.get(mWindows.size() - 1);
++ try {
++ int mDisplayWidth = mDisplay.getWidth();
++ mMlx = x;
++ mMly = y;
++ mMouseSurface.setPosition(mMlx, mMly);
++ mMouseSurface.setLayer(top.mAnimLayer + 1);
++ if (mShowMouse != 1) {
++ mMouseSurface.show();
++ mShowMouse = 1;
++ }
++ } catch ( RuntimeException e) {
++ Slog.e(TAG, "Failure showing mouse surface",e);
++ }
++ Surface.closeTransaction();
++ }
++ }
++ return true;
++ }
++
+ /**
+ * Injects a keystroke event into the UI.
+ * Even when sync is false, this method may block while waiting
for current
+@@ -8487,6 +8520,54 @@
+ createWatermark = true;
+ }
+
++ if (mMouseSurface == null) {
++ int mMx, mMy, mMw, mMh;
++ Canvas mCanvas;
++ Path mPath = new Path();
++ mMw = 12;
++ mMh = 20;
++ mMx = (mDisplay.getWidth() - mMw) / 2;
++ mMy = (mDisplay.getHeight() - mMh) / 2;
++ try {
++ /*
++ *First Mouse event, create Surface
++ */
++ mMouseSurface =
++ new Surface(mFxSession,
++ 0, -1, mMw, mMh,
++ PixelFormat.TRANSPARENT,
++ Surface.FX_SURFACE_NORMAL);
++ mCanvas = mMouseSurface.lockCanvas(null);
++ Paint tPaint = new Paint();
++ tPaint.setStyle(Paint.Style.STROKE);
++ tPaint.setStrokeWidth(2);
++ tPaint.setColor(0xffffffff);
++ mPath.moveTo(0.0f, 0.0f);
++ mPath.lineTo(12.0f, 12.0f);
++ mPath.lineTo(7.0f, 12.0f);
++ mPath.lineTo(11.0f, 20.0f);
++ mPath.lineTo(8.0f, 21.0f);
++ mPath.lineTo(4.0f, 13.0f);
++ mPath.lineTo(0.0f, 17.0f);
++ mPath.close();
++ mCanvas.clipPath(mPath);
++ mCanvas.drawColor(0xff000000);
++ mCanvas.drawPath(mPath, tPaint);
++
++ mMouseSurface.unlockCanvasAndPost(mCanvas);
++ mMouseSurface.openTransaction();
++ mMouseSurface.setSize(mMw, mMh);
++ mMouseSurface.closeTransaction();
++
++ } catch (Exception e) {
++ Slog.e(TAG, "Exception creating mouse surface",e);
++ }
++ mMlx = mMx;
++ mMly = mMy;
++ mMlw = mMw;
++ mMlh = mMh;
++ }
++
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
+
+ Surface.openTransaction();
+--- a/frameworks/base/core/java/android/view/IWindowManager.aidl
2011-02-24 18:01:12.656910000 -0800
++++ b/frameworks/base/core/java/android/view/IWindowManager.aidl
2011-02-28 18:18:05.344663002 -0800
+@@ -52,6 +52,9 @@
+ in IInputContext inputContext);
+ boolean inputMethodClientHasFocus(IInputMethodClient client);
+
++ // Draws the mouse cursor on the screen
++ boolean moveMouseSurface(int dx, int dy);
++
+ // These can only be called when injecting events to your own
window,
+ // or by holding the INJECT_EVENTS permission. These methods
may block
+ // until pending input events are finished being dispatched even
when 'sync' is false.
+--- a/frameworks/base/core/java/android/view/MotionEvent.java
2011-03-01 09:18:40.494662998 -0800
++++ b/frameworks/base/core/java/android/view/MotionEvent.java
2011-03-01 09:42:35.764663005 -0800
+@@ -781,6 +781,14 @@
+ return mDataSamples[mLastDataSampleIndex + SAMPLE_Y] +
mYOffset;
+ }
+
++ public final float getXOffset() {
++ return mXOffset;
++ }
++
++ public final float getYOffset() {
++ return mYOffset;
++ }
++
+ /**
+ * {@link #getPressure(int)} for the first pointer index (may be
an
+ * arbitrary pointer identifier).
--
cgit v0.8.3
> > > > > The thing i want to do is adding acursoron screen.
> > > > > In gingerbread, the events are handled and dispatch by ViewRoot, not
> > > > > Windowmanagerservice. But thecursorwas draw in windowsmanagerservice
> > > > > in froyo-x86.
> > > > > So if thecursorin windowsmanagerservice can not respond to the mouse
> > > > > move.
>
> > > > > I am trying to handle event in windowsmanagerserver. But it is too
> > > > > hard for me.
>
> > > > > On Jan 14, 2:40 am, Gregoire Gentil <
grego...@gentil.com> wrote:
>
> > > > > > @AI Sutton, if I was asking, it meant that I do not prefer to do the
> > > > > > porting myself ;-)
>
> > > > > > What I have discovered is that the mouse is now natively supported by
> > > > > > Gingerbread but it works like a trackball. It works like the arrow
> > > > > > keys of the keyboard. That's definitely interesting but getting a
> > > > > >cursoris still something more useful to my mind.
>
> > > > > > @summer, if the mouse is working as a trackball on Gingerbread, I
> > > > > > guess that the events are already managed by Android,
>
> > > > > > Grégoire
>
> > > > > > On Jan 12, 5:37 am, summer <
xiahui1...@gmail.com> wrote:
>
> > > > > > > The event mechanism had been change in gingerbread.
> > > > > > > Anybody know how to get motion event in WindowManagerService?
>
> > > > > > > On Jan 6, 5:38 pm, Al Sutton <
a...@funkyandroid.com> wrote:
>
> > > > > > > > Work on theGingerbread-x86 branch is in it's early days and nothings been made available, but if you want to do the forward porting work please let the list know to avoid duplication of effort.
>
> > > > > > > > Al.
>
> > > > > > > > On 5 Jan 2011, at 20:48, Gregoire Gentil wrote:
>
> > > > > > > > > Androidx-86 wrote a nicecursorpatch for Froyo and it has been