android原始版本里是没有屏幕校准功能的,tp坐标到lcd坐标是完全按照线性关系来转换的。例如,tp坐标是(X
t
,Y
t
)分辨率是(W
t
x H
t
),lcd坐标是(X,Y),分辨率是(W x H),则 X=(X
t
*W)/W
t,
Y=(Y
t
*H)/H
t
。但是一般触摸屏不是完全线性的,自然转换关系也就不一样了,好在有tslib,能帮我们解决这个问题。但是android里没有tslib,我们也不需 要完全将tslib移植过来,只需要其中根据采样点生成转换矩阵的部分,这部分是由ts_calibrate.c文件中的 perform_calibration()函数来实现的。所以只需要将该函数移植过来就可以。这里将该函数及用到的数据结构代码贴出来如下:
typedef struct{
int x[5], xfb[5]; //x[5],y[5]是分别是tp五个点的x,y坐标,xfb[5],yfb[5]是lcd五个点的x,y坐标。
int y[5], yfb[5];
int a[7]; //a[7]是生成的7个转换参数,tp到lcd坐标转换方程是: X
lcd
= (X
tp
*a[1] + Y
tp
*a[2] + a[0])/a[6]
}calibration; // Y
lcd
= (X
tp
*a[4] + Y
tp
*a[5] + a[3])/a[6]
int perform_calibration(calibration *cal) {
int j;
float n, x, y, x2, y2, xy, z, zx, zy;
float det, a, b, c, e, f, i;
float scaling = 65536.0;
// Get sums for matrix
n = x = y = x2 = y2 = xy = 0;
for(j=0;j<5;j++) {
n += 1.0;
x += (float)cal->x[j];
y += (float)cal->y[j];
x2 += (float)(cal->x[j]*cal->x[j]);
y2 += (float)(cal->y[j]*cal->y[j]);
xy += (float)(cal->x[j]*cal->y[j]);
}
// Get determinant of matrix — check if determinant is too small
det = n*(x2*y2 – xy*xy) + x*(xy*y – x*y2) + y*(x*xy – y*x2);
if(det < 0.1 && det > -0.1) {
printf(“ts_calibrate: determinant is too small — %f/n”,det);
return 0;
}
// Get elements of inverse matrix
a = (x2*y2 – xy*xy)/det;
b = (xy*y – x*y2)/det;
c = (x*xy – y*x2)/det;
e = (n*y2 – y*y)/det;
f = (x*y – n*xy)/det;
i = (n*x2 – x*x)/det;
// Get sums for x calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal->xfb[j];
zx += (float)(cal->xfb[j]*cal->x[j]);
zy += (float)(cal->xfb[j]*cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer x coord
cal->a[0] = (int)((a*z + b*zx + c*zy)*(scaling));
cal->a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
cal->a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
printf(“%f %f %f/n”,(a*z + b*zx + c*zy),
(b*z + e*zx + f*zy),
(c*z + f*zx + i*zy));
// Get sums for y calibration
z = zx = zy = 0;
for(j=0;j<5;j++) {
z += (float)cal->yfb[j];
zx += (float)(cal->yfb[j]*cal->x[j]);
zy += (float)(cal->yfb[j]*cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer y coord
cal->a[3] = (int)((a*z + b*zx + c*zy)*(scaling));
cal->a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
cal->a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
printf(“%f %f %f/n”,(a*z + b*zx + c*zy),
(b*z + e*zx + f*zy),
(c*z + f*zx + i*zy));
// If we got here, we’re OK, so assign scaling to a[6] and return
cal->a[6] = (int)scaling;
return 1;
}
有了上面的基础,接下来就是将上面的代码移植到android中并在setting里面添加屏幕校准入口,要完成这些,需要修改的文件有:
1. frameworks/base/services/java/com/android/server/InputDevice.java
2. packages/apps/Settings/AndroidManifest.xml
3. packages/apps/Settings/res/xml/settings.xml
另外在Setting源码目录里再添加一个Calibration.java文件。
frameworks/base/services/java/com/android/server/InputDevice.java修改的地方如下(
红色
表示添加,蓝色 表示删除):
public class InputDevice {
static final boolean DEBUG_POINTERS = false;
static final boolean DEBUG_HACKS = false;
/** Amount that trackball needs to move in order to generate a key event. */
static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
/** Maximum number of pointers we will track and report. */
static final int MAX_POINTERS = 10;
static final String CALIBRATION_FILE=”/data/pointercal”;
final int id;
final int classes;
final String name;
final AbsoluteInfo absX;
final AbsoluteInfo absY;
final AbsoluteInfo absPressure;
final AbsoluteInfo absSize;
………………..
final AbsoluteInfo absX = device.absX;
final AbsoluteInfo absY = device.absY;
final AbsoluteInfo absPressure = device.absPressure;
final AbsoluteInfo absSize = device.absSize;
float tmpX = 0;
float tmpY = 0;
String prop = SystemProperties.get(“sys.config.calibrate”, “noset”);
if ( !prop.equalsIgnoreCase(“loaded”) )
{
if ( prop.equalsIgnoreCase(“start”) )
{
TransformInfo.xs = 0;
TransformInfo.ys = 0;
}
else if ( prop.equalsIgnoreCase(“done”) )
{
readCalibrate();
}
if ( TransformInfo.xs == 0 && absX != null )
{
TransformInfo.x1 = w;
TransformInfo.y1 = 0;
TransformInfo.z1 = 0-absX.minValue*w;
TransformInfo.xs = absX.range;
}
if ( TransformInfo.ys == 0 && absY != null )
{
TransformInfo.x2 = 0;
TransformInfo.y2 = h;
TransformInfo.z2 = 0-absY.minValue*h;
TransformInfo.ys = absY.range;
}
SystemProperties.set(“sys.config.calibrate”, “loaded”);
}
for (int i=0; i<numPointers; i++) {
final int j = i * MotionEvent.NUM_SAMPLE_DATA;
tmpX = reportData[j + MotionEvent.SAMPLE_X];
tmpY = reportData[j + MotionEvent.SAMPLE_Y];
if (absX != null ) {
reportData[j + MotionEvent.SAMPLE_X] =
((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
/ absX.range) * w;
reportData[j + MotionEvent.SAMPLE_X] = (TransformInfo.x1 * tmpX + TransformInfo.y1 * tmpY + TransformInfo.z1) / TransformInfo.xs;
}
if (absY != null ) {
reportData[j + MotionEvent.SAMPLE_Y] =
((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
/ absY.range) * h;
reportData[j + MotionEvent.SAMPLE_Y] = (TransformInfo.x2 * tmpX + TransformInfo.y2 * tmpY + TransformInfo.z2) / TransformInfo.ys;
}
if (absPressure != null) {
reportData[j + MotionEvent.SAMPLE_PRESSURE] =
((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
/ (float)absPressure.range);
}
if (absSize != null) {
reportData[j + MotionEvent.SAMPLE_SIZE] =
((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
/ (float)absSize.range);
}
…………………………….
static class AbsoluteInfo {
int minValue;
int maxValue;
int range;
int flat;
int fuzz;
};
static class TransformInfo {
static int x1;
static int y1;
static int z1;
static int x2;
static int y2;
static int z2;
static int xs;
static int ys;
};
InputDevice(int _id, int _classes, String _name,
AbsoluteInfo _absX, AbsoluteInfo _absY,
AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
id = _id;
classes = _classes;
name = _name;
absX = _absX;
absY = _absY;
absPressure = _absPressure;
absSize = _absSize;
TransformInfo.xs = 0;
TransformInfo.ys = 0;
readCalibrate();
}
static void readCalibrate(){
try {
FileInputStream is = new FileInputStream(CALIBRATION_FILE);
byte[] mBuffer = new byte[64];
int len = is.read(mBuffer);
is.close();
if (len > 0) {
int i;
for (i = 0; i < len; i++) {
if (mBuffer[i] == ‘/n’ || mBuffer[i] == 0) {
break;
}
}
len = i;
}
StringTokenizer st = new StringTokenizer(new String(mBuffer, 0, len));
TransformInfo.x1 = Integer.parseInt(st.nextToken());
TransformInfo.y1 = Integer.parseInt(st.nextToken());
TransformInfo.z1 = Integer.parseInt(st.nextToken());
TransformInfo.x2 = Integer.parseInt(st.nextToken());
TransformInfo.y2 = Integer.parseInt(st.nextToken());
TransformInfo.z2 = Integer.parseInt(st.nextToken());
TransformInfo.xs = Integer.parseInt(st.nextToken());
TransformInfo.ys = TransformInfo.xs;
SystemProperties.set(“sys.config.calibrate”, “loaded”);
} catch (java.io.FileNotFoundException e) {
Log.i(“InputDevice”, “calibration file not found exception”);
} catch (java.io.IOException e) {
Log.i(“InputDevice”, “io exception”);
} catch (java.lang.NumberFormatException e) {
Log.i(“InputDevice”, “number format exception”);
}
}
};
packages/apps/Settings/AndroidManifest.xml文件修改地方如下:
<activity android:name=”.fuelgauge.PowerUsageDetail”
android:label=”@string/details_title”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.DEFAULT” />
</intent-filter>
</activity>
<activity android:name=”Calibration”
android:label=”@string/screen_calibration_settings”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.DEFAULT” />
</intent-filter>
</activity>
<receiver android:name=”.widget.SettingsAppWidgetProvider” android:label=”@string/gadget_title”>
<intent-filter>
<action android:name=”android.appwidget.action.APPWIDGET_UPDATE” />
packages/apps/Settings/res/xml/settings.xml文件修改地方如下:
<com.android.settings.IconPreferenceScreen
settings:icon=”@drawable/ic_settings_date_time”
android:title=”@string/date_and_time_settings_title”>
<intent
android:action=”android.intent.action.MAIN”
android:targetPackage=”com.android.settings”
android:targetClass=”com.android.settings.DateTimeSettings” />
</com.android.settings.IconPreferenceScreen>
<!– touchscreen Calibration –>
<com.android.settings.IconPreferenceScreen
settings:icon=”@drawable/ic_settings_privacy”
android:title=”@string/screen_calibration_settings”>
<intent
android:action=”android.intent.action.MAIN”
android:targetPackage=”com.android.settings”
android:targetClass=”com.android.settings.Calibration”/>
</com.android.settings.IconPreferenceScreen>
<!– About Device –>
<com.android.settings.IconPreferenceScreen
settings:icon=”@drawable/ic_settings_about”
android:title=”@string/about_settings”>
<intent
android:action=”android.intent.action.MAIN”
android:targetPackage=”com.android.settings”
android:targetClass=”com.android.settings.DeviceInfoSettings” />
</com.android.settings.IconPreferenceScreen>
Calibration.java文件代码如下
-
package
com.android.settings; -
import
java.io.FileNotFoundException; -
import
java.io.FileOutputStream; -
import
java.io.IOException; -
import
android.app.Activity; -
import
android.content.Context; -
import
android.graphics.Bitmap; -
import
android.graphics.Canvas; -
import
android.graphics.Color; -
import
android.graphics.Paint; -
import
android.os.Bundle; -
import
android.os.RemoteException; -
import
android.os.ServiceManager; -
import
android.util.Log; -
import
android.view.Display; -
import
android.view.IWindowManager; -
import
android.view.MotionEvent; -
import
android.view.View; -
import
android.view.Window; -
import
android.view.WindowManager; -
import
android.widget.Toast; -
import
android.os.SystemProperties; -
public
class
Calibration
extends
Activity { -
static
final
int
SAMPLE_COUNTS =
5
; -
static
final
int
POINT_DEGREE =
2
; -
static
final
int
FACTOR_COUNTS =
7
; -
static
final
int
TOP_LEFT =
0
; -
static
final
int
TOP_RIGHT =
1
; -
static
final
int
BOTTOM_RIGHT =
2
; -
static
final
int
BOTTOM_LEFT =
3
; -
static
final
int
CENTER =
4
; -
static
final
int
X_AXIS =
0
; -
static
final
int
Y_AXIS =
1
; -
static
final
int
EDGE_GAP =
50
; -
static
final
String CALIBRATION_FILE =
“/data/pointercal”
; -
static
final
String TAG =
“Calibration”
; -
static
final
boolean
DEBUG =
true
; -
private
int
X_RES; -
private
int
Y_RES; -
private
Display dpy; -
class
calibration { -
int
x[] =
new
int
[
5
]; -
int
y[] =
new
int
[
5
]; -
int
xfb[] =
new
int
[
5
]; -
int
yfb[] =
new
int
[
5
]; -
int
a[] =
new
int
[
7
]; - };
-
private
calibration cal; -
@Override
-
protected
void
onCreate(Bundle savedInstanceState) { -
super
.onCreate(savedInstanceState); -
SystemProperties.set(
“sys.config.calibrate”
,
“start”
); -
cal =
new
calibration(); - dpy = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
- X_RES = dpy.getWidth();
- Y_RES = dpy.getHeight();
-
this
.initScreenPoints(); -
setContentView(
new
MyView(
this
)); - }
-
// TopLeft–>TopRight–>BottomRight–>BottomLeft–>Center
-
// For 240 * 320 resolution, we use 50 pixel as edge gap
-
private
boolean
initScreenPoints() { -
cal.xfb[TOP_LEFT] = EDGE_GAP;
// TopLeft
- cal.yfb[TOP_LEFT] = EDGE_GAP;
-
cal.xfb[TOP_RIGHT] = X_RES – EDGE_GAP;
// TopRight
- cal.yfb[TOP_RIGHT] = EDGE_GAP;
-
cal.xfb[BOTTOM_RIGHT] = X_RES – EDGE_GAP;
// BottomRight
- cal.yfb[BOTTOM_RIGHT] = Y_RES – EDGE_GAP;
-
cal.xfb[BOTTOM_LEFT] = EDGE_GAP;
// BottomLeft
- cal.yfb[BOTTOM_LEFT] = Y_RES – EDGE_GAP;
-
cal.xfb[CENTER] = X_RES /
2
;
// Center
-
cal.yfb[CENTER] = Y_RES /
2
; -
return
true
; - }
-
private
boolean
perform_calibration() { -
float
n, x, y, x2, y2, xy, z, zx, zy; -
float
det, a, b, c, e, f, g; -
float
scaling = (
float
)
65536.0
; -
n = x = y = x2 = y2 = xy =
0
; -
for
(
int
i =
0
; i < SAMPLE_COUNTS; i++) { -
n +=
1.0
; -
x += (
float
)cal.x[i]; -
y += (
float
)cal.y[i]; -
x2 += (
float
)(cal.x[i] * cal.x[i]); -
y2 += (
float
)(cal.y[i] * cal.y[i]); -
xy += (
float
)(cal.x[i] * cal.y[i]); - }
- det = n * (x2 * y2 – xy * xy) + x * (xy * y – x * y2) + y * (x * xy – y * x2);
-
if
(det <
0.1
&& det > –
0.1
) { -
Log.w(
“bigcren”
,
“determinant is too small, det =”
+ det); -
return
false
; - }
-
if
(DEBUG) { -
Log.i(
“bigcren”
,
“(n,x,y,x2,y2,xy,det)=(”
-
+ n +
“,”
-
+ x +
“,”
-
+ y +
“,”
-
+ x2 +
“,”
-
+ y2 +
“,”
-
+ xy +
“,”
-
+ det +
“)”
); - }
- a = (x2 * y2 – xy * xy) / det;
- b = (xy * y – x * y2) / det;
- c = (x * xy – y * x2) / det;
- e = (n * y2 – y * y) / det;
- f = (x * y – n * xy) / det;
- g = (n * x2 – x * x) / det;
-
Log.i(
“bigcren”
,
“(a,b,c,e,f,g)=(”
-
+ a +
“,”
-
+ b +
“,”
-
+ c +
“,”
-
+ e +
“,”
-
+ f +
“,”
-
+ g +
“)”
); -
// Get sums for x calibration
-
z = zx = zy =
0
; -
for
(
int
i =
0
; i < SAMPLE_COUNTS; i++) { -
z += (
float
)cal.xfb[i]; -
zx += (
float
)(cal.xfb[i] * cal.x[i]); -
zy += (
float
)(cal.xfb[i] * cal.y[i]); - }
-
// Now multiply out to get the calibration for X coordination
-
cal.a[
0
] = (
int
)((a * z + b * zx + c * zy) * (scaling)); -
cal.a[
1
] = (
int
)((b * z + e * zx + f * zy) * (scaling)); -
cal.a[
2
] = (
int
)((c * z + f * zx + g * zy) * (scaling)); -
// Get sums for y calibration
-
z = zx = zy =
0
; -
for
(
int
i =
0
;i < SAMPLE_COUNTS; i++) { -
z += (
float
)cal.yfb[i]; -
zx += (
float
)(cal.yfb[i] * cal.x[i]); -
zy += (
float
)(cal.yfb[i] * cal.y[i]); - }
-
// Now multiply out to get the calibration for Y coordination
-
cal.a[
3
] = (
int
)((a * z + b * zx + c * zy) * (scaling)); -
cal.a[
4
] = (
int
)((b * z + e * zx + f * zy) * (scaling)); -
cal.a[
5
] = (
int
)((c * z + f * zx + g * zy) * (scaling)); -
cal.a[
6
] = (
int
)scaling; -
return
true
; - }
-
private
boolean
saveCalibrationResult() { - FileOutputStream os;
-
String res =
“”
; -
// save the calibration factor in file system for InputDevice
-
try
{ -
os =
new
FileOutputStream(CALIBRATION_FILE); -
res = String.format(
“%d %d %d %d %d %d %d”
, cal.a[
1
], cal.a[
2
], cal.a[
0
], cal.a[
4
], cal.a[
5
], cal.a[
3
], cal.a[
6
]); -
if
(DEBUG) { -
Log.i(
“bigcren”
,
“calibration result=”
+ res); - }
- os.write(res.getBytes());
- os.close();
-
}
catch
(FileNotFoundException e1) { -
// TODO Auto-generated catch block
- e1.printStackTrace();
-
Log.w(TAG,
“open calibration file write error: ”
+ CALIBRATION_FILE ); -
}
catch
(IOException e) { -
// TODO Auto-generated catch block
- e.printStackTrace();
- }
-
return
true
; - }
-
public
class
MyView
extends
View { -
private
Canvas cv; -
private
Paint paint; -
private
Bitmap bmp; -
private
int
screen_pos; -
private
Context mContext; -
public
MyView(Context c) { -
super
(c); -
// set full screen and no title
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- mContext=c;
-
paint =
new
Paint(); -
paint.setDither(
true
); -
paint.setAntiAlias(
true
); -
paint.setStrokeWidth(
2
); - paint.setColor(Color.WHITE);
- paint.setStyle(Paint.Style.STROKE);
- bmp = Bitmap.createBitmap(X_RES, Y_RES, Bitmap.Config.ARGB_8888);
-
cv =
new
Canvas(bmp); -
screen_pos =
0
; - drawCalibrationCross(screen_pos);
- }
-
protected
void
onDraw(Canvas canvas) { - canvas.drawColor(Color.BLACK);
-
canvas.drawBitmap(bmp,
0
,
0
,
null
); - }
-
private
boolean
drawCalibrationCross(
int
pos) { -
if
(DEBUG) { -
Log.i(
“bigcren”
,
“draw cross at pos ”
+ pos); - }
- cv.drawColor(Color.BLACK);
-
// draw X line
-
cv.drawLine(cal.xfb[pos] –
10
, cal.yfb[pos], -
cal.xfb[pos] –
2
, cal.yfb[pos], paint); -
cv.drawLine(cal.xfb[pos] +
2
, cal.yfb[pos], -
cal.xfb[pos] +
10
, cal.yfb[pos], paint); -
// draw Y line
-
cv.drawLine(cal.xfb[pos], cal.yfb[pos] –
10
, -
cal.xfb[pos], cal.yfb[pos] –
2
, paint); -
cv.drawLine(cal.xfb[pos], cal.yfb[pos] +
2
, -
cal.xfb[pos], cal.yfb[pos] +
10
, paint); - invalidate();
-
return
true
; - }
-
public
boolean
onTouchEvent(MotionEvent event) { -
float
tmpx, tmpy; -
boolean
ret; -
if
(screen_pos > SAMPLE_COUNTS –
1
) { -
Log.i(
“bigcren”
,
“get sample ok”
); -
return
true
; - }
-
if
(event.getAction() == MotionEvent.ACTION_UP) { - tmpx = event.getX();
- tmpy = event.getY();
-
if
(Math.abs(cal.xfb[screen_pos]-tmpx)>
15
&& -
Math.abs(cal.yfb[screen_pos]-tmpy)>
15
){ - Toast.makeText(mContext, R.string.calibration_error,Toast.LENGTH_SHORT).show();
-
return
false
; - }
-
cal.x[screen_pos] = (
int
)(event.getX()*
4096.0
/(
float
)X_RES +
0.5
); -
cal.y[screen_pos] = (
int
)(event.getY()*
4096.0
/(
float
)Y_RES +
0.5
); -
if
(screen_pos ==
4
) { - ret = perform_calibration();
-
if
(ret) { - saveCalibrationResult();
-
SystemProperties.set(
“sys.config.calibrate”
,
“done”
); - finish();
-
return
true
; -
}
else
{ -
screen_pos =
0
; -
Log.w(TAG,
“Calibration failed”
); - }
-
}
else
{ - screen_pos++;
- drawCalibrationCross(screen_pos);
- }
- }
-
return
true
; - }
- }
- }
转自:
http://blog.csdn.net/king_sundi/archive/2011/01/19/6152865.aspx
http://blogold.chinaunix.net/u3/90973/showart_2162315.html
http://blog.csdn.net/cpuwolf/archive/2011/01/11/6130010.aspx
http://blog.csdn.net/dafeifly/archive/2009/10/13/4662498.aspx