给android增加屏幕校准

android原始版本里是没有屏幕校准功能的,tp坐标到lcd坐标是完全按照线性关系来转换的。例如,tp坐标是(Xt ,Yt )分辨率是(Wt x Ht ),lcd坐标是(X,Y),分辨率是(W x H),则 X=(Xt *W)/Wt, Y=(Yt *H)/Ht 。但是一般触摸屏不是完全线性的,自然转换关系也就不一样了,好在有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坐标转换方程是: Xlcd = (Xtp *a[1] + Ytp *a[2] + a[0])/a[6]

}calibration;               //  Ylcd = (Xtp *a[4] + Ytp *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; } } }

你可能感兴趣的:(exception,android,String,import,float,Pointers)