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

Commit 85d1f158 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 7353

* changes:
  Implement virtual button support.
parents 1f872d4e e3dd8848
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ public:
    int getKeycodeState(int key) const;
    int getKeycodeState(int32_t deviceId, int key) const;
    
    status_t scancodeToKeycode(int32_t deviceId, int scancode,
            int32_t* outKeycode, uint32_t* outFlags) const;
    
    // special type codes when devices are added/removed.
    enum {
        DEVICE_ADDED = 0x10000000,
@@ -121,7 +124,7 @@ private:
    mutable Mutex   mLock;
    
    bool            mHaveFirstKeyboard;
    int32_t         mFirstKeyboardId; // the API is that the build in keyboard is id 0, so map it
    int32_t         mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it
    
    struct device_ent {
        device_t* device;
+29 −0
Original line number Diff line number Diff line
@@ -240,6 +240,35 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const
    return 0;
}

status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
        int32_t* outKeycode, uint32_t* outFlags) const
{
    AutoMutex _l(mLock);
    device_t* device = getDevice(deviceId);
    
    if (device != NULL && device->layoutMap != NULL) {
        status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
        if (err == NO_ERROR) {
            return NO_ERROR;
        }
    }
    
    if (mHaveFirstKeyboard) {
        device = getDevice(mFirstKeyboardId);
        
        if (device != NULL && device->layoutMap != NULL) {
            status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
            if (err == NO_ERROR) {
                return NO_ERROR;
            }
        }
    }
    
    *outKeycode = 0;
    *outFlags = 0;
    return NAME_NOT_FOUND;
}

EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
{
    if (deviceId == 0) deviceId = mFirstKeyboardId;
+70 −48
Original line number Diff line number Diff line
@@ -66,19 +66,56 @@ public class InputDevice {
        MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano,
                boolean isAbs, Display display, int orientation,
                int metaState) {
            if (!changed) {
                return null;
            }
            
            float scaledX = x;
            float scaledY = y;
            float temp;
            float scaledPressure = 1.0f;
            float scaledSize = 0;
            int edgeFlags = 0;
            
            int action;
            if (down != lastDown) {
                if (isAbs) {
                int w = display.getWidth()-1;
                int h = display.getHeight()-1;
                    final AbsoluteInfo absX = device.absX;
                    final AbsoluteInfo absY = device.absY;
                    if (down && absX != null && absY != null) {
                        // We don't let downs start unless we are
                        // inside of the screen.  There are two reasons for
                        // this: to avoid spurious touches when holding
                        // the edges of the device near the touchscreen,
                        // and to avoid reporting events if there are virtual
                        // keys on the touchscreen outside of the display
                        // area.
                        if (scaledX < absX.minValue || scaledX > absX.maxValue
                                || scaledY < absY.minValue || scaledY > absY.maxValue) {
                            if (false) Log.v("InputDevice", "Rejecting (" + scaledX + ","
                                    + scaledY + "): outside of ("
                                    + absX.minValue + "," + absY.minValue
                                    + ")-(" + absX.maxValue + ","
                                    + absY.maxValue + ")");
                            return null;
                        }
                    }
                } else {
                    x = y = 0;
                }
                lastDown = down;
                if (down) {
                    action = MotionEvent.ACTION_DOWN;
                    downTime = curTime;
                } else {
                    action = MotionEvent.ACTION_UP;
                }
                currentMove = null;
            } else {
                action = MotionEvent.ACTION_MOVE;
            }
            
            if (isAbs) {
                final int dispW = display.getWidth()-1;
                final int dispH = display.getHeight()-1;
                int w = dispW;
                int h = dispH;
                if (orientation == Surface.ROTATION_90
                        || orientation == Surface.ROTATION_270) {
                    int tmp = w;
@@ -120,17 +157,18 @@ public class InputDevice {
                        break;
                }

                if (scaledX == 0) {
                if (action != MotionEvent.ACTION_DOWN) {
                    if (scaledX <= 0) {
                        edgeFlags += MotionEvent.EDGE_LEFT;
                } else if (scaledX == display.getWidth() - 1.0f) {
                    } else if (scaledX >= dispW) {
                        edgeFlags += MotionEvent.EDGE_RIGHT;
                    }
                
                if (scaledY == 0) {
                    if (scaledY <= 0) {
                        edgeFlags += MotionEvent.EDGE_TOP;
                } else if (scaledY == display.getHeight() - 1.0f) {
                    } else if (scaledY >= dispH) {
                        edgeFlags += MotionEvent.EDGE_BOTTOM;
                    }
                }
                
            } else {
                scaledX *= xMoveScale;
@@ -153,24 +191,6 @@ public class InputDevice {
                }
            }
            
            changed = false;
            if (down != lastDown) {
                int action;
                lastDown = down;
                if (down) {
                    action = MotionEvent.ACTION_DOWN;
                    downTime = curTime;
                } else {
                    action = MotionEvent.ACTION_UP;
                }
                currentMove = null;
                if (!isAbs) {
                    x = y = 0;
                }
                return MotionEvent.obtainNano(downTime, curTime, curTimeNano, action,
                        scaledX, scaledY, scaledPressure, scaledSize, metaState,
                        xPrecision, yPrecision, device.id, edgeFlags);
            } else {
            if (currentMove != null) {
                if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
                        + " y=" + scaledY + " to " + currentMove);
@@ -181,13 +201,15 @@ public class InputDevice {
                }
                return null;
            }
                MotionEvent me = MotionEvent.obtainNano(downTime, curTime, curTimeNano,
                        MotionEvent.ACTION_MOVE, scaledX, scaledY,
            
            MotionEvent me = MotionEvent.obtainNano(downTime, curTime,
                    curTimeNano, action, scaledX, scaledY,
                    scaledPressure, scaledSize, metaState,
                    xPrecision, yPrecision, device.id, edgeFlags);
            if (action == MotionEvent.ACTION_MOVE) {
                currentMove = me;
                return me;
            }
            return me;
        }
    }
    
+226 −19
Original line number Diff line number Diff line
@@ -30,10 +30,20 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public abstract class KeyInputQueue {
    static final String TAG = "KeyInputQueue";

    SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
    static final boolean DEBUG_VIRTUAL_KEYS = false;
    
    final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
    final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
    
    int mGlobalMetaState = 0;
    boolean mHaveGlobalMetaState = false;
@@ -44,10 +54,14 @@ public abstract class KeyInputQueue {
    int mCacheCount;

    Display mDisplay = null;
    int mDisplayWidth;
    int mDisplayHeight;
    
    int mOrientation = Surface.ROTATION_0;
    int[] mKeyRotationMap = null;
    
    VirtualKey mPressedVirtualKey = null;
    
    PowerManager.WakeLock mWakeLock;

    static final int[] KEY_90_MAP = new int[] {
@@ -110,11 +124,106 @@ public abstract class KeyInputQueue {
        QueuedEvent next;
    }

    /**
     * A key that exists as a part of the touch-screen, outside of the normal
     * display area of the screen.
     */
    static class VirtualKey {
        int scancode;
        int centerx;
        int centery;
        int width;
        int height;
        
        int hitLeft;
        int hitTop;
        int hitRight;
        int hitBottom;
        
        InputDevice lastDevice;
        int lastKeycode;
        
        boolean checkHit(int x, int y) {
            return (x >= hitLeft && x <= hitRight
                    && y >= hitTop && y <= hitBottom);
        }
        
        void computeHitRect(InputDevice dev, int dw, int dh) {
            if (dev == lastDevice) {
                return;
            }
            
            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
            
            lastDevice = dev;
            
            int minx = dev.absX.minValue;
            int maxx = dev.absX.maxValue;
            
            int halfw = width/2;
            int left = centerx - halfw;
            int right = centerx + halfw;
            hitLeft = minx + ((left*maxx-minx)/dw);
            hitRight = minx + ((right*maxx-minx)/dw);
            
            int miny = dev.absY.minValue;
            int maxy = dev.absY.maxValue;
            
            int halfh = height/2;
            int top = centery - halfh;
            int bottom = centery + halfh;
            hitTop = miny + ((top*maxy-miny)/dh);
            hitBottom = miny + ((bottom*maxy-miny)/dh);
        }
    }
    
    KeyInputQueue(Context context) {
        if (MEASURE_LATENCY) {
            lt = new LatencyTimer(100, 1000);
        }

        try {
            FileInputStream fis = new FileInputStream(
                    "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen");
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            String str = br.readLine();
            if (str != null) {
                String[] it = str.split(":");
                if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
                final int N = it.length-6;
                for (int i=0; i<=N; i+=6) {
                    if (!"0x01".equals(it[i])) {
                        Log.w(TAG, "Unknown virtual key type at elem #" + i
                                + ": " + it[i]);
                        continue;
                    }
                    try {
                        VirtualKey sb = new VirtualKey();
                        sb.scancode = Integer.parseInt(it[i+1]);
                        sb.centerx = Integer.parseInt(it[i+2]);
                        sb.centery = Integer.parseInt(it[i+3]);
                        sb.width = Integer.parseInt(it[i+4]);
                        sb.height = Integer.parseInt(it[i+5]);
                        if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
                                + sb.scancode + ": center=" + sb.centerx + ","
                                + sb.centery + " size=" + sb.width + "x"
                                + sb.height);
                        mVirtualKeys.add(sb);
                    } catch (NumberFormatException e) {
                        Log.w(TAG, "Bad number at region " + i + " in: "
                                + str, e);
                    }
                }
            }
            br.close();
        } catch (FileNotFoundException e) {
            Log.i(TAG, "No virtual keys found");
        } catch (IOException e) {
            Log.w(TAG, "Error reading virtual keys", e);
        }
        
        PowerManager pm = (PowerManager)context.getSystemService(
                                                        Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -131,6 +240,12 @@ public abstract class KeyInputQueue {

    public void setDisplay(Display display) {
        mDisplay = display;
        
        // We assume at this point that the display dimensions reflect the
        // natural, unrotated display.  We will perform hit tests for soft
        // buttons based on that display.
        mDisplayWidth = display.getWidth();
        mDisplayHeight = display.getHeight();
    }
    
    public void getInputConfiguration(Configuration config) {
@@ -173,6 +288,7 @@ public abstract class KeyInputQueue {
    public static native int getScancodeState(int deviceId, int sw);
    public static native int getKeycodeState(int sw);
    public static native int getKeycodeState(int deviceId, int sw);
    public static native int scancodeToKeycode(int deviceId, int scancode);
    public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
    
    public static KeyEvent newKeyEvent(InputDevice device, long downTime,
@@ -339,8 +455,54 @@ public abstract class KeyInputQueue {
                                }
                                
                                MotionEvent me;
                                me = di.mAbs.generateMotion(di, curTime, curTimeNano, true,
                                        mDisplay, mOrientation, mGlobalMetaState);
                                
                                InputDevice.MotionState ms = di.mAbs;
                                if (ms.changed) {
                                    ms.changed = false;
                                    
                                    boolean doMotion = true;
                                    
                                    // Look for virtual buttons.
                                    VirtualKey vk = mPressedVirtualKey;
                                    if (vk != null) {
                                        doMotion = false;
                                        if (!ms.down) {
                                            mPressedVirtualKey = null;
                                            ms.lastDown = ms.down;
                                            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
                                                    "Generate key up for: " + vk.scancode);
                                            addLocked(di, curTimeNano, ev.flags,
                                                    RawInputEvent.CLASS_KEYBOARD,
                                                    newKeyEvent(di, di.mDownTime,
                                                            curTime, false,
                                                            vk.lastKeycode,
                                                            0, vk.scancode, 0));
                                        }
                                    } else if (ms.down && !ms.lastDown) {
                                        vk = findSoftButton(di);
                                        if (vk != null) {
                                            doMotion = false;
                                            mPressedVirtualKey = vk;
                                            vk.lastKeycode = scancodeToKeycode(
                                                    di.id, vk.scancode);
                                            ms.lastDown = ms.down;
                                            di.mDownTime = curTime;
                                            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
                                                    "Generate key down for: " + vk.scancode
                                                    + " (keycode=" + vk.lastKeycode + ")");
                                            addLocked(di, curTimeNano, ev.flags,
                                                    RawInputEvent.CLASS_KEYBOARD,
                                                    newKeyEvent(di, di.mDownTime,
                                                            curTime, true,
                                                            vk.lastKeycode, 0,
                                                            vk.scancode, 0));
                                        }
                                    }
                                    
                                    if (doMotion) {
                                        me = ms.generateMotion(di, curTime,
                                                curTimeNano, true, mDisplay,
                                                mOrientation, mGlobalMetaState);
                                        if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
                                                + " y=" + di.mAbs.y + " ev=" + me);
                                        if (me != null) {
@@ -350,8 +512,16 @@ public abstract class KeyInputQueue {
                                            addLocked(di, curTimeNano, ev.flags,
                                                    RawInputEvent.CLASS_TOUCHSCREEN, me);
                                        }
                                me = di.mRel.generateMotion(di, curTime, curTimeNano, false,
                                        mDisplay, mOrientation, mGlobalMetaState);
                                    }
                                }
                                
                                ms = di.mRel;
                                if (ms.changed) {
                                    ms.changed = false;
                                    
                                    me = ms.generateMotion(di, curTime,
                                            curTimeNano, false, mDisplay,
                                            mOrientation, mGlobalMetaState);
                                    if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
                                            + " y=" + di.mRel.y + " ev=" + me);
                                    if (me != null) {
@@ -363,12 +533,49 @@ public abstract class KeyInputQueue {
                        }
                    }
                }
            catch (RuntimeException exc) {
                
            } catch (RuntimeException exc) {
                Log.e(TAG, "InputReaderThread uncaught exception", exc);
            }
        }
    };

    private VirtualKey findSoftButton(InputDevice dev) {
        final int N = mVirtualKeys.size();
        if (N <= 0) {
            return null;
        }
        
        final InputDevice.AbsoluteInfo absx = dev.absX;
        final InputDevice.AbsoluteInfo absy = dev.absY;
        final InputDevice.MotionState absm = dev.mAbs;
        if (absx == null || absy == null || absm == null) {
            return null;
        }
        
        if (absm.x >= absx.minValue && absm.x <= absx.maxValue
                && absm.y >= absy.minValue && absm.y <= absy.maxValue) {
            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x
                    + "," + absm.y + ") inside of display");
            return null;
        }
        
        for (int i=0; i<N; i++) {
            VirtualKey sb = mVirtualKeys.get(i);
            sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" + absm.x + ","
                    + absm.y + ") in code " + sb.scancode + " - (" + sb.hitLeft
                    + "," + sb.hitTop + ")-(" + sb.hitRight + ","
                    + sb.hitBottom + ")");
            if (sb.checkHit(absm.x, absm.y)) {
                if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
                return sb;
            }
        }
        
        return null;
    }
    
    /**
     * Returns a new meta state for the given keys and old state.
     */
+19 −0
Original line number Diff line number Diff line
@@ -205,6 +205,23 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
    return st;
}

static jint
android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
                                            jint deviceId, jint scancode)
{
    jint res = 0;
    gLock.lock();
    if (gHub != NULL) {
        int32_t keycode;
        uint32_t flags;
        gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
        res = keycode;
    }
    gLock.unlock();
    
    return res;
}

static jboolean
android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
                                     jintArray keyCodes, jbooleanArray outFlags)
@@ -254,6 +271,8 @@ static JNINativeMethod gInputMethods[] = {
        (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
    { "hasKeys", "([I[Z)Z",
        (void*) android_server_KeyInputQueue_hasKeys },
    { "scancodeToKeycode", "(II)I",
        (void*) android_server_KeyInputQueue_scancodeToKeycode },
};

int register_android_server_KeyInputQueue(JNIEnv* env)