2013年5月9日

47_手势识别

--------------------

第一步:建立手势库

使用SDK自带例子GestureBuilder建立手势库(位置:android-sdk-windows\samples\android-8\GestureBuilder)。使用GestureBuilder之前,你需要恢复其到开发环境,然后进行编绎并部署到手机上。此时,就可以使用GestureBuilder建立手势库,生成的手势库文件在SCDard上,默认文件名称为:gestures

第二步:在应用中加载手势库文件,然后开发手势识别代码。

把手势库文件gestures文件拷贝到项目的res/raw目录下。然后在布局文件中添加用于手势绘制的View:

 <android.gesture.GestureOverlayView

    android:id="@+id/gestures"

    android:layout_width="fill_parent“ android:layout_height="0dip"

    android:layout_weight="1.0"

    />

大多数情况下,手势都是通过一笔完成。然而有一些特别的需求就需要通过多个笔画来实现,这时可以使用gestureStrokeType属性进行设置:Multiple:1

手势识别代码见ppt下方

public class MainActivity extends Activity {

    private GestureOverlayView gestureOverlayView;

    private GestureLibrary mLibrary;

    private boolean state;

    private EditText addressText;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        addressText = (EditText)this.findViewById(R.id.address);

        gestureOverlayView = (GestureOverlayView)this.findViewById(R.id.gestures);

        //当用户完成一次Gesture绘制后,系统将自动调用Listener对象的onGesturePerformed()方法

        gestureOverlayView.addOnGesturePerformedListener(new GestureListener());

        mLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures);

        state = mLibrary.load();//加载手势库

    }

   

    private final class GestureListener implements GestureOverlayView.OnGesturePerformedListener{

  @Override

  public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {

   if(state){

    List<Prediction> predictions = mLibrary.recognize(gesture);//从手势库中查询匹配的内容,匹配的结果可能包括多个相似的结果,匹配度高的结果放在最前面

    if(!predictions.isEmpty()){

     Prediction prediction = predictions.get(0);

     //prediction的score属性代表了与手势的相似程度

     //prediction的name代表手势对应的字母

     if(prediction.score > 1){

      addressText.setText(prediction.name);

     }

    }

   }

  }

    }

}

---------------------------------------

2.相关理解:手势识别其实就是图形识别,当用户画出图形后,由程序识别然后按照识别的结果进行执行。

----------------------------------------------------------------------------------------------------

3.导入一个android项目到eclipse工作workspace中的方法:

  a.在已经workspace已经存在的android项目中拷贝.classpath,.project,project.properties(这里应该是default.properties文件)到

    需要导入的项目中

  b.然后直接导入项目到eclipse中就可以了

  ---------------------------------------------------------

4.a、这里要实现的功能是,当用户画出一个对勾后,关闭该应用。

  b、当用户画一个L后,就给李德伟打电话

  ------------------------------------------------------

5.首先要建立手势库,手势识别的时候会从手势库中查找,如果找到就执行相应的业务功能

----------------------------------------------------------------

6.WARNING: Application does not specify an API level requirement!

[2009-12-27 16:51:33 - Tank] WARNING: Application does not specify an API level requirement!

[2009-12-27 16:51:33 - Tank] Device API version is 3 (Android 1.5)

网上一查是由于没有指定users sdk的缘故,修改AndroidManifest.xml文件.

加入:

<uses-sdk android:minSdkVersion="3"></uses-sdk>

加在<manifest> </manifest> 之间.

------------------------------------------------------

7.2013/5/10

----------------

8.[2013-05-10 22:54:48 - GestureBuilder] Re-installation failed due to different application signatures.

[2013-05-10 22:54:48 - GestureBuilder] You must perform a full uninstall of the application. WARNING: This will remove the application data!

[2013-05-10 22:54:48 - GestureBuilder] Please execute 'adb uninstall com.android.gesture.builder' in a shell.

[2013-05-10 22:54:48 - GestureBuilder] Launch canceled!

这时先运行android模拟机,进入命令行,当然你要定位adb.exe的目录,我是放在E:\android\android-sdk-windows\platform-tools 下

 E:\android\android-sdk-windows\platform-tools> adb uninstall com.android.gesture.builder.

 重新运行就可以了

 --------------------------------------------------

9.这里建立手势库的时候,用的是android自带的一个例子:

  这个例子可以在这里找到:

  G:\李鹏视频\andoid程序学习及开发\3G手机Android应用开发\3G手机Android应用开发开发资料\开发资料\android-sdk_r06-windows\android-sdk-windows\samples\android-8

  就是这个项目:GestureBuilder

  ---------------------------------------

10.如果出现问题按照上面的方法进行解决

   运行该例子程序后:点击Add gesture进行手势添加,也就是添加用户自己画的图片

   添加的时候,只要在空白区域画出手势,在Name中输入手势名称就,然后点击Done就

   可以添加一个手势了

