Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a21a77d authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change I1369e9ab into eclair

* changes:
  Work on issue #2144454: Inconsistent swipes...
parents 16cb04ab 1411d1c8
Loading
Loading
Loading
Loading
+198 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.view.WindowManagerPolicy;

public class InputDevice {
    static final boolean DEBUG_POINTERS = false;
    static final boolean DEBUG_HACKS = false;
    
    /** Amount that trackball needs to move in order to generate a key event. */
    static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
@@ -76,6 +77,19 @@ public class InputDevice {
        final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
                                        + MotionEvent.NUM_SAMPLE_DATA];
        
        // Used to determine whether we dropped bad data, to avoid doing
        // it repeatedly.
        final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
        
        // Used to perform averaging of reported coordinates, to smooth
        // the data and filter out transients during a release.
        static final int HISTORY_SIZE = 5;
        int[] mHistoryDataStart = new int[MAX_POINTERS];
        int[] mHistoryDataEnd = new int[MAX_POINTERS];
        final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
                                        * HISTORY_SIZE];
        final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
        
        // Temporary data structures for doing the pointer ID mapping.
        final int[] mLast2Next = new int[MAX_POINTERS];
        final int[] mNext2Last = new int[MAX_POINTERS];
@@ -98,6 +112,183 @@ public class InputDevice {
            }
        }
        
        /**
         * Special hack for devices that have bad screen data: if one of the
         * points has moved more than a screen height from the last position,
         * then drop it.
         */
        void dropBadPoint(InputDevice dev) {
            // We should always have absY, but let's be paranoid.
            if (dev.absY == null) {
                return;
            }
            // Don't do anything if a finger is going down or up.  We run
            // here before assigning pointer IDs, so there isn't a good
            // way to do per-finger matching.
            if (mNextNumPointers != mLastNumPointers) {
                return;
            }
            
            // We consider a single movement across more than a 7/16 of
            // the long size of the screen to be bad.  This was a magic value
            // determined by looking at the maximum distance it is feasible
            // to actually move in one sample.
            final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
            
            // Look through all new points and see if any are farther than
            // acceptable from all previous points.
            for (int i=mNextNumPointers-1; i>=0; i--) {
                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
                //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
                final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
                if (DEBUG_HACKS) Log.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
                boolean dropped = false;
                if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
                    dropped = true;
                    int closestDy = -1;
                    int closestY = -1;
                    // We will drop this new point if it is sufficiently
                    // far away from -all- last points.
                    for (int j=mLastNumPointers-1; j>=0; j--) {
                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
                        //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
                        int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
                        //if (dx < 0) dx = -dx;
                        if (dy < 0) dy = -dy;
                        if (DEBUG_HACKS) Log.v("InputDevice", "Comparing with last point #" + j
                                + ": y=" + mLastData[joff] + " dy=" + dy);
                        if (dy < maxDy) {
                            dropped = false;
                            break;
                        } else if (closestDy < 0 || dy < closestDy) {
                            closestDy = dy;
                            closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
                        }
                    }
                    if (dropped) {
                        dropped = true;
                        Log.i("InputDevice", "Dropping bad point #" + i
                                + ": newY=" + y + " closestDy=" + closestDy
                                + " maxDy=" + maxDy);
                        mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
                        break;
                    }
                }
                mDroppedBadPoint[i] = dropped;
            }
        }
        
        /**
         * Special hack for devices that have bad screen data: aggregate and
         * compute averages of the coordinate data, to reduce the amount of
         * jitter seen by applications.
         */
        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
                int nextNumPointers) {
            final int numPointers = mLastNumPointers;
            final int[] rawData = mLastData;
            if (DEBUG_HACKS) Log.v("InputDevice", "lastNumPointers=" + lastNumPointers
                    + " nextNumPointers=" + nextNumPointers
                    + " numPointers=" + numPointers);
            for (int i=0; i<numPointers; i++) {
                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
                // We keep the average data in offsets based on the pointer
                // ID, so we don't need to move it around as fingers are
                // pressed and released.
                final int p = mPointerIds[i];
                final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
                if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
                    if (lastNumPointers < nextNumPointers) {
                        // This pointer is going down.  Clear its history
                        // and start fresh.
                        if (DEBUG_HACKS) Log.v("InputDevice", "Pointer down @ index "
                                + upOrDownPointer + " id " + mPointerIds[i]);
                        mHistoryDataStart[i] = 0;
                        mHistoryDataEnd[i] = 0;
                        System.arraycopy(rawData, ioff, mHistoryData, poff,
                                MotionEvent.NUM_SAMPLE_DATA);
                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
                                MotionEvent.NUM_SAMPLE_DATA);
                        continue;
                    } else {
                        // The pointer is going up.  Just fall through to
                        // recompute the last averaged point (and don't add
                        // it as a new point to include in the average).
                        if (DEBUG_HACKS) Log.v("InputDevice", "Pointer up @ index "
                                + upOrDownPointer + " id " + mPointerIds[i]);
                    }
                } else {
                    int end = mHistoryDataEnd[i];
                    int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
                    int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
                    int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
                    int newX = rawData[ioff + MotionEvent.SAMPLE_X];
                    int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
                    int dx = newX-oldX;
                    int dy = newY-oldY;
                    int delta = dx*dx + dy*dy;
                    if (DEBUG_HACKS) Log.v("InputDevice", "Delta from last: " + delta);
                    if (delta >= (75*75)) {
                        // Magic number, if moving farther than this, turn
                        // off filtering to avoid lag in response.
                        mHistoryDataStart[i] = 0;
                        mHistoryDataEnd[i] = 0;
                        System.arraycopy(rawData, ioff, mHistoryData, poff,
                                MotionEvent.NUM_SAMPLE_DATA);
                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
                                MotionEvent.NUM_SAMPLE_DATA);
                        continue;
                    } else {
                        end++;
                        if (end >= HISTORY_SIZE) {
                            end -= HISTORY_SIZE;
                        }
                        mHistoryDataEnd[i] = end;
                        int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
                        mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
                        mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
                        mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
                                = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
                        int start = mHistoryDataStart[i];
                        if (end == start) {
                            start++;
                            if (start >= HISTORY_SIZE) {
                                start -= HISTORY_SIZE;
                            }
                            mHistoryDataStart[i] = start;
                        }
                    }
                }
                
                // Now compute the average.
                int start = mHistoryDataStart[i];
                int end = mHistoryDataEnd[i];
                int x=0, y=0;
                int totalPressure = 0;
                while (start != end) {
                    int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
                    int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
                    x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
                    y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
                    totalPressure += pressure;
                    start++;
                    if (start >= HISTORY_SIZE) start = 0;
                }
                int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
                int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
                x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
                y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
                totalPressure += pressure;
                x /= totalPressure;
                y /= totalPressure;
                if (DEBUG_HACKS) Log.v("InputDevice", "Averaging " + totalPressure
                        + " weight: (" + x + "," + y + ")");
                mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
                mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
            }
            return mAveragedData;
        }
        
        private boolean assignPointer(int nextIndex, boolean allowOverlap) {
            final int lastNumPointers = mLastNumPointers;
            final int[] next2Last = mNext2Last;
@@ -333,7 +524,13 @@ public class InputDevice {
            int upOrDownPointer = updatePointerIdentifiers();
            
            final float[] reportData = mReportData;
            final int[] rawData = mLastData;
            final int[] rawData;
            if (KeyInputQueue.BAD_TOUCH_HACK) {
                rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
                        nextNumPointers);
            } else {
                rawData = mLastData;
            }
            
            final int numPointers = mLastNumPointers;
            
+34 −27
Original line number Diff line number Diff line
@@ -52,6 +52,12 @@ public abstract class KeyInputQueue {
    static final boolean DEBUG_VIRTUAL_KEYS = false;
    static final boolean DEBUG_POINTERS = false;
    
    /**
     * Turn on some hacks we have to improve the touch interaction with a
     * certain device whose screen currently is not all that good.
     */
    static final boolean BAD_TOUCH_HACK = true;
    
    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";

    final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
@@ -540,19 +546,17 @@ public abstract class KeyInputQueue {
                                            keycode, 0, scancode,
                                            ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
                                             ? KeyEvent.FLAG_WOKE_HERE : 0));
                            
                        } else if (ev.type == RawInputEvent.EV_KEY) {
                            // Single touch protocol: touch going down or up.
                            if (ev.scancode == RawInputEvent.BTN_TOUCH &&
                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
                                di.mAbs.changed = true;
                                di.mAbs.mDown[0] = ev.value != 0;
                            } else if (ev.scancode == RawInputEvent.BTN_2 &&
                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
                                di.mAbs.changed = true;
                                di.mAbs.mDown[1] = ev.value != 0;
                            
                            // Trackball (mouse) protocol: press down or up.
                            } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
                                    (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
                                di.mRel.changed = true;
@@ -560,6 +564,7 @@ public abstract class KeyInputQueue {
                                send = true;
                            }
    
                        // Process position events from multitouch protocol.
                        } else if (ev.type == RawInputEvent.EV_ABS &&
                                (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
                            if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
@@ -586,9 +591,9 @@ public abstract class KeyInputQueue {
                                    + MotionEvent.SAMPLE_SIZE] = ev.value;
                            }
                        
                        // Process position events from single touch protocol.
                        } else if (ev.type == RawInputEvent.EV_ABS &&
                                (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
                            // Finger 1
                            if (ev.scancode == RawInputEvent.ABS_X) {
                                di.mAbs.changed = true;
                                di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
@@ -605,18 +610,9 @@ public abstract class KeyInputQueue {
                                di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
                                                 + MotionEvent.SAMPLE_SIZE] = ev.value;

                            // Finger 2
                            } else if (ev.scancode == RawInputEvent.ABS_HAT0X) {
                                di.mAbs.changed = true;
                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA 
                                         + MotionEvent.SAMPLE_X] = ev.value;
                            } else if (ev.scancode == RawInputEvent.ABS_HAT0Y) {
                                di.mAbs.changed = true;
                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
                                        + MotionEvent.SAMPLE_Y] = ev.value;
                            }
    
                        // Process movement events from trackball (mouse) protocol.
                        } else if (ev.type == RawInputEvent.EV_REL &&
                                (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
                            // Add this relative movement into our totals.
@@ -629,6 +625,9 @@ public abstract class KeyInputQueue {
                            }
                        }
                        
                        // Handle multitouch protocol sync: tells us that the
                        // driver has returned all data for -one- of the pointers
                        // that is currently down.
                        if (ev.type == RawInputEvent.EV_SYN
                                && ev.scancode == RawInputEvent.SYN_MT_REPORT
                                && di.mAbs != null) {
@@ -654,6 +653,9 @@ public abstract class KeyInputQueue {
                                    if (DEBUG_POINTERS) Log.v(TAG, "MT_REPORT: no pointer");
                                }
                            }
                        
                        // Handle general event sync: all data for the current
                        // event update has been delivered.
                        } else if (send || (ev.type == RawInputEvent.EV_SYN
                                && ev.scancode == RawInputEvent.SYN_REPORT)) {
                            if (mDisplay != null) {
@@ -677,15 +679,10 @@ public abstract class KeyInputQueue {
                                                    MotionEvent.NUM_SAMPLE_DATA);
                                            ms.mNextNumPointers++;
                                        }
                                        if (ms.mDown[1]) {
                                            System.arraycopy(di.curTouchVals,
                                                    MotionEvent.NUM_SAMPLE_DATA,
                                                    ms.mNextData,
                                                    ms.mNextNumPointers
                                                    * MotionEvent.NUM_SAMPLE_DATA,
                                                    MotionEvent.NUM_SAMPLE_DATA);
                                            ms.mNextNumPointers++;
                                    }
                                    
                                    if (BAD_TOUCH_HACK) {
                                        ms.dropBadPoint(di);
                                    }
                                    
                                    boolean doMotion = !monitorVirtualKey(di,
@@ -719,6 +716,16 @@ public abstract class KeyInputQueue {
                                                        RawInputEvent.CLASS_TOUCHSCREEN, me);
                                            }
                                        } while (ms.hasMore());
                                    } else {
                                        // We are consuming movement in the
                                        // virtual key area...  but still
                                        // propagate this to the previous
                                        // data for comparisons.
                                        System.arraycopy(ms.mNextData, 0,
                                                ms.mLastData, 0,
                                                ms.mNextNumPointers
                                                        * MotionEvent.NUM_SAMPLE_DATA);
                                        ms.mLastNumPointers = ms.mNextNumPointers;
                                    }
                                    
                                    ms.finish();