Input device calibration and capabilities.

Finished the input device capability API.
Added a mechanism for calibrating touch devices to obtain more
accurate information about the touch contact area.
Improved pointer location to show new coordinates and capabilities.
Optimized pointer location display and formatting to avoid allocating large
numbers of temporary objects.  The GC churn was causing the application to
stutter very badly when more than a couple of fingers were down).
Added more diagnostics.

Change-Id: Ie25380278ed6f16c5b04cd9df848015850383498
This commit is contained in:
Jeff Brown
2010-08-30 03:02:23 -07:00
parent bb660d7e1b
commit 8d60866e21
15 changed files with 1775 additions and 431 deletions

View File

@@ -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"

View File

@@ -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);

View File

@@ -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;

View File

@@ -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");
}
}
}

View File

@@ -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();
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();
}
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_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;
}
}
}

View File

@@ -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;
}
};
/*

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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,21 +482,46 @@ 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>();

View File

@@ -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) {

View File

@@ -138,6 +138,7 @@ static struct {
jmethodID filterTouchEvents;
jmethodID filterJumpyTouchEvents;
jmethodID getVirtualKeyDefinitions;
jmethodID getInputDeviceCalibration;
jmethodID getExcludedDeviceNames;
jmethodID getMaxEventsPerSecond;
} gCallbacksClassInfo;
@@ -152,6 +153,13 @@ static struct {
jfieldID height;
} gVirtualKeyDefinitionClassInfo;
static struct {
jclass clazz;
jfieldID keys;
jfieldID values;
} gInputDeviceCalibrationClassInfo;
static struct {
jclass clazz;
@@ -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;
}