即時顯示gsensor的數據,可以在調試重力感應器驅動和測試手機性能時起到很好的作用。類似的,SensorEventListener還可以用在其他感應器的場合,比如光感應、地磁感應。這裏用兩種方式來完成讀取並顯示gsensor數據的功能,一種是activity和SensorEventListener監聽分離,在不同類中完成;另一種是在同一個activity中完成(*)。
(1)activity和SensorEventListener監聽分離
Acvitivity啓動時初始化SensorEventListener,在退出activity時註銷Listener。
- import android.os.Bundle;
- import android.app.Activity;
- import android.util.Log;
- import android.view.Menu;
- import android.widget.TextView;
- public class Activity01 extends Activity {
- private final String TAG = "zhangcheng";
- SensorListenerTest sensorListenerTest; //sensor監聽類,同一個包裏的類被調用時不需要import
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_activity01);
- sensorListenerTest = new SensorListenerTest(this); //監聽類的構造函數,activity通過this句柄跟監聽類綁定
- }
- protected void onResume(){
- super.onResume();
- sensorListenerTest.enableSensor(); //activity啓動後使能sensor監聽
- }
- protected void onStop(){
- super.onStop();
- sensorListenerTest.disableSensor(); //出於系統控制原因,在退出activity時註銷監聽
- }
- }
SensorListenerTest類,監聽gsensor數據。注意import android.hardware.sensor的四個類。
- import android.content.Context;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.util.Log;
- public class SensorListenerTest implements SensorEventListener { //使用listsen的接口,所以必須實現接口的兩個成員函數
- private final String TAG = "zhangcheng";
- private SensorManager mSensorManager;
- private Sensor sensor;
- private float mLastX,mLastY,mLastZ; // X Y Z三軸數據
- private Context mContext;
- public SensorListenerTest(Context context){
- mContext = context;
- }
- public void enableSensor(){
- mSensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE); //獲得系統的sensor服務
- sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //具體要操作的sensor類型
- if(mSensorManager == null){
- Log.i(TAG,"sensor not supported");
- }
- mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); //以普通採樣率註冊監聽器
- }
- public void disableSensor(){
- if(mSensorManager != null){
- mSensorManager.unregisterListener(this); //註銷監聽器
- mSensorManager = null;
- }
- }
- public void onAccuracyChanged(Sensor arg0, int arg1){
- }
- public void onSensorChanged(SensorEvent event){ //必須完成SensorEventListener的響應函數
- if(event.sensor == null){
- return;
- }
- if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
- mLastX = event.values[0];
- mLastY = event.values[1];
- mLastZ = event.values[2]; //得到XYZ三軸數據
- String sX = String.valueOf(mLastX);
- String sY = String.valueOf(mLastY);
- String sZ = String.valueOf(mLastZ); //利用String的成員函數valueOf快速將float型轉成String型
- Log.i(TAG,"mLastX == "+sX);
- Log.i(TAG,"mLastY == "+sY);
- Log.i(TAG,"mLastZ == "+sZ); //在Logcat中即時提示讀出的gsensor數據
- }
- }
- }
運行結果諸如在Logcat中顯示:
01-02 23:28:41.634: I/zhangcheng(2238): mLastX == -0.181
01-02 23:28:41.634: I/zhangcheng(2238): mLastY == 0.143
01-02 23:28:41.634: I/zhangcheng(2238): mLastZ == 9.979
01-02 23:28:41.808: I/zhangcheng(2238): mLastX == -0.143
01-02 23:28:41.808: I/zhangcheng(2238): mLastY == 0.172
01-02 23:28:41.808: I/zhangcheng(2238): mLastZ == 10.008
(2)單一activity完成監聽。上述方法完成後在Logcat中顯示讀數不太直觀,可以直接在activity上用textview來顯示。
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.app.Activity;
- import android.content.Context;
- import android.util.Log;
- import android.view.Menu;
- import android.widget.TextView;
- public class Activity01 extends Activity implements SensorEventListener{ //在繼承activity類的同時使用listsen接口
- private final String TAG = "zhangcheng";
- private SensorManager mSensorManager;
- private Sensor sensor;
- private float mLastX,mLastY,mLastZ;
- private String sX,sY,sZ;
- private TextView mTextViewX = null;
- private TextView mTextViewY = null;
- private TextView mTextViewZ = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_activity01);
- mTextViewX = (TextView)findViewById(R.id.TextView1);
- mTextViewY = (TextView)findViewById(R.id.TextView2);
- mTextViewZ = (TextView)findViewById(R.id.TextView3); //綁定顯示控件句柄
- mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
- sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- if(mSensorManager == null){
- Log.i(TAG,"sensor not supported");
- }
- mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
- }
- public void onAccuracyChanged(Sensor arg0, int arg1){
- }
- public void onSensorChanged(SensorEvent event){ //在activity中完成該接口函數
- if(event.sensor == null){
- return;
- }
- if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){
- mLastX = event.values[0];
- mLastY = event.values[1];
- mLastZ = event.values[2];
- sX = String.valueOf(mLastX);
- sY = String.valueOf(mLastY);
- sZ = String.valueOf(mLastZ);
- mTextViewX.setText(sX);
- mTextViewY.setText(sY);
- mTextViewZ.setText(sZ); //由於該接口函數不斷刷新,所以可以把控件顯示函數放在這裏顯示
- }
- }
- protected void onStop(){ //同樣在退出activity時要註銷監聽
- super.onStop();
- if(mSensorManager != null){
- mSensorManager.unregisterListener(this);
- mSensorManager = null;
- }
- }
- }
該函數可在一個activity中即時顯示gsensor數據,方便查看。
========================================================================================================================
現實中的很多手機應用會到gsensor這個感應器,比如手機的傾斜角度,手機的運動方向和加速度。如果我們要在一個服務中通過監控gsensor的數據來判斷手機的靜止或者運動,進而作相應處理。流程是:原始數據 -> 低通濾波 -> 重力在3個方向的分量 -> 判斷即可。以下步驟:
(1)服務定義時要implements SensorEventListener接口,以下是一些變量。
- private SensorManager mSensorManager; //sensor管理器
- private Sensor sensor;
- private float[] curGravity = new float[3]; //xyz重力數據
- private lowPassFilter filter1;
- private lowPassFilter filter2;
- private firLowPassFilter firFilter1;
- private firLowPassFilter firFilter2;
- private firLowPassFilter firFilter3; //低通濾波的一些類的內容
- private int mAccSkipCnt = 0; //抖動計數
- private static final int __ACC_SKIP_SAMPLES = 30; // 跳過剛開始的若干個加速度採樣
- private int _NTAPS = 6;
- private double[] h = {
- 0.125514644795420960,
- 0.414388923238107440,
- -0.013420976983735622,
- -0.013420976983735622,
- 0.414388923238107440,
- 0.125514644795420960
- };
- private boolean DeviceFlating = false; //手機是否平躺了
(2)在服務onCreate函數中定義sensor相關變量,並設置低通濾波的一些係數
- mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
- sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
- filter1 = new lowPassFilter(1, 20);
- filter2 = new lowPassFilter(0, 0.9f);
- firFilter1 = new firLowPassFilter(_NTAPS, h);
- firFilter2 = new firLowPassFilter(_NTAPS, h);
- firFilter3 = new firLowPassFilter(_NTAPS, h);
(3)SensorEventListener接口中要完成的成員函數
- public void onSensorChanged(SensorEvent event){
- if(event.sensor == null){
- return;
- }
- mIsSmartStayOn= Settings.System.getInt(cr,"isSmartStayEnabled",0) == 1 ? true : false;//人眼識別打開時才啓動重力監聽
- if(mIsSmartStayOn == true){
- Log.i(TAG,"gsensor respond");
- curGravity[0] = (float)firFilter1.filter1((double)event.values[0]);
- curGravity[1] = (float)firFilter2.filter1((double)event.values[1]);
- curGravity[2] = (float)firFilter3.filter1((double)event.values[2]);
- curGravity = filter1.SMAFilter(curGravity); //取得三軸重力數據並濾波處理
- if(mAccSkipCnt < __ACC_SKIP_SAMPLES) {
- mAccSkipCnt++;
- return ; //待gsensor讀數穩定才繼續後面的處理
- }
- float[] linearAcc = new float[]{
- event.values[0]-curGravity[0],
- event.values[1]-curGravity[1],
- event.values[2]-curGravity[2]
- };
- double linearLen = KonkaGeneHelper.vecLength(linearAcc); //三軸數據平方和相加開根號的結果
- Log.w(TAG,"linearLen is "+linearLen);
- if(linearLen < 0.6f && DeviceFlating == false){ //如果手機一開始沒有靜止並且linearLen小於0.6
- DeviceFlating = true; //手機趨近於靜止狀態(不論方向)
- }
- if(linearLen > 1.0f && DeviceFlating == true && pm.isScreenOn() == true){
- DisplayEyeIcon(1); //如果手機靜止的,並且gsensor檢測到linearLen大於1且手機亮屏 freshDetect();
- DeviceFlating = false; //馬上啓動人眼識別
- }
- }
- }
通過以上過程,可以參考其中的重力計算和判斷流程用在其他場合。