-------------------------------

11.当添加完手势后,可以查看在sdcard根目录下,有gestures这个文件,这个就是手势库文件

   也是一个数据库文件,这时候就可以在这个手势库的基础上进行手势的查找识别了。

   ---------------------------------------------------------------------------------------

   11-1:做的时候首先将上一步生成的手势库文件gestures复制到:/gesture/res/raw/gestures这个路径下,当查不到的时候需要关闭应用

   11-2:关闭应用的方法:

          当应用不再使用时,通常需要关闭应用,可以使用以下两种方法关闭android应用:

第一种方法:首先获取当前进程的id,然后杀死该进程。 (建议使用)

android.os.Process.killProcess(android.os.Process.myPid())

第二种方法:终止当前正在运行的Java虚拟机,导致程序终止

System.exit(0);

第三种方法:强制关闭与该包有关联的一切执行

ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);   

manager.restartPackage(getPackageName());

<uses-permission android:name="android.permission.RESTART_PACKAGES" />

----------------------------------------------------------------------------------------

12.下面是手势识别实例的所有源码:

   屏幕布局:

   --------------

   整个屏幕都是供用户绘制手势

   在屏幕右下角有个识别按钮

---------------------------------

  a.新建android项目:gesture

  b./gesture/src/com/credream/gesture/GestureActivity.java

    package com.credream.gesture;

import java.util.ArrayList;

import android.app.Activity;

import android.content.Intent;

import android.gesture.Gesture;

import android.gesture.GestureLibraries;

import android.gesture.GestureLibrary;

import android.gesture.GestureOverlayView;

import android.gesture.GestureOverlayView.OnGestureListener;

import android.gesture.GestureOverlayView.OnGesturePerformedListener;

import android.gesture.Prediction;

import android.net.Uri;

import android.os.Bundle;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.widget.Toast;

public class GestureActivity extends Activity {

 private static final String TAG = "GestureActivity";

    private  GestureLibrary library;

 private Gesture mgesture;

    private GestureOverlayView overlayView;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        //fromRawResource从raw这个手势库文件中得到手势对象

        library = GestureLibraries.fromRawResource(this, R.raw.gestures);

        //加载手势对象

        library.load();

        //获取overlayView,也就是用户识别手势的画板。

        overlayView = (GestureOverlayView) this.findViewById(R.id.gestures);

        //只针对单笔手势:overlayView.addOnGesturePerformedListener(new GesturePerformedListener());

        //当用户绘制完手势之后,就会触发一个事件

        //overlayView.addOnGesturePerformedListener(new GesturePerformedListener());

        //注意这里GesturePerformedListener这个方法只是针对单笔手势的,用户画多笔的时候会没有响应

        overlayView.addOnGestureListener(new GestureListener());

