1. 程式人生 > 其它 >Android-感測器開發

Android-感測器開發

技術標籤:android感測器

感測器種類

感測器Sensor是一系列感測器的總稱,是Android裝置用來感知周圍環境和運動資訊的工具。因為工具的感應資訊依賴於相關硬體,所以雖然Android定義了多個感測器。但並非每部手機都支援這麼多感應器。

編號型別名稱說明
1TYPE_ACCELEROMETER加速度常用於搖一搖功能
2TYPE_MAGNETIC_FIELD磁場
3TYPE_ORIENTATION方向已棄用,使用getOrientation方法
4TYPE_GYROSCOPE螺旋儀用來感應手機的旋轉和傾斜
5TYPE_LIGHT光線用來感應手機正面的光線強弱
6TYPE_PRESSURE壓力用來感應氣壓
7TYPE_TEMPERATURE溫度已棄用,使用型別13
8TYPE_PROXIMITY距離
9TYPE_GRAVITY重力
10TYPE_LINEAR_ACCELERATION線性加速度
11TYPE_ROTATION_VECTOR旋轉向量
12TYPE_RELATIVE_HUMIDITY相對溼度
13TYPE_AMBIENT_TEMPERATURE環境溫度
14TYPE_MAGNETIC_FIELD_UNCALIBRATED無標定磁場
15TYPE_GAME_ROTATION_VECTOR無標定旋轉向量
16TYPE_GYROSCOPE_UNCALIBRATED未校準陀螺儀
17TYPE_SIGNIFICANT_MOTION特殊動作
18TYPE_STEP_DETECTOR步行檢測使用者每走一步觸發一次
19TYPE_STEP_COUNTER步行計數記錄啟用後的步伐數
20TYPE_GEOMAGNETIC_ROTATION_VECTOR地磁旋轉向量
21TYPE_HEART_RATE心跳速率可穿戴裝置使用
22TYPE_TILT_DETECTOR傾斜檢測
23TYPE_WAKE_GESTURE喚醒手勢
24TYPE_GLANCE_GESTURE掠過手勢
25TYPE_PICK_UP_GESTURE拾起手勢

檢視當前裝置支援的感測器種類,可通關呼叫SensorManager物件的getSensorList方法獲得,該方法返回了一個Sensor佇列。遍歷Sensor佇列中的每個元素,呼叫Sensor物件的getType方法可獲得該感測器的型別,呼叫Sensor物件的getName方法方法獲得該感測器的名稱。

例子
SensorActivity

public class SensorActivity extends AppCompatActivity {
    private TextView tv_sensor;
    private String[] mSensorType = {
            "加速度", "磁場", "方向", "陀螺儀", "光線",
            "壓力", "溫度", "距離", "重力", "線性加速度",
            "旋轉向量", "溼度", "環境溫度", "無標定磁場", "無標定旋轉向量",
            "未校準陀螺儀", "特殊動作", "步行檢測", "計步器", "地磁旋轉向量",
            "心跳", "傾斜檢測", "喚醒手勢", "掠過手勢", "拾起手勢"};
    private Map<Integer, String> mapSensor = new HashMap<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sensor);
        tv_sensor = findViewById(R.id.tv_sensor);
        showSensorInfo(); // 顯示手機自帶的感測器資訊
    }

    private void showSensorInfo() {
        // 從系統服務中獲取感測管理器物件
        SensorManager mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        // 獲取當前裝置支援的感測器列表
        List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
        String show_content = "當前支援的感測器包括:\n";
        for (Sensor sensor : sensorList) {
            if (sensor.getType() >= mSensorType.length) {
                continue;
            }
            mapSensor.put(sensor.getType(), sensor.getName());
        }
        for (Map.Entry<Integer, String> item_map : mapSensor.entrySet()) {
            int type = item_map.getKey();
            String name = item_map.getValue();
            String content = String.format("%d %s:%s\n", type, mSensorType[type - 1], name);
            show_content += content;
        }
        tv_sensor.setText(show_content);
    }

}

