summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml61
-rw-r--r--core/java/android/view/IWindowManager.aidl5
-rw-r--r--core/java/android/view/InputDevice.aidl20
-rwxr-xr-xcore/java/android/view/InputDevice.java219
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java406
-rw-r--r--include/ui/EventHub.h8
-rw-r--r--include/ui/Input.h4
-rw-r--r--include/ui/InputReader.h157
-rw-r--r--libs/ui/EventHub.cpp9
-rw-r--r--libs/ui/InputDispatcher.cpp22
-rw-r--r--libs/ui/InputReader.cpp1046
-rw-r--r--native/include/android/input.h2
-rw-r--r--services/java/com/android/server/InputManager.java64
-rw-r--r--services/java/com/android/server/WindowManagerService.java8
-rw-r--r--services/jni/com_android_server_InputManager.cpp179
15 files changed, 1777 insertions, 433 deletions
diff --git a/api/current.xml b/api/current.xml
index 0331d3e..dad5c03 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -177160,14 +177160,19 @@
deprecated="not deprecated"
visibility="public"
>
-<constructor name="InputDevice"
- type="android.view.InputDevice"
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-</constructor>
+</method>
<method name="getDevice"
return="android.view.InputDevice"
abstract="false"
@@ -177181,6 +177186,28 @@
<parameter name="id" type="int">
</parameter>
</method>
+<method name="getDeviceIds"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getKeyCharacterMap"
return="android.view.KeyCharacterMap"
abstract="false"
@@ -177213,7 +177240,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="range" type="int">
+<parameter name="rangeType" type="int">
</parameter>
</method>
<method name="getName"
@@ -177238,8 +177265,8 @@
visibility="public"
>
</method>
-<method name="hasKey"
- return="boolean"
+<method name="writeToParcel"
+ return="void"
abstract="false"
native="false"
synchronized="false"
@@ -177248,9 +177275,21 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="keyCode" type="int">
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
</parameter>
</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEYBOARD_TYPE_ALPHABETIC"
type="int"
transient="false"
@@ -177579,14 +177618,6 @@
deprecated="not deprecated"
visibility="public"
>
-<constructor name="InputDevice.MotionRange"
- type="android.view.InputDevice.MotionRange"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
<method name="getFlat"
return="float"
abstract="false"
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e86e3bf..d4dd05c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,6 +29,7 @@ import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.InputChannel;
+import android.view.InputDevice;
/**
* System private interface to the window manager.
@@ -125,6 +126,10 @@ interface IWindowManager
// Report whether the hardware supports the given keys; returns true if successful
boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
+ // Get input device information.
+ InputDevice getInputDevice(int deviceId);
+ int[] getInputDeviceIds();
+
// For testing
void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/InputDevice.aidl b/core/java/android/view/InputDevice.aidl
new file mode 100644
index 0000000..dbc40c1
--- /dev/null
+++ b/core/java/android/view/InputDevice.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android.view.InputDevice.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.view;
+
+parcelable InputDevice;
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index d5b2121..fb47b9c 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,6 +16,12 @@
package android.view;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
/**
* Describes the capabilities of a particular input device.
* <p>
@@ -32,12 +38,14 @@ package android.view;
* the appropriate interpretation.
* </p>
*/
-public final class InputDevice {
+public final class InputDevice implements Parcelable {
private int mId;
private String mName;
private int mSources;
private int mKeyboardType;
+ private MotionRange[] mMotionRanges;
+
/**
* A mask for input source classes.
*
@@ -246,6 +254,8 @@ public final class InputDevice {
*/
public static final int MOTION_RANGE_ORIENTATION = 8;
+ private static final int MOTION_RANGE_LAST = MOTION_RANGE_ORIENTATION;
+
/**
* There is no keyboard.
*/
@@ -261,6 +271,11 @@ public final class InputDevice {
* The keyboard supports a complement of alphabetic keys.
*/
public static final int KEYBOARD_TYPE_ALPHABETIC = 2;
+
+ // Called by native code.
+ private InputDevice() {
+ mMotionRanges = new MotionRange[MOTION_RANGE_LAST + 1];
+ }
/**
* Gets information about the input device with the specified id.
@@ -268,8 +283,35 @@ public final class InputDevice {
* @return The input device or null if not found.
*/
public static InputDevice getDevice(int id) {
- // TODO
- return null;
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+ try {
+ return wm.getInputDevice(id);
+ } catch (RemoteException ex) {
+ throw new RuntimeException(
+ "Could not get input device information from Window Manager.", ex);
+ }
+ }
+
+ /**
+ * Gets the ids of all input devices in the system.
+ * @return The input device ids.
+ */
+ public static int[] getDeviceIds() {
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+ try {
+ return wm.getInputDeviceIds();
+ } catch (RemoteException ex) {
+ throw new RuntimeException(
+ "Could not get input device ids from Window Manager.", ex);
+ }
+ }
+
+ /**
+ * Gets the input device id.
+ * @return The input device id.
+ */
+ public int getId() {
+ return mId;
}
/**
@@ -307,23 +349,23 @@ public final class InputDevice {
/**
* Gets information about the range of values for a particular {@link MotionEvent}
* coordinate.
- * @param range The motion range constant.
+ * @param rangeType The motion range constant.
* @return The range of values, or null if the requested coordinate is not
* supported by the device.
*/
- public MotionRange getMotionRange(int range) {
- // TODO
- return null;
+ public MotionRange getMotionRange(int rangeType) {
+ if (rangeType < 0 || rangeType > MOTION_RANGE_LAST) {
+ throw new IllegalArgumentException("Requested range is out of bounds.");
+ }
+
+ return mMotionRanges[rangeType];
}
- /**
- * Returns true if the device supports a particular button or key.
- * @param keyCode The key code.
- * @return True if the device supports the key.
- */
- public boolean hasKey(int keyCode) {
- // TODO
- return false;
+ private void addMotionRange(int rangeType, float min, float max, float flat, float fuzz) {
+ if (rangeType >= 0 && rangeType <= MOTION_RANGE_LAST) {
+ MotionRange range = new MotionRange(min, max, flat, fuzz);
+ mMotionRanges[rangeType] = range;
+ }
}
/**
@@ -331,13 +373,24 @@ public final class InputDevice {
* coordinate.
*/
public static final class MotionRange {
+ private float mMin;
+ private float mMax;
+ private float mFlat;
+ private float mFuzz;
+
+ private MotionRange(float min, float max, float flat, float fuzz) {
+ mMin = min;
+ mMax = max;
+ mFlat = flat;
+ mFuzz = fuzz;
+ }
+
/**
* Gets the minimum value for the coordinate.
* @return The minimum value.
*/
public float getMin() {
- // TODO
- return 0;
+ return mMin;
}
/**
@@ -345,8 +398,7 @@ public final class InputDevice {
* @return The minimum value.
*/
public float getMax() {
- // TODO
- return 0;
+ return mMax;
}
/**
@@ -354,8 +406,7 @@ public final class InputDevice {
* @return The range of values.
*/
public float getRange() {
- // TODO
- return 0;
+ return mMax - mMin;
}
/**
@@ -365,8 +416,7 @@ public final class InputDevice {
* @return The extent of the center flat position.
*/
public float getFlat() {
- // TODO
- return 0;
+ return mFlat;
}
/**
@@ -376,8 +426,127 @@ public final class InputDevice {
* @return The error tolerance.
*/
public float getFuzz() {
- // TODO
- return 0;
+ return mFuzz;
+ }
+ }
+
+ public static final Parcelable.Creator<InputDevice> CREATOR
+ = new Parcelable.Creator<InputDevice>() {
+ public InputDevice createFromParcel(Parcel in) {
+ InputDevice result = new InputDevice();
+ result.readFromParcel(in);
+ return result;
+ }
+
+ public InputDevice[] newArray(int size) {
+ return new InputDevice[size];
+ }
+ };
+
+ private void readFromParcel(Parcel in) {
+ mId = in.readInt();
+ mName = in.readString();
+ mSources = in.readInt();
+ mKeyboardType = in.readInt();
+
+ for (;;) {
+ int rangeType = in.readInt();
+ if (rangeType < 0) {
+ break;
+ }
+
+ addMotionRange(rangeType,
+ in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeString(mName);
+ out.writeInt(mSources);
+ out.writeInt(mKeyboardType);
+
+ for (int i = 0; i <= MOTION_RANGE_LAST; i++) {
+ MotionRange range = mMotionRanges[i];
+ if (range != null) {
+ out.writeInt(i);
+ out.writeFloat(range.mMin);
+ out.writeFloat(range.mMax);
+ out.writeFloat(range.mFlat);
+ out.writeFloat(range.mFuzz);
+ }
+ }
+ out.writeInt(-1);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder description = new StringBuilder();
+ description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
+
+ description.append(" Keyboard Type: ");
+ switch (mKeyboardType) {
+ case KEYBOARD_TYPE_NONE:
+ description.append("none");
+ break;
+ case KEYBOARD_TYPE_NON_ALPHABETIC:
+ description.append("non-alphabetic");
+ break;
+ case KEYBOARD_TYPE_ALPHABETIC:
+ description.append("alphabetic");
+ break;
+ }
+ description.append("\n");
+
+ description.append(" Sources:");
+ appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
+ appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
+ appendSourceDescriptionIfApplicable(description, SOURCE_GAMEPAD, "gamepad");
+ appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
+ appendSourceDescriptionIfApplicable(description, SOURCE_MOUSE, "mouse");
+ appendSourceDescriptionIfApplicable(description, SOURCE_TRACKBALL, "trackball");
+ appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHPAD, "touchpad");
+ appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_LEFT, "joystick_left");
+ appendSourceDescriptionIfApplicable(description, SOURCE_JOYSTICK_RIGHT, "joystick_right");
+ description.append("\n");
+
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_X, "x");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_Y, "y");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_PRESSURE, "pressure");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_SIZE, "size");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MAJOR, "touchMajor");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOUCH_MINOR, "touchMinor");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MAJOR, "toolMajor");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_TOOL_MINOR, "toolMinor");
+ appendRangeDescriptionIfApplicable(description, MOTION_RANGE_ORIENTATION, "orientation");
+
+ return description.toString();
+ }
+
+ private void appendSourceDescriptionIfApplicable(StringBuilder description, int source,
+ String sourceName) {
+ if ((mSources & source) == source) {
+ description.append(" ");
+ description.append(sourceName);
+ }
+ }
+
+ private void appendRangeDescriptionIfApplicable(StringBuilder description,
+ int rangeType, String rangeName) {
+ MotionRange range = mMotionRanges[rangeType];
+ if (range != null) {
+ description.append(" Range[").append(rangeName);
+ description.append("]: min=").append(range.mMin);
+ description.append(" max=").append(range.mMax);
+ description.append(" flat=").append(range.mFlat);
+ description.append(" fuzz=").append(range.mFuzz);
+ description.append("\n");
}
}
}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index d5a9979..939f118 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -19,8 +19,10 @@ package com.android.internal.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.RectF;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -29,17 +31,45 @@ import android.view.ViewConfiguration;
import java.util.ArrayList;
public class PointerLocationView extends View {
+ private static final String TAG = "Pointer";
+
public static class PointerState {
- private final ArrayList<Float> mXs = new ArrayList<Float>();
- private final ArrayList<Float> mYs = new ArrayList<Float>();
+ // Trace of previous points.
+ private float[] mTraceX = new float[32];
+ private float[] mTraceY = new float[32];
+ private int mTraceCount;
+
+ // True if the pointer is down.
private boolean mCurDown;
- private int mCurX;
- private int mCurY;
- private float mCurPressure;
- private float mCurSize;
- private int mCurWidth;
+
+ // Most recent coordinates.
+ private MotionEvent.PointerCoords mCoords = new MotionEvent.PointerCoords();
+
+ // Most recent velocity.
private float mXVelocity;
private float mYVelocity;
+
+ public void clearTrace() {
+ mTraceCount = 0;
+ }
+
+ public void addTrace(float x, float y) {
+ int traceCapacity = mTraceX.length;
+ if (mTraceCount == traceCapacity) {
+ traceCapacity *= 2;
+ float[] newTraceX = new float[traceCapacity];
+ System.arraycopy(mTraceX, 0, newTraceX, 0, mTraceCount);
+ mTraceX = newTraceX;
+
+ float[] newTraceY = new float[traceCapacity];
+ System.arraycopy(mTraceY, 0, newTraceY, 0, mTraceCount);
+ mTraceY = newTraceY;
+ }
+
+ mTraceX[mTraceCount] = x;
+ mTraceY[mTraceCount] = y;
+ mTraceCount += 1;
+ }
}
private final ViewConfiguration mVC;
@@ -54,11 +84,12 @@ public class PointerLocationView extends View {
private boolean mCurDown;
private int mCurNumPointers;
private int mMaxNumPointers;
- private final ArrayList<PointerState> mPointers
- = new ArrayList<PointerState>();
+ private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
private final VelocityTracker mVelocity;
+ private final FasterStringBuilder mText = new FasterStringBuilder();
+
private boolean mPrintCoords = true;
public PointerLocationView(Context c) {
@@ -94,6 +125,18 @@ public class PointerLocationView extends View {
mPointers.add(ps);
mVelocity = VelocityTracker.obtain();
+
+ logInputDeviceCapabilities();
+ }
+
+ private void logInputDeviceCapabilities() {
+ int[] deviceIds = InputDevice.getDeviceIds();
+ for (int i = 0; i < deviceIds.length; i++) {
+ InputDevice device = InputDevice.getDevice(deviceIds[i]);
+ if (device != null) {
+ Log.i(TAG, device.toString());
+ }
+ }
}
public void setPrintCoords(boolean state) {
@@ -113,6 +156,21 @@ public class PointerLocationView extends View {
+ " bottom=" + mTextMetrics.bottom);
}
}
+
+ // Draw an oval. When angle is 0 radians, orients the major axis vertically,
+ // angles less than or greater than 0 radians rotate the major axis left or right.
+ private RectF mReusableOvalRect = new RectF();
+ private void drawOval(Canvas canvas, float x, float y, float major, float minor,
+ float angle, Paint paint) {
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ canvas.rotate((float) (angle * 180 / Math.PI), x, y);
+ mReusableOvalRect.left = x - minor / 2;
+ mReusableOvalRect.right = x + minor / 2;
+ mReusableOvalRect.top = y - major / 2;
+ mReusableOvalRect.bottom = y + major / 2;
+ canvas.drawOval(mReusableOvalRect, paint);
+ canvas.restore();
+ }
@Override
protected void onDraw(Canvas canvas) {
@@ -124,76 +182,80 @@ public class PointerLocationView extends View {
final int NP = mPointers.size();
+ // Labels
if (NP > 0) {
final PointerState ps = mPointers.get(0);
canvas.drawRect(0, 0, itemW-1, bottom,mTextBackgroundPaint);
- canvas.drawText("P: " + mCurNumPointers + " / " + mMaxNumPointers,
- 1, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("P: ").append(mCurNumPointers)
+ .append(" / ").append(mMaxNumPointers)
+ .toString(), 1, base, mTextPaint);
- final int N = ps.mXs.size();
+ final int N = ps.mTraceCount;
if ((mCurDown && ps.mCurDown) || N == 0) {
canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom, mTextBackgroundPaint);
- canvas.drawText("X: " + ps.mCurX, 1 + itemW, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("X: ").append(ps.mCoords.x, 1)
+ .toString(), 1 + itemW, base, mTextPaint);
canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom, mTextBackgroundPaint);
- canvas.drawText("Y: " + ps.mCurY, 1 + itemW * 2, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("Y: ").append(ps.mCoords.y, 1)
+ .toString(), 1 + itemW * 2, base, mTextPaint);
} else {
- float dx = ps.mXs.get(N-1) - ps.mXs.get(0);
- float dy = ps.mYs.get(N-1) - ps.mYs.get(0);
+ float dx = ps.mTraceX[N - 1] - ps.mTraceX[0];
+ float dy = ps.mTraceY[N - 1] - ps.mTraceY[0];
canvas.drawRect(itemW, 0, (itemW * 2) - 1, bottom,
Math.abs(dx) < mVC.getScaledTouchSlop()
? mTextBackgroundPaint : mTextLevelPaint);
- canvas.drawText("dX: " + String.format("%.1f", dx), 1 + itemW, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("dX: ").append(dx, 1)
+ .toString(), 1 + itemW, base, mTextPaint);
canvas.drawRect(itemW * 2, 0, (itemW * 3) - 1, bottom,
Math.abs(dy) < mVC.getScaledTouchSlop()
? mTextBackgroundPaint : mTextLevelPaint);
- canvas.drawText("dY: " + String.format("%.1f", dy), 1 + itemW * 2, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("dY: ").append(dy, 1)
+ .toString(), 1 + itemW * 2, base, mTextPaint);
}
canvas.drawRect(itemW * 3, 0, (itemW * 4) - 1, bottom, mTextBackgroundPaint);
- int velocity = (int) (ps.mXVelocity * 1000);
- canvas.drawText("Xv: " + velocity, 1 + itemW * 3, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("Xv: ").append(ps.mXVelocity, 3)
+ .toString(), 1 + itemW * 3, base, mTextPaint);
canvas.drawRect(itemW * 4, 0, (itemW * 5) - 1, bottom, mTextBackgroundPaint);
- velocity = (int) (ps.mYVelocity * 1000);
- canvas.drawText("Yv: " + velocity, 1 + itemW * 4, base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("Yv: ").append(ps.mYVelocity, 3)
+ .toString(), 1 + itemW * 4, base, mTextPaint);
canvas.drawRect(itemW * 5, 0, (itemW * 6) - 1, bottom, mTextBackgroundPaint);
- canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCurPressure * itemW) - 1,
+ canvas.drawRect(itemW * 5, 0, (itemW * 5) + (ps.mCoords.pressure * itemW) - 1,
bottom, mTextLevelPaint);
- canvas.drawText("Prs: " + String.format("%.2f", ps.mCurPressure), 1 + itemW * 5,
- base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("Prs: ").append(ps.mCoords.pressure, 2)
+ .toString(), 1 + itemW * 5, base, mTextPaint);
canvas.drawRect(itemW * 6, 0, w, bottom, mTextBackgroundPaint);
- canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCurSize * itemW) - 1,
+ canvas.drawRect(itemW * 6, 0, (itemW * 6) + (ps.mCoords.size * itemW) - 1,
bottom, mTextLevelPaint);
- canvas.drawText("Size: " + String.format("%.2f", ps.mCurSize), 1 + itemW * 6,
- base, mTextPaint);
+ canvas.drawText(mText.clear()
+ .append("Size: ").append(ps.mCoords.size, 2)
+ .toString(), 1 + itemW * 6, base, mTextPaint);
}
- for (int p=0; p<NP; p++) {
+ // Pointer trace.
+ for (int p = 0; p < NP; p++) {
final PointerState ps = mPointers.get(p);
- if (mCurDown && ps.mCurDown) {
- canvas.drawLine(0, (int)ps.mCurY, getWidth(), (int)ps.mCurY, mTargetPaint);
- canvas.drawLine((int)ps.mCurX, 0, (int)ps.mCurX, getHeight(), mTargetPaint);
- int pressureLevel = (int)(ps.mCurPressure*255);
- mPaint.setARGB(255, pressureLevel, 128, 255-pressureLevel);
- canvas.drawPoint(ps.mCurX, ps.mCurY, mPaint);
- canvas.drawCircle(ps.mCurX, ps.mCurY, ps.mCurWidth, mPaint);
- }
- }
-
- for (int p=0; p<NP; p++) {
- final PointerState ps = mPointers.get(p);
-
- final int N = ps.mXs.size();
- float lastX=0, lastY=0;
+ // Draw path.
+ final int N = ps.mTraceCount;
+ float lastX = 0, lastY = 0;
boolean haveLast = false;
boolean drawn = false;
mPaint.setARGB(255, 128, 255, 255);
- for (int i=0; i<N; i++) {
- float x = ps.mXs.get(i);
- float y = ps.mYs.get(i);
+ for (int i=0; i < N; i++) {
+ float x = ps.mTraceX[i];
+ float y = ps.mTraceY[i];
if (Float.isNaN(x)) {
haveLast = false;
continue;
@@ -208,21 +270,57 @@ public class PointerLocationView extends View {
haveLast = true;
}
+ // Draw velocity vector.
if (drawn) {
mPaint.setARGB(255, 255, 64, 128);
- float xVel = ps.mXVelocity * (1000/60);
- float yVel = ps.mYVelocity * (1000/60);
- canvas.drawLine(lastX, lastY, lastX+xVel, lastY+yVel, mPaint);
+ float xVel = ps.mXVelocity * (1000 / 60);
+ float yVel = ps.mYVelocity * (1000 / 60);
+ canvas.drawLine(lastX, lastY, lastX + xVel, lastY + yVel, mPaint);
+ }
+
+ if (mCurDown && ps.mCurDown) {
+ // Draw crosshairs.
+ canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint);
+ canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint);
+
+ // Draw current point.
+ int pressureLevel = (int)(ps.mCoords.pressure * 255);
+ mPaint.setARGB(255, pressureLevel, 255, 255 - pressureLevel);
+ canvas.drawPoint(ps.mCoords.x, ps.mCoords.y, mPaint);
+
+ // Draw current touch ellipse.
+ mPaint.setARGB(255, pressureLevel, 255 - pressureLevel, 128);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.touchMajor,
+ ps.mCoords.touchMinor, ps.mCoords.orientation, mPaint);
+
+ // Draw current tool ellipse.
+ mPaint.setARGB(255, pressureLevel, 128, 255 - pressureLevel);
+ drawOval(canvas, ps.mCoords.x, ps.mCoords.y, ps.mCoords.toolMajor,
+ ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint);
}
}
}
}
+
+ private void logPointerCoords(MotionEvent.PointerCoords coords, int id) {
+ Log.i(TAG, mText.clear()
+ .append("Pointer ").append(id + 1)
+ .append(": (").append(coords.x, 3).append(", ").append(coords.y, 3)
+ .append(") Pressure=").append(coords.pressure, 3)
+ .append(" Size=").append(coords.size, 3)
+ .append(" TouchMajor=").append(coords.touchMajor, 3)
+ .append(" TouchMinor=").append(coords.touchMinor, 3)
+ .append(" ToolMajor=").append(coords.toolMajor, 3)
+ .append(" ToolMinor=").append(coords.toolMinor, 3)
+ .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1)
+ .append("deg").toString());
+ }
public void addTouchEvent(MotionEvent event) {
synchronized (mPointers) {
int action = event.getAction();
- //Log.i("Pointer", "Motion: action=0x" + Integer.toHexString(action)
+ //Log.i(TAG, "Motion: action=0x" + Integer.toHexString(action)
// + " pointers=" + event.getPointerCount());
int NP = mPointers.size();
@@ -235,35 +333,33 @@ public class PointerLocationView extends View {
//} else {
// mRect.setEmpty();
//}
- if (action == MotionEvent.ACTION_DOWN) {
- mVelocity.clear();
-
- for (int p=0; p<NP; p++) {
- final PointerState ps = mPointers.get(p);
- ps.mXs.clear();
- ps.mYs.clear();
- ps.mCurDown = false;
- }
- mPointers.get(0).mCurDown = true;
- mMaxNumPointers = 0;
- if (mPrintCoords) {
- Log.i("Pointer", "Pointer 1: DOWN");
+ if (action == MotionEvent.ACTION_DOWN
+ || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
+ final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for down
+ if (action == MotionEvent.ACTION_DOWN) {
+ for (int p=0; p<NP; p++) {
+ final PointerState ps = mPointers.get(p);
+ ps.clearTrace();
+ ps.mCurDown = false;
+ }
+ mCurDown = true;
+ mMaxNumPointers = 0;
+ mVelocity.clear();
}
- }
-
- if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_DOWN) {
- final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+
final int id = event.getPointerId(index);
while (NP <= id) {
PointerState ps = new PointerState();
mPointers.add(ps);
NP++;
}
+
final PointerState ps = mPointers.get(id);
ps.mCurDown = true;
if (mPrintCoords) {
- Log.i("Pointer", "Pointer " + (id+1) + ": DOWN");
+ Log.i(TAG, mText.clear().append("Pointer ")
+ .append(id + 1).append(": DOWN").toString());
}
}
@@ -284,58 +380,38 @@ public class PointerLocationView extends View {
final PointerState ps = mPointers.get(id);
final int N = event.getHistorySize();
for (int j=0; j<N; j++) {
+ event.getHistoricalPointerCoords(i, j, ps.mCoords);
if (mPrintCoords) {
- Log.i("Pointer", "Pointer " + (id+1) + ": ("
- + event.getHistoricalX(i, j)
- + ", " + event.getHistoricalY(i, j) + ")"
- + " Prs=" + event.getHistoricalPressure(i, j)
- + " Size=" + event.getHistoricalSize(i, j));
+ logPointerCoords(ps.mCoords, id);
}
- ps.mXs.add(event.getHistoricalX(i, j));
- ps.mYs.add(event.getHistoricalY(i, j));
+ ps.addTrace(event.getHistoricalX(i, j), event.getHistoricalY(i, j));
}
+ event.getPointerCoords(i, ps.mCoords);
if (mPrintCoords) {
- Log.i("Pointer", "Pointer " + (id+1) + ": ("
- + event.getX(i) + ", " + event.getY(i) + ")"
- + " Prs=" + event.getPressure(i)
- + " Size=" + event.getSize(i));
+ logPointerCoords(ps.mCoords, id);
}
- ps.mXs.add(event.getX(i));
- ps.mYs.add(event.getY(i));
- ps.mCurX = (int)event.getX(i);
- ps.mCurY = (int)event.getY(i);
- //Log.i("Pointer", "Pointer #" + p + ": (" + ps.mCurX
- // + "," + ps.mCurY + ")");
- ps.mCurPressure = event.getPressure(i);
- ps.mCurSize = event.getSize(i);
- ps.mCurWidth = (int)(ps.mCurSize*(getWidth()/3));
+ ps.addTrace(ps.mCoords.x, ps.mCoords.y);
ps.mXVelocity = mVelocity.getXVelocity(id);
ps.mYVelocity = mVelocity.getYVelocity(id);
}
- if ((action&MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
- final int index = (action&MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ if (action == MotionEvent.ACTION_UP
+ || (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP) {
+ final int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; // will be 0 for UP
+
final int id = event.getPointerId(index);
final PointerState ps = mPointers.get(id);
- ps.mXs.add(Float.NaN);
- ps.mYs.add(Float.NaN);
ps.mCurDown = false;
if (mPrintCoords) {
- Log.i("Pointer", "Pointer " + (id+1) + ": UP");
+ Log.i(TAG, mText.clear().append("Pointer ")
+ .append(id + 1).append(": UP").toString());
}
- }
-
- if (action == MotionEvent.ACTION_UP) {
- for (int i=0; i<NI; i++) {
- final int id = event.getPointerId(i);
- final PointerState ps = mPointers.get(id);
- if (ps.mCurDown) {
- ps.mCurDown = false;
- if (mPrintCoords) {
- Log.i("Pointer", "Pointer " + (id+1) + ": UP");
- }
- }
+
+ if (action == MotionEvent.ACTION_UP) {
+ mCurDown = false;
+ } else {
+ ps.addTrace(Float.NaN, Float.NaN);
}
}
@@ -356,8 +432,120 @@ public class PointerLocationView extends View {
@Override
public boolean onTrackballEvent(MotionEvent event) {
- Log.i("Pointer", "Trackball: " + event);
+ Log.i(TAG, "Trackball: " + event);
return super.onTrackballEvent(event);
}
+ // HACK
+ // A quick and dirty string builder implementation optimized for GC.
+ // Using the basic StringBuilder implementation causes the application grind to a halt when
+ // more than a couple of pointers are down due to the number of temporary objects allocated
+ // while formatting strings for drawing or logging.
+ private static final class FasterStringBuilder {
+ private char[] mChars;
+ private int mLength;
+
+ public FasterStringBuilder() {
+ mChars = new char[64];
+ }
+
+ public FasterStringBuilder clear() {
+ mLength = 0;
+ return this;
+ }
+
+ public FasterStringBuilder append(String value) {
+ final int valueLength = value.length();
+ final int index = reserve(valueLength);
+ value.getChars(0, valueLength, mChars, index);
+ mLength += valueLength;
+ return this;
+ }
+
+ public FasterStringBuilder append(int value) {
+ return append(value, 0);
+ }
+
+ public FasterStringBuilder append(int value, int zeroPadWidth) {
+ final boolean negative = value < 0;
+ if (negative) {
+ value = - value;
+ if (value < 0) {
+ append("-2147483648");
+ return this;
+ }
+ }
+
+ int index = reserve(11);
+ final char[] chars = mChars;
+
+ if (value == 0) {
+ chars[index++] = '0';
+ mLength += 1;
+ return this;
+ }
+
+ if (negative) {
+ chars[index++] = '-';
+ }
+
+ int divisor = 1000000000;
+ int numberWidth = 10;
+ while (value < divisor) {
+ divisor /= 10;
+ numberWidth -= 1;
+ if (numberWidth < zeroPadWidth) {
+ chars[index++] = '0';
+ }
+ }
+
+ do {
+ int digit = value / divisor;
+ value -= digit * divisor;
+ divisor /= 10;
+ chars[index++] = (char) (digit + '0');
+ } while (divisor != 0);
+
+ mLength = index;
+ return this;
+ }
+
+ public FasterStringBuilder append(float value, int precision) {
+ int scale = 1;
+ for (int i = 0; i < precision; i++) {
+ scale *= 10;
+ }
+ value = (float) (Math.rint(value * scale) / scale);
+
+ append((int) value);
+
+ if (precision != 0) {
+ append(".");
+ value = Math.abs(value);
+ value -= Math.floor(value);
+ append((int) (value * scale), precision);
+ }
+
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return new String(mChars, 0, mLength);
+ }
+
+ private int reserve(int length) {
+ final int oldLength = mLength;
+ final int newLength = mLength + length;
+ final char[] oldChars = mChars;
+ final int oldCapacity = oldChars.length;
+ if (newLength > oldCapacity) {
+ final int newCapacity = oldCapacity * 2;
+ final char[] newChars = new char[newCapacity];
+ System.arraycopy(oldChars, 0, newChars, 0, oldLength);
+ mChars = newChars;
+ }
+ return oldLength;
+ }
+ }
}
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 3d42856..25d5afb 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -82,6 +82,14 @@ struct RawAbsoluteAxisInfo {
int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
inline int32_t getRange() { return maxValue - minValue; }
+
+ inline void clear() {
+ valid = false;
+ minValue = 0;
+ maxValue = 0;
+ flat = 0;
+ fuzz = 0;
+ }
};
/*
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 2385973..49347d3 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -453,6 +453,10 @@ public:
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
inline int32_t getKeyboardType() const { return mKeyboardType; }
+ inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const {
+ return mMotionRanges;
+ }
+
private:
int32_t mId;
String8 mName;
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 56d2765..7a089a4 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -35,6 +35,34 @@ namespace android {
class InputDevice;
class InputMapper;
+/* Describes a virtual key. */
+struct VirtualKeyDefinition {
+ int32_t scanCode;
+
+ // configured position data, specified in display coords
+ int32_t centerX;
+ int32_t centerY;
+ int32_t width;
+ int32_t height;
+};
+
+
+/* Specifies input device calibration settings. */
+class InputDeviceCalibration {
+public:
+ InputDeviceCalibration();
+
+ void clear();
+ void addProperty(const String8& key, const String8& value);
+
+ bool tryGetProperty(const String8& key, String8& outValue) const;
+ bool tryGetProperty(const String8& key, int32_t& outValue) const;
+ bool tryGetProperty(const String8& key, float& outValue) const;
+
+private:
+ KeyedVector<String8, String8> mProperties;
+};
+
/*
* Input reader policy interface.
@@ -73,17 +101,6 @@ public:
ACTION_APP_SWITCH_COMING = 0x00000002,
};
- /* Describes a virtual key. */
- struct VirtualKeyDefinition {
- int32_t scanCode;
-
- // configured position data, specified in display coords
- int32_t centerX;
- int32_t centerY;
- int32_t width;
- int32_t height;
- };
-
/* Gets information about the display with the specified id.
* Returns true if the display info is available, false otherwise.
*/
@@ -135,6 +152,10 @@ public:
virtual void getVirtualKeyDefinitions(const String8& deviceName,
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
+ /* Gets the calibration for an input device. */
+ virtual void getInputDeviceCalibration(const String8& deviceName,
+ InputDeviceCalibration& outCalibration) = 0;
+
/* Gets the excluded device names for the platform. */
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
};
@@ -327,6 +348,10 @@ public:
int32_t getMetaState();
+ inline const InputDeviceCalibration& getCalibration() {
+ return mCalibration;
+ }
+
private:
InputReaderContext* mContext;
int32_t mId;
@@ -338,6 +363,8 @@ private:
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
+
+ InputDeviceCalibration mCalibration;
};
@@ -538,12 +565,12 @@ protected:
}
};
+ // Raw data for a single pointer.
struct PointerData {
uint32_t id;
int32_t x;
int32_t y;
int32_t pressure;
- int32_t size;
int32_t touchMajor;
int32_t touchMinor;
int32_t toolMajor;
@@ -551,6 +578,7 @@ protected:
int32_t orientation;
};
+ // Raw data for a collection of pointers including a pointer id mapping table.
struct TouchData {
uint32_t pointerCount;
PointerData pointers[MAX_POINTERS];
@@ -584,18 +612,82 @@ protected:
bool useAveragingTouchFilter;
} mParameters;
- // Raw axis information.
- struct Axes {
+ // Immutable calibration parameters in parsed form.
+ struct Calibration {
+ // Touch Area
+ enum TouchAreaCalibration {
+ TOUCH_AREA_CALIBRATION_DEFAULT,
+ TOUCH_AREA_CALIBRATION_NONE,
+ TOUCH_AREA_CALIBRATION_GEOMETRIC,
+ TOUCH_AREA_CALIBRATION_PRESSURE,
+ };
+
+ TouchAreaCalibration touchAreaCalibration;
+
+ // Tool Area
+ enum ToolAreaCalibration {
+ TOOL_AREA_CALIBRATION_DEFAULT,
+ TOOL_AREA_CALIBRATION_NONE,
+ TOOL_AREA_CALIBRATION_GEOMETRIC,
+ TOOL_AREA_CALIBRATION_LINEAR,
+ };
+
+ ToolAreaCalibration toolAreaCalibration;
+ bool haveToolAreaLinearScale;
+ float toolAreaLinearScale;
+ bool haveToolAreaLinearBias;
+ float toolAreaLinearBias;
+ bool haveToolAreaIsSummed;
+ int32_t toolAreaIsSummed;
+
+ // Pressure
+ enum PressureCalibration {
+ PRESSURE_CALIBRATION_DEFAULT,
+ PRESSURE_CALIBRATION_NONE,
+ PRESSURE_CALIBRATION_PHYSICAL,
+ PRESSURE_CALIBRATION_AMPLITUDE,
+ };
+ enum PressureSource {
+ PRESSURE_SOURCE_DEFAULT,
+ PRESSURE_SOURCE_PRESSURE,
+ PRESSURE_SOURCE_TOUCH,
+ };
+
+ PressureCalibration pressureCalibration;
+ PressureSource pressureSource;
+ bool havePressureScale;
+ float pressureScale;
+
+ // Size
+ enum SizeCalibration {
+ SIZE_CALIBRATION_DEFAULT,
+ SIZE_CALIBRATION_NONE,
+ SIZE_CALIBRATION_NORMALIZED,
+ };
+
+ SizeCalibration sizeCalibration;
+
+ // Orientation
+ enum OrientationCalibration {
+ ORIENTATION_CALIBRATION_DEFAULT,
+ ORIENTATION_CALIBRATION_NONE,
+ ORIENTATION_CALIBRATION_INTERPOLATED,
+ };
+
+ OrientationCalibration orientationCalibration;
+ } mCalibration;
+
+ // Raw axis information from the driver.
+ struct RawAxes {
RawAbsoluteAxisInfo x;
RawAbsoluteAxisInfo y;
RawAbsoluteAxisInfo pressure;
- RawAbsoluteAxisInfo size;
RawAbsoluteAxisInfo touchMajor;
RawAbsoluteAxisInfo touchMinor;
RawAbsoluteAxisInfo toolMajor;
RawAbsoluteAxisInfo toolMinor;
RawAbsoluteAxisInfo orientation;
- } mAxes;
+ } mRawAxes;
// Current and previous touch sample data.
TouchData mCurrentTouch;
@@ -620,10 +712,13 @@ protected:
float yScale;
float yPrecision;
- int32_t pressureOrigin;
+ float geometricScale;
+
+ float toolAreaLinearScale;
+ float toolAreaLinearBias;
+
float pressureScale;
- int32_t sizeOrigin;
float sizeScale;
float orientationScale;
@@ -632,12 +727,22 @@ protected:
struct OrientedRanges {
InputDeviceInfo::MotionRange x;
InputDeviceInfo::MotionRange y;
+
+ bool havePressure;
InputDeviceInfo::MotionRange pressure;
+
+ bool haveSize;
InputDeviceInfo::MotionRange size;
+
+ bool haveTouchArea;
InputDeviceInfo::MotionRange touchMajor;
InputDeviceInfo::MotionRange touchMinor;
+
+ bool haveToolArea;
InputDeviceInfo::MotionRange toolMajor;
InputDeviceInfo::MotionRange toolMinor;
+
+ bool haveOrientation;
InputDeviceInfo::MotionRange orientation;
} orientedRanges;
@@ -653,9 +758,14 @@ protected:
} currentVirtualKey;
} mLocked;
- virtual void configureAxes();
+ virtual void configureParameters();
+ virtual void configureRawAxes();
+ virtual void logRawAxes();
virtual bool configureSurfaceLocked();
virtual void configureVirtualKeysLocked();
+ virtual void parseCalibration();
+ virtual void resolveCalibration();
+ virtual void logCalibration();
enum TouchResult {
// Dispatch the touch normally.
@@ -713,7 +823,8 @@ private:
TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
- BitSet32 idBits, uint32_t changedId, int32_t motionEventAction);
+ BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
+ int32_t motionEventAction);
void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
int32_t keyEventAction, int32_t keyEventFlags,
@@ -738,7 +849,7 @@ public:
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void configureAxes();
+ virtual void configureRawAxes();
private:
struct Accumulator {
@@ -767,7 +878,7 @@ private:
int32_t mX;
int32_t mY;
int32_t mPressure;
- int32_t mSize;
+ int32_t mToolWidth;
void initialize();
@@ -784,7 +895,7 @@ public:
virtual void process(const RawEvent* rawEvent);
protected:
- virtual void configureAxes();
+ virtual void configureRawAxes();
private:
struct Accumulator {
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 891661d..1d38b4b 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -139,11 +139,7 @@ uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
- outAxisInfo->valid = false;
- outAxisInfo->minValue = 0;
- outAxisInfo->maxValue = 0;
- outAxisInfo->flat = 0;
- outAxisInfo->fuzz = 0;
+ outAxisInfo->clear();
AutoMutex _l(mLock);
device_t* device = getDevice(deviceId);
@@ -709,8 +705,7 @@ int EventHub::open_device(const char *deviceName)
LOGV("Getting absolute controllers...");
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
// Is this a new modern multi-touch driver?
- if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
- && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+ if (test_bit(ABS_MT_POSITION_X, abs_bitmask)
&& test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index e35050c..886c785 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -405,12 +405,15 @@ void InputDispatcher::processMotionLockedInterruptible(
sampleCount += 1;
}
for (uint32_t i = 0; i < entry->pointerCount; i++) {
- LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f",
+ LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
i, entry->pointerIds[i],
- sample->pointerCoords[i].x,
- sample->pointerCoords[i].y,
- sample->pointerCoords[i].pressure,
- sample->pointerCoords[i].size);
+ sample->pointerCoords[i].x, sample->pointerCoords[i].y,
+ sample->pointerCoords[i].pressure, sample->pointerCoords[i].size,
+ sample->pointerCoords[i].touchMajor, sample->pointerCoords[i].touchMinor,
+ sample->pointerCoords[i].toolMajor, sample->pointerCoords[i].toolMinor,
+ sample->pointerCoords[i].orientation);
}
// Keep in mind that due to batching, it is possible for the number of samples actually
@@ -1080,9 +1083,14 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t
eventTime, deviceId, source, policyFlags, action, metaState, edgeFlags,
xPrecision, yPrecision, downTime);
for (uint32_t i = 0; i < pointerCount; i++) {
- LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f",
+ LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
i, pointerIds[i], pointerCoords[i].x, pointerCoords[i].y,
- pointerCoords[i].pressure, pointerCoords[i].size);
+ pointerCoords[i].pressure, pointerCoords[i].size,
+ pointerCoords[i].touchMajor, pointerCoords[i].touchMinor,
+ pointerCoords[i].toolMajor, pointerCoords[i].toolMinor,
+ pointerCoords[i].orientation);
}
#endif
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 6f042ec..8ffb48d 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -26,11 +26,14 @@
#include <ui/InputReader.h>
#include <stddef.h>
+#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
+#define INDENT " "
+
namespace android {
// --- Static Functions ---
@@ -52,6 +55,14 @@ inline static void swap(T& a, T& b) {
b = temp;
}
+inline static float avg(float x, float y) {
+ return (x + y) / 2;
+}
+
+inline static float pythag(float x, float y) {
+ return sqrtf(x * x + y * y);
+}
+
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
@@ -116,6 +127,64 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
}
+// --- InputDeviceCalibration ---
+
+InputDeviceCalibration::InputDeviceCalibration() {
+}
+
+void InputDeviceCalibration::clear() {
+ mProperties.clear();
+}
+
+void InputDeviceCalibration::addProperty(const String8& key, const String8& value) {
+ mProperties.add(key, value);
+}
+
+bool InputDeviceCalibration::tryGetProperty(const String8& key, String8& outValue) const {
+ ssize_t index = mProperties.indexOfKey(key);
+ if (index < 0) {
+ return false;
+ }
+
+ outValue = mProperties.valueAt(index);
+ return true;
+}
+
+bool InputDeviceCalibration::tryGetProperty(const String8& key, int32_t& outValue) const {
+ String8 stringValue;
+ if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+ return false;
+ }
+
+ char* end;
+ int value = strtol(stringValue.string(), & end, 10);
+ if (*end != '\0') {
+ LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.",
+ key.string(), stringValue.string());
+ return false;
+ }
+ outValue = value;
+ return true;
+}
+
+bool InputDeviceCalibration::tryGetProperty(const String8& key, float& outValue) const {
+ String8 stringValue;
+ if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+ return false;
+ }
+
+ char* end;
+ float value = strtof(stringValue.string(), & end);
+ if (*end != '\0') {
+ LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.",
+ key.string(), stringValue.string());
+ return false;
+ }
+ outValue = value;
+ return true;
+}
+
+
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -167,9 +236,18 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
String8 name = mEventHub->getDeviceName(deviceId);
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
+ // Write a log message about the added device as a heading for subsequent log messages.
+ LOGI("Device added: id=0x%x, name=%s", deviceId, name.string());
+
InputDevice* device = createDevice(deviceId, name, classes);
device->configure();
+ if (device->isIgnored()) {
+ LOGI(INDENT "Sources: none (device is ignored)");
+ } else {
+ LOGI(INDENT "Sources: 0x%08x", device->getSources());
+ }
+
bool added = false;
{ // acquire device registry writer lock
RWLock::AutoWLock _wl(mDeviceRegistryLock);
@@ -187,14 +265,6 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
return;
}
- if (device->isIgnored()) {
- LOGI("Device added: id=0x%x, name=%s (ignored non-input device)",
- deviceId, name.string());
- } else {
- LOGI("Device added: id=0x%x, name=%s, sources=%08x",
- deviceId, name.string(), device->getSources());
- }
-
handleConfigurationChanged(when);
}
@@ -217,8 +287,7 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) {
return;
}
- device->reset();
-
+ // Write a log message about the removed device as a heading for subsequent log messages.
if (device->isIgnored()) {
LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
device->getId(), device->getName().string());
@@ -227,6 +296,8 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) {
device->getId(), device->getName().string(), device->getSources());
}
+ device->reset();
+
delete device;
handleConfigurationChanged(when);
@@ -537,6 +608,10 @@ void InputDevice::addMapper(InputMapper* mapper) {
}
void InputDevice::configure() {
+ if (! isIgnored()) {
+ mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);
+ }
+
mSources = 0;
size_t numMappers = mMappers.size();
@@ -1121,13 +1196,35 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x);
info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y);
- info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure);
- info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size);
- info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor);
- info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor);
- info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor);
- info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor);
- info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation);
+
+ if (mLocked.orientedRanges.havePressure) {
+ info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE,
+ mLocked.orientedRanges.pressure);
+ }
+
+ if (mLocked.orientedRanges.haveSize) {
+ info->addMotionRange(AINPUT_MOTION_RANGE_SIZE,
+ mLocked.orientedRanges.size);
+ }
+
+ if (mLocked.orientedRanges.haveTouchArea) {
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR,
+ mLocked.orientedRanges.touchMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR,
+ mLocked.orientedRanges.touchMinor);
+ }
+
+ if (mLocked.orientedRanges.haveToolArea) {
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR,
+ mLocked.orientedRanges.toolMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR,
+ mLocked.orientedRanges.toolMinor);
+ }
+
+ if (mLocked.orientedRanges.haveOrientation) {
+ info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION,
+ mLocked.orientedRanges.orientation);
+ }
} // release lock
}
@@ -1144,77 +1241,72 @@ void TouchInputMapper::initializeLocked() {
mJumpyTouchFilter.jumpyPointsDropped = 0;
mLocked.currentVirtualKey.down = false;
+
+ mLocked.orientedRanges.havePressure = false;
+ mLocked.orientedRanges.haveSize = false;
+ mLocked.orientedRanges.haveTouchArea = false;
+ mLocked.orientedRanges.haveToolArea = false;
+ mLocked.orientedRanges.haveOrientation = false;
+}
+
+static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) {
+ if (axis.valid) {
+ LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d",
+ name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
+ } else {
+ LOGI(INDENT "Raw %s axis: unknown range", name);
+ }
}
void TouchInputMapper::configure() {
InputMapper::configure();
// Configure basic parameters.
- mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
- mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
- mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
+ configureParameters();
// Configure absolute axis information.
- configureAxes();
+ configureRawAxes();
+ logRawAxes();
+
+ // Prepare input device calibration.
+ parseCalibration();
+ resolveCalibration();
+ logCalibration();
{ // acquire lock
AutoMutex _l(mLock);
- // Configure pressure factors.
- if (mAxes.pressure.valid) {
- mLocked.pressureOrigin = mAxes.pressure.minValue;
- mLocked.pressureScale = 1.0f / mAxes.pressure.getRange();
- } else {
- mLocked.pressureOrigin = 0;
- mLocked.pressureScale = 1.0f;
- }
-
- mLocked.orientedRanges.pressure.min = 0.0f;
- mLocked.orientedRanges.pressure.max = 1.0f;
- mLocked.orientedRanges.pressure.flat = 0.0f;
- mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale;
-
- // Configure size factors.
- if (mAxes.size.valid) {
- mLocked.sizeOrigin = mAxes.size.minValue;
- mLocked.sizeScale = 1.0f / mAxes.size.getRange();
- } else {
- mLocked.sizeOrigin = 0;
- mLocked.sizeScale = 1.0f;
- }
-
- mLocked.orientedRanges.size.min = 0.0f;
- mLocked.orientedRanges.size.max = 1.0f;
- mLocked.orientedRanges.size.flat = 0.0f;
- mLocked.orientedRanges.size.fuzz = mLocked.sizeScale;
-
- // Configure orientation factors.
- if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
- mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
- } else {
- mLocked.orientationScale = 0.0f;
- }
-
- mLocked.orientedRanges.orientation.min = - M_PI_2;
- mLocked.orientedRanges.orientation.max = M_PI_2;
- mLocked.orientedRanges.orientation.flat = 0;
- mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale;
-
- // Configure surface dimensions and orientation.
+ // Configure surface dimensions and orientation.
configureSurfaceLocked();
} // release lock
}
-void TouchInputMapper::configureAxes() {
- mAxes.x.valid = false;
- mAxes.y.valid = false;
- mAxes.pressure.valid = false;
- mAxes.size.valid = false;
- mAxes.touchMajor.valid = false;
- mAxes.touchMinor.valid = false;
- mAxes.toolMajor.valid = false;
- mAxes.toolMinor.valid = false;
- mAxes.orientation.valid = false;
+void TouchInputMapper::configureParameters() {
+ mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
+}
+
+void TouchInputMapper::configureRawAxes() {
+ mRawAxes.x.clear();
+ mRawAxes.y.clear();
+ mRawAxes.pressure.clear();
+ mRawAxes.touchMajor.clear();
+ mRawAxes.touchMinor.clear();
+ mRawAxes.toolMajor.clear();
+ mRawAxes.toolMinor.clear();
+ mRawAxes.orientation.clear();
+}
+
+void TouchInputMapper::logRawAxes() {
+ logAxisInfo(mRawAxes.x, "x");
+ logAxisInfo(mRawAxes.y, "y");
+ logAxisInfo(mRawAxes.pressure, "pressure");
+ logAxisInfo(mRawAxes.touchMajor, "touchMajor");
+ logAxisInfo(mRawAxes.touchMinor, "touchMinor");
+ logAxisInfo(mRawAxes.toolMajor, "toolMajor");
+ logAxisInfo(mRawAxes.toolMinor, "toolMinor");
+ logAxisInfo(mRawAxes.orientation, "orientation");
}
bool TouchInputMapper::configureSurfaceLocked() {
@@ -1228,8 +1320,8 @@ bool TouchInputMapper::configureSurfaceLocked() {
}
} else {
orientation = InputReaderPolicyInterface::ROTATION_0;
- width = mAxes.x.getRange();
- height = mAxes.y.getRange();
+ width = mRawAxes.x.getRange();
+ height = mRawAxes.y.getRange();
}
bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1239,24 +1331,24 @@ bool TouchInputMapper::configureSurfaceLocked() {
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
+ LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
+ getDeviceId(), getDeviceName().string());
+
mLocked.surfaceWidth = width;
mLocked.surfaceHeight = height;
- // Compute size-dependent translation and scaling factors and place virtual keys.
- if (mAxes.x.valid && mAxes.y.valid) {
- mLocked.xOrigin = mAxes.x.minValue;
- mLocked.yOrigin = mAxes.y.minValue;
-
- LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
- getDeviceId(), getDeviceName().string());
-
- mLocked.xScale = float(width) / mAxes.x.getRange();
- mLocked.yScale = float(height) / mAxes.y.getRange();
+ // Configure X and Y factors.
+ if (mRawAxes.x.valid && mRawAxes.y.valid) {
+ mLocked.xOrigin = mRawAxes.x.minValue;
+ mLocked.yOrigin = mRawAxes.y.minValue;
+ mLocked.xScale = float(width) / mRawAxes.x.getRange();
+ mLocked.yScale = float(height) / mRawAxes.y.getRange();
mLocked.xPrecision = 1.0f / mLocked.xScale;
mLocked.yPrecision = 1.0f / mLocked.yScale;
configureVirtualKeysLocked();
} else {
+ LOGW(INDENT "Touch device did not report support for X or Y axis!");
mLocked.xOrigin = 0;
mLocked.yOrigin = 0;
mLocked.xScale = 1.0f;
@@ -1265,22 +1357,112 @@ bool TouchInputMapper::configureSurfaceLocked() {
mLocked.yPrecision = 1.0f;
}
- // Configure touch and tool area ranges.
- float diagonal = sqrt(float(width * width + height * height));
- float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale
- + mLocked.yScale * mLocked.yScale);
+ // Scale factor for terms that are not oriented in a particular axis.
+ // If the pixels are square then xScale == yScale otherwise we fake it
+ // by choosing an average.
+ mLocked.geometricScale = avg(mLocked.xScale, mLocked.yScale);
+
+ // Size of diagonal axis.
+ float diagonalSize = pythag(width, height);
+
+ // TouchMajor and TouchMinor factors.
+ if (mCalibration.touchAreaCalibration != Calibration::TOUCH_AREA_CALIBRATION_NONE) {
+ mLocked.orientedRanges.haveTouchArea = true;
+ mLocked.orientedRanges.touchMajor.min = 0;
+ mLocked.orientedRanges.touchMajor.max = diagonalSize;
+ mLocked.orientedRanges.touchMajor.flat = 0;
+ mLocked.orientedRanges.touchMajor.fuzz = 0;
+ mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor;
+ }
+
+ // ToolMajor and ToolMinor factors.
+ if (mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) {
+ mLocked.toolAreaLinearScale = 0;
+ mLocked.toolAreaLinearBias = 0;
+ if (mCalibration.toolAreaCalibration == Calibration::TOOL_AREA_CALIBRATION_LINEAR) {
+ if (mCalibration.haveToolAreaLinearScale) {
+ mLocked.toolAreaLinearScale = mCalibration.toolAreaLinearScale;
+ } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) {
+ mLocked.toolAreaLinearScale = float(min(width, height))
+ / mRawAxes.toolMajor.maxValue;
+ }
+
+ if (mCalibration.haveToolAreaLinearBias) {
+ mLocked.toolAreaLinearBias = mCalibration.toolAreaLinearBias;
+ }
+ }
+
+ mLocked.orientedRanges.haveToolArea = true;
+ mLocked.orientedRanges.toolMajor.min = 0;
+ mLocked.orientedRanges.toolMajor.max = diagonalSize;
+ mLocked.orientedRanges.toolMajor.flat = 0;
+ mLocked.orientedRanges.toolMajor.fuzz = 0;
+ mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor;
+ }
+
+ // Pressure factors.
+ if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) {
+ RawAbsoluteAxisInfo rawPressureAxis;
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ rawPressureAxis = mRawAxes.pressure;
+ break;
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ rawPressureAxis = mRawAxes.touchMajor;
+ break;
+ default:
+ rawPressureAxis.clear();
+ }
+
+ mLocked.pressureScale = 0;
+ if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
+ || mCalibration.pressureCalibration
+ == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
+ if (mCalibration.havePressureScale) {
+ mLocked.pressureScale = mCalibration.pressureScale;
+ } else if (rawPressureAxis.valid && rawPressureAxis.maxValue != 0) {
+ mLocked.pressureScale = 1.0f / rawPressureAxis.maxValue;
+ }
+ }
+
+ mLocked.orientedRanges.havePressure = true;
+ mLocked.orientedRanges.pressure.min = 0;
+ mLocked.orientedRanges.pressure.max = 1.0;
+ mLocked.orientedRanges.pressure.flat = 0;
+ mLocked.orientedRanges.pressure.fuzz = 0;
+ }
+
+ // Size factors.
+ if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
+ mLocked.sizeScale = 0;
+ if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_NORMALIZED) {
+ if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) {
+ mLocked.sizeScale = 1.0f / mRawAxes.toolMajor.maxValue;
+ }
+ }
- InputDeviceInfo::MotionRange area;
- area.min = 0.0f;
- area.max = diagonal;
- area.flat = 0.0f;
- area.fuzz = diagonalFuzz;
+ mLocked.orientedRanges.haveSize = true;
+ mLocked.orientedRanges.size.min = 0;
+ mLocked.orientedRanges.size.max = 1.0;
+ mLocked.orientedRanges.size.flat = 0;
+ mLocked.orientedRanges.size.fuzz = 0;
+ }
- mLocked.orientedRanges.touchMajor = area;
- mLocked.orientedRanges.touchMinor = area;
+ // Orientation
+ if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) {
+ mLocked.orientationScale = 0;
+ if (mCalibration.orientationCalibration
+ == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
+ if (mRawAxes.orientation.valid && mRawAxes.orientation.maxValue != 0) {
+ mLocked.orientationScale = float(M_PI_2) / mRawAxes.orientation.maxValue;
+ }
+ }
- mLocked.orientedRanges.toolMajor = area;
- mLocked.orientedRanges.toolMinor = area;
+ mLocked.orientedRanges.orientation.min = - M_PI_2;
+ mLocked.orientedRanges.orientation.max = M_PI_2;
+ mLocked.orientedRanges.orientation.flat = 0;
+ mLocked.orientedRanges.orientation.fuzz = 0;
+ }
}
if (orientationChanged || sizeChanged) {
@@ -1322,10 +1504,10 @@ bool TouchInputMapper::configureSurfaceLocked() {
}
void TouchInputMapper::configureVirtualKeysLocked() {
- assert(mAxes.x.valid && mAxes.y.valid);
+ assert(mRawAxes.x.valid && mRawAxes.y.valid);
// Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
- Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
+ Vector<VirtualKeyDefinition> virtualKeyDefinitions;
getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
mLocked.virtualKeys.clear();
@@ -1336,13 +1518,13 @@ void TouchInputMapper::configureVirtualKeysLocked() {
mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size());
- int32_t touchScreenLeft = mAxes.x.minValue;
- int32_t touchScreenTop = mAxes.y.minValue;
- int32_t touchScreenWidth = mAxes.x.getRange();
- int32_t touchScreenHeight = mAxes.y.getRange();
+ int32_t touchScreenLeft = mRawAxes.x.minValue;
+ int32_t touchScreenTop = mRawAxes.y.minValue;
+ int32_t touchScreenWidth = mRawAxes.x.getRange();
+ int32_t touchScreenHeight = mRawAxes.y.getRange();
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
- const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+ const VirtualKeyDefinition& virtualKeyDefinition =
virtualKeyDefinitions[i];
mLocked.virtualKeys.add();
@@ -1353,7 +1535,8 @@ void TouchInputMapper::configureVirtualKeysLocked() {
uint32_t flags;
if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
& keyCode, & flags)) {
- LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+ LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
+ virtualKey.scanCode);
mLocked.virtualKeys.pop(); // drop the key
continue;
}
@@ -1374,12 +1557,316 @@ void TouchInputMapper::configureVirtualKeysLocked() {
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
- LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
+ LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
virtualKey.scanCode, virtualKey.keyCode,
virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
}
}
+void TouchInputMapper::parseCalibration() {
+ const InputDeviceCalibration& in = getDevice()->getCalibration();
+ Calibration& out = mCalibration;
+
+ // Touch Area
+ out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_DEFAULT;
+ String8 touchAreaCalibrationString;
+ if (in.tryGetProperty(String8("touch.touchArea.calibration"), touchAreaCalibrationString)) {
+ if (touchAreaCalibrationString == "none") {
+ out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE;
+ } else if (touchAreaCalibrationString == "geometric") {
+ out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC;
+ } else if (touchAreaCalibrationString == "pressure") {
+ out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE;
+ } else if (touchAreaCalibrationString != "default") {
+ LOGW("Invalid value for touch.touchArea.calibration: '%s'",
+ touchAreaCalibrationString.string());
+ }
+ }
+
+ // Tool Area
+ out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_DEFAULT;
+ String8 toolAreaCalibrationString;
+ if (in.tryGetProperty(String8("tool.toolArea.calibration"), toolAreaCalibrationString)) {
+ if (toolAreaCalibrationString == "none") {
+ out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE;
+ } else if (toolAreaCalibrationString == "geometric") {
+ out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC;
+ } else if (toolAreaCalibrationString == "linear") {
+ out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR;
+ } else if (toolAreaCalibrationString != "default") {
+ LOGW("Invalid value for tool.toolArea.calibration: '%s'",
+ toolAreaCalibrationString.string());
+ }
+ }
+
+ out.haveToolAreaLinearScale = in.tryGetProperty(String8("touch.toolArea.linearScale"),
+ out.toolAreaLinearScale);
+ out.haveToolAreaLinearBias = in.tryGetProperty(String8("touch.toolArea.linearBias"),
+ out.toolAreaLinearBias);
+ out.haveToolAreaIsSummed = in.tryGetProperty(String8("touch.toolArea.isSummed"),
+ out.toolAreaIsSummed);
+
+ // Pressure
+ out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
+ String8 pressureCalibrationString;
+ if (in.tryGetProperty(String8("tool.pressure.calibration"), pressureCalibrationString)) {
+ if (pressureCalibrationString == "none") {
+ out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+ } else if (pressureCalibrationString == "physical") {
+ out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
+ } else if (pressureCalibrationString == "amplitude") {
+ out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
+ } else if (pressureCalibrationString != "default") {
+ LOGW("Invalid value for tool.pressure.calibration: '%s'",
+ pressureCalibrationString.string());
+ }
+ }
+
+ out.pressureSource = Calibration::PRESSURE_SOURCE_DEFAULT;
+ String8 pressureSourceString;
+ if (in.tryGetProperty(String8("touch.pressure.source"), pressureSourceString)) {
+ if (pressureSourceString == "pressure") {
+ out.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE;
+ } else if (pressureSourceString == "touch") {
+ out.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH;
+ } else if (pressureSourceString != "default") {
+ LOGW("Invalid value for touch.pressure.source: '%s'",
+ pressureSourceString.string());
+ }
+ }
+
+ out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"),
+ out.pressureScale);
+
+ // Size
+ out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
+ String8 sizeCalibrationString;
+ if (in.tryGetProperty(String8("tool.size.calibration"), sizeCalibrationString)) {
+ if (sizeCalibrationString == "none") {
+ out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+ } else if (sizeCalibrationString == "normalized") {
+ out.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED;
+ } else if (sizeCalibrationString != "default") {
+ LOGW("Invalid value for tool.size.calibration: '%s'",
+ sizeCalibrationString.string());
+ }
+ }
+
+ // Orientation
+ out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
+ String8 orientationCalibrationString;
+ if (in.tryGetProperty(String8("tool.orientation.calibration"), orientationCalibrationString)) {
+ if (orientationCalibrationString == "none") {
+ out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+ } else if (orientationCalibrationString == "interpolated") {
+ out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+ } else if (orientationCalibrationString != "default") {
+ LOGW("Invalid value for tool.orientation.calibration: '%s'",
+ orientationCalibrationString.string());
+ }
+ }
+}
+
+void TouchInputMapper::resolveCalibration() {
+ // Pressure
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_DEFAULT:
+ if (mRawAxes.pressure.valid) {
+ mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE;
+ } else if (mRawAxes.touchMajor.valid) {
+ mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH;
+ }
+ break;
+
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ if (! mRawAxes.pressure.valid) {
+ LOGW("Calibration property touch.pressure.source is 'pressure' but "
+ "the pressure axis is not available.");
+ }
+ break;
+
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ if (! mRawAxes.touchMajor.valid) {
+ LOGW("Calibration property touch.pressure.source is 'touch' but "
+ "the touchMajor axis is not available.");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (mCalibration.pressureCalibration) {
+ case Calibration::PRESSURE_CALIBRATION_DEFAULT:
+ if (mCalibration.pressureSource != Calibration::PRESSURE_SOURCE_DEFAULT) {
+ mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
+ } else {
+ mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Tool Area
+ switch (mCalibration.toolAreaCalibration) {
+ case Calibration::TOOL_AREA_CALIBRATION_DEFAULT:
+ if (mRawAxes.toolMajor.valid) {
+ mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR;
+ } else {
+ mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Touch Area
+ switch (mCalibration.touchAreaCalibration) {
+ case Calibration::TOUCH_AREA_CALIBRATION_DEFAULT:
+ if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE
+ && mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) {
+ mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE;
+ } else {
+ mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Size
+ switch (mCalibration.sizeCalibration) {
+ case Calibration::SIZE_CALIBRATION_DEFAULT:
+ if (mRawAxes.toolMajor.valid) {
+ mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED;
+ } else {
+ mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Orientation
+ switch (mCalibration.orientationCalibration) {
+ case Calibration::ORIENTATION_CALIBRATION_DEFAULT:
+ if (mRawAxes.orientation.valid) {
+ mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+ } else {
+ mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void TouchInputMapper::logCalibration() {
+ // Touch Area
+ switch (mCalibration.touchAreaCalibration) {
+ case Calibration::TOUCH_AREA_CALIBRATION_NONE:
+ LOGI(INDENT " touch.touchArea.calibration: none");
+ break;
+ case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
+ LOGI(INDENT " touch.touchArea.calibration: geometric");
+ break;
+ case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
+ LOGI(INDENT " touch.touchArea.calibration: pressure");
+ break;
+ default:
+ assert(false);
+ }
+
+ // Tool Area
+ switch (mCalibration.toolAreaCalibration) {
+ case Calibration::TOOL_AREA_CALIBRATION_NONE:
+ LOGI(INDENT " touch.toolArea.calibration: none");
+ break;
+ case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
+ LOGI(INDENT " touch.toolArea.calibration: geometric");
+ break;
+ case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
+ LOGI(INDENT " touch.toolArea.calibration: linear");
+ break;
+ default:
+ assert(false);
+ }
+
+ if (mCalibration.haveToolAreaLinearScale) {
+ LOGI(INDENT " touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale);
+ }
+
+ if (mCalibration.haveToolAreaLinearBias) {
+ LOGI(INDENT " touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias);
+ }
+
+ if (mCalibration.haveToolAreaIsSummed) {
+ LOGI(INDENT " touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed);
+ }
+
+ // Pressure
+ switch (mCalibration.pressureCalibration) {
+ case Calibration::PRESSURE_CALIBRATION_NONE:
+ LOGI(INDENT " touch.pressure.calibration: none");
+ break;
+ case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+ LOGI(INDENT " touch.pressure.calibration: physical");
+ break;
+ case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+ LOGI(INDENT " touch.pressure.calibration: amplitude");
+ break;
+ default:
+ assert(false);
+ }
+
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ LOGI(INDENT " touch.pressure.source: pressure");
+ break;
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ LOGI(INDENT " touch.pressure.source: touch");
+ break;
+ case Calibration::PRESSURE_SOURCE_DEFAULT:
+ break;
+ default:
+ assert(false);
+ }
+
+ if (mCalibration.havePressureScale) {
+ LOGI(INDENT " touch.pressure.scale: %f", mCalibration.pressureScale);
+ }
+
+ // Size
+ switch (mCalibration.sizeCalibration) {
+ case Calibration::SIZE_CALIBRATION_NONE:
+ LOGI(INDENT " touch.size.calibration: none");
+ break;
+ case Calibration::SIZE_CALIBRATION_NORMALIZED:
+ LOGI(INDENT " touch.size.calibration: normalized");
+ break;
+ default:
+ assert(false);
+ }
+
+ // Orientation
+ switch (mCalibration.orientationCalibration) {
+ case Calibration::ORIENTATION_CALIBRATION_NONE:
+ LOGI(INDENT " touch.orientation.calibration: none");
+ break;
+ case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+ LOGI(INDENT " touch.orientation.calibration: interpolated");
+ break;
+ default:
+ assert(false);
+ }
+}
+
void TouchInputMapper::reset() {
// Synthesize touch up event if touch is currently down.
// This will also take care of finishing virtual key processing if needed.
@@ -1584,13 +2071,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
// The dispatcher takes care of batching moves so we don't have to deal with that here.
int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
dispatchTouch(when, policyFlags, & mCurrentTouch,
- currentIdBits, -1, motionEventAction);
+ currentIdBits, -1, currentPointerCount, motionEventAction);
} else {
// There may be pointers going up and pointers going down at the same time when pointer
// ids are reported by the device driver.
BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value);
BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value);
BitSet32 activeIdBits(lastIdBits.value);
+ uint32_t pointerCount = lastPointerCount;
while (! upIdBits.isEmpty()) {
uint32_t upId = upIdBits.firstMarkedBit();
@@ -1606,7 +2094,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
}
dispatchTouch(when, policyFlags, & mLastTouch,
- oldActiveIdBits, upId, motionEventAction);
+ oldActiveIdBits, upId, pointerCount, motionEventAction);
+ pointerCount -= 1;
}
while (! downIdBits.isEmpty()) {
@@ -1623,16 +2112,16 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN;
}
+ pointerCount += 1;
dispatchTouch(when, policyFlags, & mCurrentTouch,
- activeIdBits, downId, motionEventAction);
+ activeIdBits, downId, pointerCount, motionEventAction);
}
}
}
void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
- TouchData* touch, BitSet32 idBits, uint32_t changedId,
+ TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
int32_t motionEventAction) {
- uint32_t pointerCount = 0;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
int32_t motionEventEdgeFlags = 0;
@@ -1643,36 +2132,130 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
// Walk through the the active pointers and map touch screen coordinates (TouchData) into
// display coordinates (PointerCoords) and adjust for display orientation.
- while (! idBits.isEmpty()) {
+ for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
- uint32_t index = touch->idToIndex[id];
-
- float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale;
- float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale;
- float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin)
- * mLocked.pressureScale;
- float size = float(touch->pointers[index].size - mLocked.sizeOrigin)
- * mLocked.sizeScale;
-
- float orientation = float(touch->pointers[index].orientation)
- * mLocked.orientationScale;
-
- float touchMajor, touchMinor, toolMajor, toolMinor;
- if (abs(orientation) <= M_PI_4) {
- // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
- touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale;
- touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale;
- toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale;
- toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale;
- } else {
- // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
- touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale;
- touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale;
- toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale;
- toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale;
+ uint32_t inIndex = touch->idToIndex[id];
+
+ const PointerData& in = touch->pointers[inIndex];
+
+ // X and Y
+ float x = float(in.x - mLocked.xOrigin) * mLocked.xScale;
+ float y = float(in.y - mLocked.yOrigin) * mLocked.yScale;
+
+ // ToolMajor and ToolMinor
+ float toolMajor, toolMinor;
+ switch (mCalibration.toolAreaCalibration) {
+ case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC:
+ toolMajor = in.toolMajor * mLocked.geometricScale;
+ if (mRawAxes.toolMinor.valid) {
+ toolMinor = in.toolMinor * mLocked.geometricScale;
+ } else {
+ toolMinor = toolMajor;
+ }
+ break;
+ case Calibration::TOOL_AREA_CALIBRATION_LINEAR:
+ toolMajor = in.toolMajor != 0
+ ? in.toolMajor * mLocked.toolAreaLinearScale + mLocked.toolAreaLinearBias
+ : 0;
+ if (mRawAxes.toolMinor.valid) {
+ toolMinor = in.toolMinor != 0
+ ? in.toolMinor * mLocked.toolAreaLinearScale
+ + mLocked.toolAreaLinearBias
+ : 0;
+ } else {
+ toolMinor = toolMajor;
+ }
+ break;
+ default:
+ toolMajor = 0;
+ toolMinor = 0;
+ break;
+ }
+
+ if (mCalibration.haveToolAreaIsSummed && mCalibration.toolAreaIsSummed) {
+ toolMajor /= pointerCount;
+ toolMinor /= pointerCount;
+ }
+
+ // Pressure
+ float rawPressure;
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ rawPressure = in.pressure;
+ break;
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ rawPressure = in.touchMajor;
+ break;
+ default:
+ rawPressure = 0;
+ }
+
+ float pressure;
+ switch (mCalibration.pressureCalibration) {
+ case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+ case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+ pressure = rawPressure * mLocked.pressureScale;
+ break;
+ default:
+ pressure = 1;
+ break;
+ }
+
+ // TouchMajor and TouchMinor
+ float touchMajor, touchMinor;
+ switch (mCalibration.touchAreaCalibration) {
+ case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC:
+ touchMajor = in.touchMajor * mLocked.geometricScale;
+ if (mRawAxes.touchMinor.valid) {
+ touchMinor = in.touchMinor * mLocked.geometricScale;
+ } else {
+ touchMinor = touchMajor;
+ }
+ break;
+ case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE:
+ touchMajor = toolMajor * pressure;
+ touchMinor = toolMinor * pressure;
+ break;
+ default:
+ touchMajor = 0;
+ touchMinor = 0;
+ break;
+ }
+
+ if (touchMajor > toolMajor) {
+ touchMajor = toolMajor;
+ }
+ if (touchMinor > toolMinor) {
+ touchMinor = toolMinor;
+ }
+
+ // Size
+ float size;
+ switch (mCalibration.sizeCalibration) {
+ case Calibration::SIZE_CALIBRATION_NORMALIZED: {
+ float rawSize = mRawAxes.toolMinor.valid
+ ? avg(in.toolMajor, in.toolMinor)
+ : in.toolMajor;
+ size = rawSize * mLocked.sizeScale;
+ break;
+ }
+ default:
+ size = 0;
+ break;
}
+ // Orientation
+ float orientation;
+ switch (mCalibration.orientationCalibration) {
+ case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+ orientation = in.orientation * mLocked.orientationScale;
+ break;
+ default:
+ orientation = 0;
+ }
+
+ // Adjust coords for orientation.
switch (mLocked.surfaceOrientation) {
case InputReaderPolicyInterface::ROTATION_90: {
float xTemp = x;
@@ -1702,23 +2285,23 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
}
}
- pointerIds[pointerCount] = int32_t(id);
+ // Write output coords.
+ PointerCoords& out = pointerCoords[outIndex];
+ out.x = x;
+ out.y = y;
+ out.pressure = pressure;
+ out.size = size;
+ out.touchMajor = touchMajor;
+ out.touchMinor = touchMinor;
+ out.toolMajor = toolMajor;
+ out.toolMinor = toolMinor;
+ out.orientation = orientation;
- pointerCoords[pointerCount].x = x;
- pointerCoords[pointerCount].y = y;
- pointerCoords[pointerCount].pressure = pressure;
- pointerCoords[pointerCount].size = size;
- pointerCoords[pointerCount].touchMajor = touchMajor;
- pointerCoords[pointerCount].touchMinor = touchMinor;
- pointerCoords[pointerCount].toolMajor = toolMajor;
- pointerCoords[pointerCount].toolMinor = toolMinor;
- pointerCoords[pointerCount].orientation = orientation;
+ pointerIds[outIndex] = int32_t(id);
if (id == changedId) {
- motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
-
- pointerCount += 1;
}
// Check edge flags by looking only at the first pointer since the flags are
@@ -1747,9 +2330,9 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
}
bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
- if (mAxes.x.valid && mAxes.y.valid) {
- return x >= mAxes.x.minValue && x <= mAxes.x.maxValue
- && y >= mAxes.y.minValue && y <= mAxes.y.maxValue;
+ if (mRawAxes.x.valid && mRawAxes.y.valid) {
+ return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
+ && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
}
return true;
}
@@ -1960,7 +2543,7 @@ void TouchInputMapper::calculatePointerIds() {
* then drop it. */
bool TouchInputMapper::applyBadTouchFilter() {
// This hack requires valid axis parameters.
- if (! mAxes.y.valid) {
+ if (! mRawAxes.y.valid) {
return false;
}
@@ -1982,7 +2565,7 @@ bool TouchInputMapper::applyBadTouchFilter() {
// 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.
- int32_t maxDeltaY = mAxes.y.getRange() * 7 / 16;
+ int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16;
// XXX The original code in InputDevice.java included commented out
// code for testing the X axis. Note that when we drop a point
@@ -2044,7 +2627,7 @@ bool TouchInputMapper::applyBadTouchFilter() {
*/
bool TouchInputMapper::applyJumpyTouchFilter() {
// This hack requires valid axis parameters.
- if (! mAxes.y.valid) {
+ if (! mRawAxes.y.valid) {
return false;
}
@@ -2104,7 +2687,7 @@ bool TouchInputMapper::applyJumpyTouchFilter() {
}
if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
- int jumpyEpsilon = mAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
+ int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
// We only replace the single worst jumpy point as characterized by pointer distance
// in a single axis.
@@ -2209,7 +2792,18 @@ void TouchInputMapper::applyAveragingTouchFilter() {
uint32_t id = mCurrentTouch.pointers[currentIndex].id;
int32_t x = mCurrentTouch.pointers[currentIndex].x;
int32_t y = mCurrentTouch.pointers[currentIndex].y;
- int32_t pressure = mCurrentTouch.pointers[currentIndex].pressure;
+ int32_t pressure;
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ pressure = mCurrentTouch.pointers[currentIndex].pressure;
+ break;
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ pressure = mCurrentTouch.pointers[currentIndex].touchMajor;
+ break;
+ default:
+ pressure = 1;
+ break;
+ }
if (mLastTouch.idBits.hasBit(id)) {
// Pointer was down before and is still down now.
@@ -2274,17 +2868,19 @@ void TouchInputMapper::applyAveragingTouchFilter() {
}
}
- averagedX /= totalPressure;
- averagedY /= totalPressure;
+ if (totalPressure != 0) {
+ averagedX /= totalPressure;
+ averagedY /= totalPressure;
#if DEBUG_HACKS
- LOGD("AveragingTouchFilter: Pointer id %d - "
- "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
- averagedX, averagedY);
+ LOGD("AveragingTouchFilter: Pointer id %d - "
+ "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
+ averagedX, averagedY);
#endif
- mCurrentTouch.pointers[currentIndex].x = averagedX;
- mCurrentTouch.pointers[currentIndex].y = averagedY;
+ mCurrentTouch.pointers[currentIndex].x = averagedX;
+ mCurrentTouch.pointers[currentIndex].y = averagedY;
+ }
} else {
#if DEBUG_HACKS
LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
@@ -2382,8 +2978,8 @@ void SingleTouchInputMapper::initialize() {
mDown = false;
mX = 0;
mY = 0;
- mPressure = 1; // default to 1 for devices that don't report pressure
- mSize = 0; // default to 0 for devices that don't report size
+ mPressure = 0; // default to 0 for devices that don't report pressure
+ mToolWidth = 0; // default to 0 for devices that don't report tool width
}
void SingleTouchInputMapper::reset() {
@@ -2460,7 +3056,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
}
if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) {
- mSize = mAccumulator.absToolWidth;
+ mToolWidth = mAccumulator.absToolWidth;
}
mCurrentTouch.clear();
@@ -2471,11 +3067,10 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
mCurrentTouch.pointers[0].x = mX;
mCurrentTouch.pointers[0].y = mY;
mCurrentTouch.pointers[0].pressure = mPressure;
- mCurrentTouch.pointers[0].size = mSize;
- mCurrentTouch.pointers[0].touchMajor = mSize;
- mCurrentTouch.pointers[0].touchMinor = mSize;
- mCurrentTouch.pointers[0].toolMajor = mSize;
- mCurrentTouch.pointers[0].toolMinor = mSize;
+ mCurrentTouch.pointers[0].touchMajor = 0;
+ mCurrentTouch.pointers[0].touchMinor = 0;
+ mCurrentTouch.pointers[0].toolMajor = mToolWidth;
+ mCurrentTouch.pointers[0].toolMinor = mToolWidth;
mCurrentTouch.pointers[0].orientation = 0;
mCurrentTouch.idToIndex[0] = 0;
mCurrentTouch.idBits.markBit(0);
@@ -2486,20 +3081,13 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
mAccumulator.clear();
}
-void SingleTouchInputMapper::configureAxes() {
- TouchInputMapper::configureAxes();
-
- // The axes are aliased to take into account the manner in which they are presented
- // as part of the TouchData during the sync.
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mAxes.x);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mAxes.y);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
+void SingleTouchInputMapper::configureRawAxes() {
+ TouchInputMapper::configureRawAxes();
- mAxes.touchMajor = mAxes.size;
- mAxes.touchMinor = mAxes.size;
- mAxes.toolMajor = mAxes.size;
- mAxes.toolMinor = mAxes.size;
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mRawAxes.pressure);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mRawAxes.toolMajor);
}
@@ -2562,6 +3150,10 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
pointer->absMTTrackingId = rawEvent->value;
break;
+ case ABS_MT_PRESSURE:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;
+ pointer->absMTPressure = rawEvent->value;
+ break;
}
break;
}
@@ -2596,8 +3188,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
void MultiTouchInputMapper::sync(nsecs_t when) {
static const uint32_t REQUIRED_FIELDS =
- Accumulator::FIELD_ABS_MT_POSITION_X
- | Accumulator::FIELD_ABS_MT_POSITION_Y;
+ Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y;
uint32_t inCount = mAccumulator.pointerCount;
uint32_t outCount = 0;
@@ -2619,60 +3210,59 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
outPointer.x = inPointer.absMTPositionX;
outPointer.y = inPointer.absMTPositionY;
+ if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
+ if (inPointer.absMTPressure <= 0) {
+ // Some devices send sync packets with X / Y but with a 0 presure to indicate
+ // a pointer up. Drop this finger.
+ continue;
+ }
+ outPointer.pressure = inPointer.absMTPressure;
+ } else {
+ // Default pressure to 0 if absent.
+ outPointer.pressure = 0;
+ }
+
if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
- int32_t value = inPointer.absMTTouchMajor;
- if (value <= 0) {
+ if (inPointer.absMTTouchMajor <= 0) {
// Some devices send sync packets with X / Y but with a 0 touch major to indicate
- // a pointer up. Drop this finger.
+ // a pointer going up. Drop this finger.
continue;
}
outPointer.touchMajor = inPointer.absMTTouchMajor;
} else {
+ // Default touch area to 0 if absent.
outPointer.touchMajor = 0;
}
if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
outPointer.touchMinor = inPointer.absMTTouchMinor;
} else {
+ // Assume touch area is circular.
outPointer.touchMinor = outPointer.touchMajor;
}
if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
outPointer.toolMajor = inPointer.absMTWidthMajor;
} else {
- outPointer.toolMajor = outPointer.touchMajor;
+ // Default tool area to 0 if absent.
+ outPointer.toolMajor = 0;
}
if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
outPointer.toolMinor = inPointer.absMTWidthMinor;
} else {
+ // Assume tool area is circular.
outPointer.toolMinor = outPointer.toolMajor;
}
if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
outPointer.orientation = inPointer.absMTOrientation;
} else {
+ // Default orientation to vertical if absent.
outPointer.orientation = 0;
}
- if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
- outPointer.pressure = inPointer.absMTPressure;
- } else {
- // Derive an approximation of pressure.
- // FIXME Traditionally we have just passed a normalized value based on
- // ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not
- // very meaningful, particularly on large displays. We should probably let
- // pressure = touch_major / tool_major but it is unclear whether that will
- // break applications.
- outPointer.pressure = outPointer.touchMajor;
- }
-
- // Size is an alias for a normalized tool width.
- // FIXME Normalized tool width doesn't actually make much sense since it literally
- // means the approaching contact major axis is divided by its full range as
- // reported by the driver. On a large display this could produce very small values.
- outPointer.size = outPointer.toolMajor;
-
+ // Assign pointer id using tracking id if available.
if (havePointerIds) {
if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
uint32_t id = uint32_t(inPointer.absMTTrackingId);
@@ -2705,33 +3295,17 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
mAccumulator.clear();
}
-void MultiTouchInputMapper::configureAxes() {
- TouchInputMapper::configureAxes();
-
- // The axes are aliased to take into account the manner in which they are presented
- // as part of the TouchData during the sync.
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mAxes.x);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mAxes.y);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mAxes.touchMajor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mAxes.touchMinor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure);
-
- if (! mAxes.touchMinor.valid) {
- mAxes.touchMinor = mAxes.touchMajor;
- }
-
- if (! mAxes.toolMinor.valid) {
- mAxes.toolMinor = mAxes.toolMajor;
- }
-
- if (! mAxes.pressure.valid) {
- mAxes.pressure = mAxes.touchMajor;
- }
+void MultiTouchInputMapper::configureRawAxes() {
+ TouchInputMapper::configureRawAxes();
- mAxes.size = mAxes.toolMajor;
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mRawAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mRawAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mRawAxes.touchMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mRawAxes.touchMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mRawAxes.toolMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mRawAxes.toolMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mRawAxes.orientation);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mRawAxes.pressure);
}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 243c33c..d9486e5 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -718,8 +718,6 @@ int32_t AInputDevice_getKeyboardType(AInputDevice* device);
int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType,
float* outMin, float* outMax, float* outFlat, float* outFuzz);
-//TODO hasKey, keymap stuff, etc...
-
#ifdef __cplusplus
}
#endif
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index f330d40..314dd8a 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -30,6 +30,7 @@ import android.os.SystemProperties;
import android.util.Slog;
import android.util.Xml;
import android.view.InputChannel;
+import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -45,6 +46,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Properties;
/*
* Wraps the C++ InputManager and provides its callbacks.
@@ -82,6 +84,8 @@ public class InputManager {
private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
private static native void nativeSetFocusedApplication(InputApplication application);
private static native void nativePreemptInputDispatch();
+ private static native InputDevice nativeGetInputDevice(int deviceId);
+ private static native int[] nativeGetInputDeviceIds();
private static native String nativeDump();
// Input event injection constants defined in InputDispatcher.h.
@@ -302,6 +306,23 @@ public class InputManager {
return nativeInjectInputEvent(event, injectorPid, injectorUid, syncMode, timeoutMillis);
}
+ /**
+ * Gets information about the input device with the specified id.
+ * @param id The device id.
+ * @return The input device or null if not found.
+ */
+ public InputDevice getInputDevice(int deviceId) {
+ return nativeGetInputDevice(deviceId);
+ }
+
+ /**
+ * Gets the ids of all input devices in the system.
+ * @return The input device ids.
+ */
+ public int[] getInputDeviceIds() {
+ return nativeGetInputDeviceIds();
+ }
+
public void setInputWindows(InputWindow[] windows) {
nativeSetInputWindows(windows);
}
@@ -335,6 +356,11 @@ public class InputManager {
public int height;
}
+ private static final class InputDeviceCalibration {
+ public String[] keys;
+ public String[] values;
+ }
+
/*
* Callbacks from native.
*/
@@ -343,6 +369,7 @@ public class InputManager {
private static final boolean DEBUG_VIRTUAL_KEYS = false;
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
+ private static final String CALIBRATION_DIR_PATH = "usr/idc/";
@SuppressWarnings("unused")
public void virtualKeyDownFeedback() {
@@ -438,8 +465,8 @@ public class InputManager {
final int N = it.length-6;
for (int i=0; i<=N; i+=6) {
if (!"0x01".equals(it[i])) {
- Slog.w(TAG, "Unknown virtual key type at elem #" + i
- + ": " + it[i]);
+ Slog.w(TAG, "Unknown virtual key type at elem #"
+ + i + ": " + it[i] + " for device " + deviceName);
continue;
}
try {
@@ -455,22 +482,47 @@ public class InputManager {
+ key.height);
keys.add(key);
} catch (NumberFormatException e) {
- Slog.w(TAG, "Bad number at region " + i + " in: "
- + str, e);
+ Slog.w(TAG, "Bad number in virtual key definition at region "
+ + i + " in: " + str + " for device " + deviceName, e);
}
}
}
br.close();
} catch (FileNotFoundException e) {
- Slog.i(TAG, "No virtual keys found");
+ Slog.i(TAG, "No virtual keys found for device " + deviceName + ".");
} catch (IOException e) {
- Slog.w(TAG, "Error reading virtual keys", e);
+ Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e);
}
return keys.toArray(new VirtualKeyDefinition[keys.size()]);
}
@SuppressWarnings("unused")
+ public InputDeviceCalibration getInputDeviceCalibration(String deviceName) {
+ // Calibration is specified as a sequence of colon-delimited key value pairs.
+ Properties properties = new Properties();
+ File calibrationFile = new File(Environment.getRootDirectory(),
+ CALIBRATION_DIR_PATH + deviceName + ".idc");
+ if (calibrationFile.exists()) {
+ try {
+ properties.load(new FileInputStream(calibrationFile));
+ } catch (IOException ex) {
+ Slog.w(TAG, "Error reading input device calibration properties for device "
+ + deviceName + " from " + calibrationFile + ".", ex);
+ }
+ } else {
+ Slog.i(TAG, "No input device calibration properties found for device "
+ + deviceName + ".");
+ return null;
+ }
+
+ InputDeviceCalibration calibration = new InputDeviceCalibration();
+ calibration.keys = properties.keySet().toArray(new String[properties.size()]);
+ calibration.values = properties.values().toArray(new String[properties.size()]);
+ return calibration;
+ }
+
+ @SuppressWarnings("unused")
public String[] getExcludedDeviceNames() {
ArrayList<String> names = new ArrayList<String>();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9b9d950..3841f75 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -4392,6 +4392,14 @@ public class WindowManagerService extends IWindowManager.Stub
return mInputManager.monitorInput(inputChannelName);
}
+ public InputDevice getInputDevice(int deviceId) {
+ return mInputManager.getInputDevice(deviceId);
+ }
+
+ public int[] getInputDeviceIds() {
+ return mInputManager.getInputDeviceIds();
+ }
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (mSystemBooted) {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 3addc0d..a237ee9 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -138,6 +138,7 @@ static struct {
jmethodID filterTouchEvents;
jmethodID filterJumpyTouchEvents;
jmethodID getVirtualKeyDefinitions;
+ jmethodID getInputDeviceCalibration;
jmethodID getExcludedDeviceNames;
jmethodID getMaxEventsPerSecond;
} gCallbacksClassInfo;
@@ -155,6 +156,13 @@ static struct {
static struct {
jclass clazz;
+ jfieldID keys;
+ jfieldID values;
+} gInputDeviceCalibrationClassInfo;
+
+static struct {
+ jclass clazz;
+
jfieldID inputChannel;
jfieldID layoutParamsFlags;
jfieldID layoutParamsType;
@@ -189,6 +197,19 @@ static struct {
jclass clazz;
} gMotionEventClassInfo;
+static struct {
+ jclass clazz;
+
+ jmethodID ctor;
+ jmethodID addMotionRange;
+
+ jfieldID mId;
+ jfieldID mName;
+ jfieldID mSources;
+ jfieldID mKeyboardType;
+ jfieldID mMotionRanges;
+} gInputDeviceClassInfo;
+
// ----------------------------------------------------------------------------
static inline nsecs_t now() {
@@ -235,7 +256,9 @@ public:
virtual bool filterTouchEvents();
virtual bool filterJumpyTouchEvents();
virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions);
+ Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
+ virtual void getInputDeviceCalibration(const String8& deviceName,
+ InputDeviceCalibration& outCalibration);
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -761,7 +784,9 @@ bool NativeInputManager::filterJumpyTouchEvents() {
}
void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName,
- Vector<InputReaderPolicyInterface::VirtualKeyDefinition>& outVirtualKeyDefinitions) {
+ Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) {
+ outVirtualKeyDefinitions.clear();
+
JNIEnv* env = jniEnv();
jstring deviceNameStr = env->NewStringUTF(deviceName.string());
@@ -793,7 +818,51 @@ void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName,
}
}
+void NativeInputManager::getInputDeviceCalibration(const String8& deviceName,
+ InputDeviceCalibration& outCalibration) {
+ outCalibration.clear();
+
+ JNIEnv* env = jniEnv();
+
+ jstring deviceNameStr = env->NewStringUTF(deviceName.string());
+ if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration")) {
+ jobject result = env->CallObjectMethod(mCallbacksObj,
+ gCallbacksClassInfo.getInputDeviceCalibration, deviceNameStr);
+ if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration") && result) {
+ jobjectArray keys = jobjectArray(env->GetObjectField(result,
+ gInputDeviceCalibrationClassInfo.keys));
+ jobjectArray values = jobjectArray(env->GetObjectField(result,
+ gInputDeviceCalibrationClassInfo.values));
+
+ jsize length = env->GetArrayLength(keys);
+ for (jsize i = 0; i < length; i++) {
+ jstring keyStr = jstring(env->GetObjectArrayElement(keys, i));
+ jstring valueStr = jstring(env->GetObjectArrayElement(values, i));
+
+ const char* keyChars = env->GetStringUTFChars(keyStr, NULL);
+ String8 key(keyChars);
+ env->ReleaseStringUTFChars(keyStr, keyChars);
+
+ const char* valueChars = env->GetStringUTFChars(valueStr, NULL);
+ String8 value(valueChars);
+ env->ReleaseStringUTFChars(valueStr, valueChars);
+
+ outCalibration.addProperty(key, value);
+
+ env->DeleteLocalRef(keyStr);
+ env->DeleteLocalRef(valueStr);
+ }
+ env->DeleteLocalRef(keys);
+ env->DeleteLocalRef(values);
+ env->DeleteLocalRef(result);
+ }
+ env->DeleteLocalRef(deviceNameStr);
+ }
+}
+
void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
+ outExcludedDeviceNames.clear();
+
JNIEnv* env = jniEnv();
jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj,
@@ -2199,6 +2268,66 @@ static void android_server_InputManager_nativePreemptInputDispatch(JNIEnv* env,
gNativeInputManager->preemptInputDispatch();
}
+static jobject android_server_InputManager_nativeGetInputDevice(JNIEnv* env,
+ jclass clazz, jint deviceId) {
+ if (checkInputManagerUnitialized(env)) {
+ return NULL;
+ }
+
+ InputDeviceInfo deviceInfo;
+ status_t status = gNativeInputManager->getInputManager()->getInputDeviceInfo(
+ deviceId, & deviceInfo);
+ if (status) {
+ return NULL;
+ }
+
+ jobject deviceObj = env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor);
+ if (! deviceObj) {
+ return NULL;
+ }
+
+ jstring deviceNameObj = env->NewStringUTF(deviceInfo.getName().string());
+ if (! deviceNameObj) {
+ return NULL;
+ }
+
+ env->SetIntField(deviceObj, gInputDeviceClassInfo.mId, deviceInfo.getId());
+ env->SetObjectField(deviceObj, gInputDeviceClassInfo.mName, deviceNameObj);
+ env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
+ env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
+
+ const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+ for (size_t i = 0; i < ranges.size(); i++) {
+ int rangeType = ranges.keyAt(i);
+ const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
+ env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
+ rangeType, range.min, range.max, range.flat, range.fuzz);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ }
+
+ return deviceObj;
+}
+
+static jintArray android_server_InputManager_nativeGetInputDeviceIds(JNIEnv* env,
+ jclass clazz) {
+ if (checkInputManagerUnitialized(env)) {
+ return NULL;
+ }
+
+ Vector<int> deviceIds;
+ gNativeInputManager->getInputManager()->getInputDeviceIds(deviceIds);
+
+ jintArray deviceIdsObj = env->NewIntArray(deviceIds.size());
+ if (! deviceIdsObj) {
+ return NULL;
+ }
+
+ env->SetIntArrayRegion(deviceIdsObj, 0, deviceIds.size(), deviceIds.array());
+ return deviceIdsObj;
+}
+
static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) {
if (checkInputManagerUnitialized(env)) {
return NULL;
@@ -2242,6 +2371,10 @@ static JNINativeMethod gInputManagerMethods[] = {
(void*) android_server_InputManager_nativeSetInputDispatchMode },
{ "nativePreemptInputDispatch", "()V",
(void*) android_server_InputManager_nativePreemptInputDispatch },
+ { "nativeGetInputDevice", "(I)Landroid/view/InputDevice;",
+ (void*) android_server_InputManager_nativeGetInputDevice },
+ { "nativeGetInputDeviceIds", "()[I",
+ (void*) android_server_InputManager_nativeGetInputDeviceIds },
{ "nativeDump", "()Ljava/lang/String;",
(void*) android_server_InputManager_nativeDump },
};
@@ -2311,6 +2444,10 @@ int register_android_server_InputManager(JNIEnv* env) {
"getVirtualKeyDefinitions",
"(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;");
+ GET_METHOD_ID(gCallbacksClassInfo.getInputDeviceCalibration, gCallbacksClassInfo.clazz,
+ "getInputDeviceCalibration",
+ "(Ljava/lang/String;)Lcom/android/server/InputManager$InputDeviceCalibration;");
+
GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
"getExcludedDeviceNames", "()[Ljava/lang/String;");
@@ -2337,6 +2474,17 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
"height", "I");
+ // InputDeviceCalibration
+
+ FIND_CLASS(gInputDeviceCalibrationClassInfo.clazz,
+ "com/android/server/InputManager$InputDeviceCalibration");
+
+ GET_FIELD_ID(gInputDeviceCalibrationClassInfo.keys, gInputDeviceCalibrationClassInfo.clazz,
+ "keys", "[Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputDeviceCalibrationClassInfo.values, gInputDeviceCalibrationClassInfo.clazz,
+ "values", "[Ljava/lang/String;");
+
// InputWindow
FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
@@ -2407,10 +2555,35 @@ int register_android_server_InputManager(JNIEnv* env) {
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
- // MotionEVent
+ // MotionEvent
FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+ // InputDevice
+
+ FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
+
+ GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
+ "<init>", "()V");
+
+ GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
+ "addMotionRange", "(IFFFF)V");
+
+ GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
+ "mId", "I");
+
+ GET_FIELD_ID(gInputDeviceClassInfo.mName, gInputDeviceClassInfo.clazz,
+ "mName", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputDeviceClassInfo.mSources, gInputDeviceClassInfo.clazz,
+ "mSources", "I");
+
+ GET_FIELD_ID(gInputDeviceClassInfo.mKeyboardType, gInputDeviceClassInfo.clazz,
+ "mKeyboardType", "I");
+
+ GET_FIELD_ID(gInputDeviceClassInfo.mMotionRanges, gInputDeviceClassInfo.clazz,
+ "mMotionRanges", "[Landroid/view/InputDevice$MotionRange;");
+
return 0;
}