Android/wear os

Wear OS 심박수 센서 사용

zigo0 2023. 5. 1. 09:05

Wear OS(갤럭시 워치4) 심박수 센서사용에 대한 내용이 별로 없어 기록용으로 작성한다.

따라서 부정확한 내용이 존재 할 수 있다.

 

심박수 센서와 타이머 기능을 가진 어플을 만들 것이다.

 

권한 설정

 

우선 심박수 센서를 사용하기 위해선 권한을 받아야한다. 

필요한 권한은 다음과 같다.

Manifest.permission.BODY_SENSORS

 

아래와 같이 입력해 권한을 체크 하도록 한다.

if (checkSelfPermission(Manifest.permission.BODY_SENSORS) != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.BODY_SENSORS}, 1);
} else {
    Log.d("11", "ALREADY GRANTED");
}

 

센서를 사용하기 위해 SensorManager를 사용한다.

mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
assert mSensorManager != null;
mHeartRateSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
mSensorManager.registerListener(mheart, mHeartRateSensor, SensorManager.SENSOR_DELAY_FASTEST);

다음과 같이SensorManager를 사용해 센서 정보를 받아온다. 

 

mHeartRateSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);

이 부분에 Sensor.TYPE_HEART_RATE 에 HEART_BEAT를 넣으면 워치의 심박수 센서가 켜지자 마자 꺼지기 때문에 꼭 TYPE_HEART_RATE를 넣어야한다.

 

 

mSensorManager.registerListener(mheart, mHeartRateSensor, SensorManager.SENSOR_DELAY_FASTEST);

마지막 부분이 센서를 등록하는 부분으로 이부분이 센서를 동작시키는 코드이다. 여기서 SensorEventListener와 SenserManager에서 받아온 Sensor.TYPE_HEART_RATE의 정보, 마지막으로 센서 속도를 지정 할 수 있다.

센서 속도에 대한 부분은 다음 블로그를 참고하자

안드로이드 SensorManager의 딜레이 옵션 : 네이버 블로그 (naver.com)

 

안드로이드 SensorManager의 딜레이 옵션

안드로이드에서 센서를 잡아올때  SensorManager 라는 것을 사용한다.   그리고 SensorManag...

blog.naver.com

간단하게 SENSOR_DELAY_FASTEST 가 가장 빠르다.

 

public class HeartListener implements SensorEventListener {
    
    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if(sensorEvent.sensor.getType()==Sensor.TYPE_HEART_RATE && sensorEvent.values.length>0 ) {
            float mHeartRateFloat = sensorEvent.values[0];
            int mHeartRate = Math.round(mHeartRateFloat);
            beat.setText(Integer.toString(mHeartRate));
            if(mHeartRate >= 195 && flag ==1){
                ll.setBackgroundResource(R.drawable.green);
            }else if(mHeartRate>0 && flag ==1){
                ll.setBackgroundResource(R.drawable.red);
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

}

SensorEventListener를 구현한 클래스를 만들었는데 여기서 onSensorChanged가 센서의 값이 변경되면 작동되는 코드로 센서 동작시 실행 시킬 코드를 여기에 모두 넣으면 된다.

 

전체 코드는 다음과 같다.

더보기

 

package com.kb.myapplication;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.hardware.Sensor;
import android.hardware.SensorManager;

import com.kb.myapplication.databinding.ActivityMainBinding;

import androidx.health.services.client.data.HeartRateAccuracy;
import androidx.wear.widget.BoxInsetLayout;


import org.w3c.dom.Text;

public class MainActivity extends Activity {
    HeartRateAccuracy heartRateAccuracy;
    private Chronometer chronometer;
    private boolean running;
    private long pauseOffset;
    private ActivityMainBinding binding;
    private Thread timeThread = null;
    private Boolean isRunning = true;
    private SensorManager mSensorManager;
    private Sensor mHeartRateSensor;
    private HeartListener mheart = new HeartListener();
    TextView hh;
    TextView beat;
    BoxInsetLayout ll;
    int flag = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        Button start = (Button) findViewById(R.id.start);
        Button stop = (Button) findViewById(R.id.stop);
        Button reset = (Button) findViewById(R.id.reset);
        beat = (TextView) findViewById(R.id.beat);
        hh = (TextView) findViewById(R.id.mtext);
        ll=(BoxInsetLayout) findViewById(R.id.LL);

        if (checkSelfPermission(Manifest.permission.BODY_SENSORS) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.BODY_SENSORS}, 1);
        } else {
            Log.d("11", "ALREADY GRANTED");
        }

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        assert mSensorManager != null;
        mHeartRateSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
        mSensorManager.registerListener(mheart, mHeartRateSensor, SensorManager.SENSOR_DELAY_FASTEST);

        if (mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE) != null) {
            Log.d("123123", "TYPE_HEART_RATE supports");
        } else {
            Log.d("123123", "no TYPE_HEART_RATE supports");

        }
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setVisibility(View.GONE);
                stop.setVisibility(View.VISIBLE);
                timeThread = new Thread(new timeThread());
                timeThread.start();
                flag = 1;
                if (isRunning) {
                    stop.setText("정지");
                } else {
                    stop.setText("시작");
                }
            }
        });

        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isRunning = !isRunning;
                if (isRunning) {
                    stop.setText("정지");
                } else {
                    stop.setText("시작");
                }
            }
        });


        reset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                timeThread.interrupt();
                isRunning = true;
                hh.setText("00:00:00:00");
                ll.setBackgroundResource(R.drawable.dark);
                start.setVisibility(View.VISIBLE);
                stop.setVisibility(View.GONE);
                flag = 0;
            }
        });

    }

    @SuppressLint("HandlerLeak")
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            int mSec = msg.arg1 % 100;
            int sec = (msg.arg1 / 100) % 60;
            int min = (msg.arg1 / 100) / 60;
            int hour = (msg.arg1 / 100) / 360;
            //1000이 1초 1000*60 은 1분 1000*60*10은 10분 1000*60*60은 한시간

            @SuppressLint("DefaultLocale") String result = String.format("%02d:%02d:%02d:%02d", hour, min, sec, mSec);
            hh.setText(result);
        }
    };


    public class timeThread implements Runnable {
        @Override
        public void run() {
            int i = 0;

            while (true) {
                while (isRunning) { //일시정지를 누르면 멈춤
                    Message msg = new Message();
                    msg.arg1 = i++;
                    handler.sendMessage(msg);

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                hh.setText("");
                                hh.setText("00:00:00:00");
                            }
                        });
                        return; // 인터럽트 받을 경우 return
                    }
                }
            }
        }
    }


    public class HeartListener implements SensorEventListener {

        @Override
        public void onSensorChanged(SensorEvent sensorEvent) {
            if(sensorEvent.sensor.getType()==Sensor.TYPE_HEART_RATE && sensorEvent.values.length>0 ) {
                float mHeartRateFloat = sensorEvent.values[0];
                int mHeartRate = Math.round(mHeartRateFloat);
                beat.setText(Integer.toString(mHeartRate));
                if(mHeartRate >= 195 && flag ==1){
                    ll.setBackgroundResource(R.drawable.green);
                }else if(mHeartRate>0 && flag ==1){
                    ll.setBackgroundResource(R.drawable.red);
                }
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int i) {

        }

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSensorManager.unregisterListener(mheart);
    }
}