activity_sensor

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="5dp" >

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_sensor"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="left"
                android:textColor="@color/black"
                android:textSize="15sp" />

        </LinearLayout>
    </ScrollView>

</LinearLayout>

加速度感測器

加速度感測器是最常見的感應器,大部分智慧手機都內建了加速度感測器。

震動器

以搖一搖為例演示加速度感測器開發步驟。
過程中用到了震動器可通過我之前的文章檢視。

AccelerationActivity

public class AccelerationActivity extends AppCompatActivity implements SensorEventListener {
    private TextView tv_shake;
    private SensorManager mSensorMgr; // 宣告一個感測管理器物件
    private Vibrator mVibrator; // 宣告一個震動器物件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_acceleration);
        tv_shake = findViewById(R.id.tv_shake);
        // 從系統服務中獲取感測管理器物件
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        // 從系統服務中獲取震動器物件
        mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 登出當前活動的感測監聽器
        mSensorMgr.unregisterListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 給加速度感測器註冊感測監聽器
        mSensorMgr.registerListener(this,
                mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 加速度變更事件
            // values[0]:X軸,values[1]:Y軸,values[2]:Z軸
            float[] values = event.values;
            if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15
                    || Math.abs(values[2]) > 15)) {
                tv_shake.setText(DateUtil.getNowTime() + " 恭喜您搖一搖啦");
                // 系統檢測到搖一搖事件後,震動手機提示使用者
                mVibrator.vibrate(500);
            }
        }
    }

    // 當感測器精度改變時回撥該方法,一般無需處理
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

}

activity_acceleration

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_shake"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:text="搖一搖看看有什麼"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>

感光器

感光器也叫光線感測器,藉助與前置攝像頭的曝光,一旦遮住前置攝像頭,感測器監測到的光線強度立馬就會下降。在實際開發中,光線感測器往往用於感應手機正面的光線強弱,從而自動調節螢幕亮度。

LightActivity

public class LightActivity extends AppCompatActivity implements
        CompoundButton.OnCheckedChangeListener, SensorEventListener {
    private TextView tv_light;
    private SensorManager mSensorMgr; // 宣告一個感測管理器物件

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_light);
        CheckBox ck_bright = findViewById(R.id.ck_bright);
        // 檢查螢幕亮度是否為自動調節
        if (SwitchUtil.getAutoBrightStatus(this)) {
            ck_bright.setChecked(true);
        }
        // Android8.0之後普通應用不允許修改系統設定
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            ck_bright.setOnCheckedChangeListener(this);
        } else {
            ck_bright.setEnabled(false);
        }
        tv_light = findViewById(R.id.tv_light);
        // 從系統服務中獲取感測管理器物件
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (buttonView.getId() == R.id.ck_bright) {
            // 設定是否開啟螢幕亮度的自動調節
            SwitchUtil.setAutoBrightStatus(this, isChecked);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 登出當前活動的感測監聽器
        mSensorMgr.unregisterListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 給光線感測器註冊感測監聽器
        mSensorMgr.registerListener(this, mSensorMgr.getDefaultSensor(Sensor.TYPE_LIGHT),
                SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_LIGHT) { // 光線強度變更事件
            float light_strength = event.values[0];
            tv_light.setText(DateUtil.getNowTime() + " 當前光線強度為" + light_strength);
        }
    }

    //當感測器精度改變時回撥該方法,一般無需處理
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

}


activity_light

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <CheckBox
        android:id="@+id/ck_bright"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:padding="5dp"
        android:button="@null"
        android:checked="false"
        android:drawableLeft="@drawable/ck_status_selector"
        android:text="亮度自動調節"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <TextView
        android:id="@+id/tv_light"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:layout_gravity="left"
        android:text="看看光線變化了沒有"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>

SwitchUtil

public class SwitchUtil {