        //addOnGestureListener,这个方法,既可以实现单笔手势,也可以实现多笔手势

    }

    // ②.在这个方法中识别手势

    public void find(View v){

     recognize(mgesture);

     //②.1 识别完之后,清除。

     overlayView.clear(true);

    }

    //②.下面这个方法可以识别单笔,也可以识别多笔。

    private final class GestureListener implements OnGestureListener{

 

     public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {

   Log.i(TAG, "onGestureStarted()");

   //可以打印到控制台,得到这三个方法的调用顺序。

   //-----------------------------------------

   /*这三个方法的调用顺序是,当用户画第一笔的时候,调用onGestureStarted方法

    * 当用户在画第一笔的过程中不断调用onGesture这个方法

    * 当用户画完第一笔的时候调用onGestureEnded这个方法

    * 当用户开始画第二笔的时候调用onGestureStarted这个方法,一次循环。。

    * */

   //-------------------------------------------

  }

  public void onGesture(GestureOverlayView overlay, MotionEvent event) {

   Log.i(TAG, "onGesture()");

  }

  public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {

   Log.i(TAG, "onGestureEnded()");

   //因为这个方法是最后调用的,所以在这个方法里得到用户最后画完的手势

   mgesture = overlay.getGesture();

   //取得用户最后画完的手势

  }

  public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {

   Log.i(TAG, "onGestureCancelled()");

  }

    }

    //①.以下方法只识别单笔绘图。

  //当用户绘制完手势之后,就会触发一个事件,就会调用这个方法,把用户绘制完的手势传进来

    private final class GesturePerformedListener implements OnGesturePerformedListener{

  //overlay这个参数其实就是取得用户绘制所用的那个画板,这里是overlayView

     public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {

   //在这个方法中就来识别用户画出的手势,也就是把用户绘制的手势在手势库中查找,查找到就是

      //代表可以识别。

      //这时候把导出的手势库文件gesture,添加到

      ///gesture/res/raw这个路径中,注意这里raw是新建的文件夹

      //然后查看R文件就可以看到下面这些:

      //public static final int gestures=0x7f040000;

      //识别手势, recognize(gesture)这个方法会在手势库中查找,如果找到匹配项

      //会以集合的形式返回

      

     //ArrayList<Prediction> predictions=library.recognize(gesture);

     //这个集合中的元素排序原则是最匹配的在最上边,其次是不怎么匹配的。

     //这个方法会把所有匹配的记录查询出来,并且把最匹配的在最上边

       recognize(gesture);

  }  

    }

   

    private void recognize(Gesture gesture) {

     //这个集合中的元素排序原则是最匹配的在最上边,其次是不怎么匹配的。

     //这个方法会把所有匹配的记录查询出来,并且把最匹配的在最上边

     ArrayList<Prediction> predictions = library.recognize(gesture);

  if(!predictions.isEmpty()){//当结果集合不是空的时候,就说明有匹配

   //得到最匹配的那个,也就是第一条记录

   Prediction prediction = predictions.get(0);

   //prediction.score>0-10这个是匹配值,范围:prediction.score>0-10

   //这个值为10的时候,代表手势库中的图和用户绘制的图有10%的匹配度

   if(prediction.score >= 6){

    //这里要求匹配度要在60%以上

    //如果名称为李德伟lidewei

    if("lidewei".equals(prediction.name)){

     //调用打电话意图,

     Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:1350505050"));

     //通过意图调用打电话的activity,这里需要有拨号权限

     startActivity(intent);

    }else if("close".equals(prediction.name)){

     finish();//关闭Activity,也就是关闭窗口

    //当activity关闭的时候,其实应用还存在,这里需要关闭应用

     //当activity关闭的时候,会调用onDestroy方法,在这个方法里

     //可以直接杀掉进程

    }

   }else{

    //匹配度不够6的时候,提示匹配度太低

    Toast.makeText(getApplicationContext(), R.string.low, 1).show();

   }

  }else{

   //没有匹配的记录

   Toast.makeText(getApplicationContext(), R.string.notfind, 1).show();

  }

 }

 @Override

 protected void onDestroy() {

  super.onDestroy();

  //这里直接杀掉进程:首先取得当前进程的id,然后调用killProcess杀掉进程

          android.os.Process.killProcess(android.os.Process.myPid());//关闭应用

 }

}

-----------------------------------------------------------

c./gesture/res/values/strings.xml

  <?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">Hello World, MainActivity!</string>

    <string name="app_name">手势识别</string>

    <string name="notfind">不匹配</string>

    <string name="low">匹配度太低</string>

    <string name="recognize">识别</string>

</resources>

--------------------------------------------------

d./gesture/AndroidManifest.xml

  <?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="​​http://schemas.android.com/apk/res/android​​"

    package="com.credream.gesture"

    android:versionCode="1"

    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name" >

        <activity

            android:label="@string/app_name"

            android:name=".GestureActivity" >

            <intent-filter >

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

<!-- 由于识别成功后会给李德伟拨打电话,所以这里需要这个权限 -->

<uses-permission android:name="android.permission.CALL_PHONE"/>

       

</manifest>

-----------------------------------------------------

e./gesture/res/layout/main.xml

  <?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="​​http://schemas.android.com/apk/res/android​​"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

    <!-- 这个控件可以供用户在他上面绘制手势 -->

 <android.gesture.GestureOverlayView

     android:id="@+id/gestures"

     android:layout_width="fill_parent"

     android:layout_height="0dp"

     android:layout_weight="1"

     android:gestureStrokeType="multiple"

     />

 <!-- ①.1 android:layout_height="0dp",设置用户绘制手势界面的高度

 ①.2 android:layout_weight="1",设置定义测量的优先级别,0的优先级最高,0>1>2...

       按钮的话,android:layout_weight="1"这个默认值是0

 ①.3 系统首先测量按钮的高度,因为按钮的优先级高。

 ④.4 只要这样设置就可以实现用窗口的高度,减去按钮的高度,剩余的,就是用户绘制手势的高度

  -->

 <!-- android:gestureStrokeType="multiple"注意加上这一句就可以进行多笔画识别

 以前只可以写一笔,现在可以写好几笔画。

  -->

<!-- ①. android:layout_weight="0"这里要求让这个按钮显示在屏幕的最下方

  这里采取的方法是,用窗口的高度,减去按钮的高度,剩余的,就是用户绘制手势的高度 -->

 <Button

 android:layout_weight="0"

  android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/recognize"

    android:onClick="find"

    />

</LinearLayout>

------------------------------------------------------------------------------------

13.这个功能可以做成,用户输入密码。

   手势识别,可以用于软件的快捷方式。比如用户想打开某个应用画个o就可以。

   使用手势识别可以实现解锁功能。

----------------------------------------------------------------------------