    // 設定亮度自動調節的開關
    public static void setAutoBrightStatus(Context ctx, boolean enabled) {
        int screenMode = (enabled) ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
                : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
        Settings.System.putInt(ctx.getContentResolver(),
                Settings.System.SCREEN_BRIGHTNESS_MODE, screenMode);
    }

    // 獲取亮度自動調節的狀態
    public static boolean getAutoBrightStatus(Context ctx) {
        int screenMode = Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
        try {
            screenMode = Settings.System.getInt(ctx.getContentResolver(),
                    Settings.System.SCREEN_BRIGHTNESS_MODE);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return screenMode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
    }

}

ck_status_selector

<?xml version="1.0" encoding="utf-8"?>
<selector
  xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@drawable/switch_on" android:state_checked="true"/>
    <item android:drawable="@drawable/switch_off" android:state_checked="false"/>
    <item android:drawable="@drawable/switch_off"/>
</selector>

在這裡插入圖片描述
在這裡插入圖片描述

陀螺儀

陀螺儀顧名思義是測量平衡的儀器,它的測量結果未當前與上次位置之間的傾斜角度,這個角度描述的是三維空間的夾角,因而其數值由x,y,z,三個座標軸上的角度偏移組成。由於陀螺儀幾倍三維角度的測量功能,因此它又被稱為角速度感測器。

GyroscopeActivity

public class GyroscopeActivity extends AppCompatActivity implements SensorEventListener {
    private static final float NS2S = 1.0f / 1000000000.0f; // 將納秒轉化為秒
    private TextView tv_gyroscope;
    private SensorManager mSensorMgr; // 宣告一個感測管理器物件
    private float mTimestamp; // 記錄上次的時間戳
    private float mAngle[] = new float[3]; // 記錄xyz三個方向上的旋轉角度

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gyroscope);
        tv_gyroscope = findViewById(R.id.tv_gyroscope);
        // 從系統服務中獲取感測管理器物件
        mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 登出當前活動的感測監聽器
        mSensorMgr.unregisterListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 獲取當前裝置支援的感測器列表
        List<Sensor> sensorList = mSensorMgr.getSensorList(Sensor.TYPE_ALL);
        boolean isSuitable = false;
        for (Sensor sensor : sensorList) {
            if (sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 找到陀螺儀
                isSuitable = true;
                break;
            }
        }
        if (isSuitable) {
            // 給陀螺儀感測器註冊感測監聽器
            mSensorMgr.registerListener(this,
                    mSensorMgr.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
                    SensorManager.SENSOR_DELAY_FASTEST);
        } else {
            tv_gyroscope.setText("當前裝置不支援陀螺儀,請檢查是否存在陀螺儀感測器");
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { // 陀螺儀角度變更事件
            if (mTimestamp != 0) {
                final float dT = (event.timestamp - mTimestamp) * NS2S;
                mAngle[0] += event.values[0] * dT;
                mAngle[1] += event.values[1] * dT;
                mAngle[2] += event.values[2] * dT;
                // x軸的旋轉角度,手機平放桌上,然後繞側邊轉動
                float angleX = (float) Math.toDegrees(mAngle[0]);
                // y軸的旋轉角度,手機平放桌上,然後繞底邊轉動
                float angleY = (float) Math.toDegrees(mAngle[1]);
                // z軸的旋轉角度,手機平放桌上,然後水平旋轉
                float angleZ = (float) Math.toDegrees(mAngle[2]);
                String desc = String.format("陀螺儀檢測到當前x軸方向的轉動角度為%f,y軸方向的轉動角度為%f,z軸方向的轉動角度為%f",
                        angleX, angleY, angleZ);
                tv_gyroscope.setText(desc);
            }
            mTimestamp = event.timestamp;
        }
    }

    //當感測器精度改變時回撥該方法,一般無需處理
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

activity_gyroscope

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp" >

    <TextView
        android:id="@+id/tv_gyroscope"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="請上下左右轉動手機檢視陀螺儀"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>