Google Fit API を使って、Androidで歩数を取得してみよう


# はじめに
私は、ヘルスケア事業部で、スマホの歩数計を活用したサービスの開発に携わっており、主にAndroidアプリ開発を行っております。

Androidでは、Google Fit API を使うことで、ヘルスケアに関する様々なデータを取得したり記録したりすることが出来ます。
その中でも`歩数`は、スマホ以外のデバイスや、ユーザーによる手動入力無しに計測/記録することができるため、モバイルアプリサービスに活用しやすいデータだと思います。
ということで今回は、Google Fit API を用いた歩数取得についてご紹介します。

# Fit API での情報取得
FitAPIでは、ヘルスケアに関する様々なデータを取得することが出来ます。
まずはFitAPIでの、基本的な情報取得についてご紹介します。

## 1. 導入
FitAPIを導入するためにまずは、AndroidStudioにて必要なパッケージを導入したり、認証キーを手に入れたりする必要があります。
詳しくは、[公式ガイド](https://developers.google.com/fit/android/get-started)をご覧ください。

## 2. ユーザー許可を得る
情報取得を行うためには、GoogleFitの情報にアクセスするための許可を得る必要があります。
FitnessOptionsにてアクセスしたいDataTypeを指定し、権限をリクエストします。

```Kotlin
val fitnessOptions = FitnessOptions.builder()
    .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
    .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
    .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA)
    .build()

if (!GoogleSignIn.hasPermissions(
        GoogleSignIn.getLastSignedInAccount(this),
        fitnessOptions
    )
) {
    GoogleSignIn.requestPermissions(
        this,
        REQUEST_OAUTH_REQUEST_CODE,
        GoogleSignIn.getLastSignedInAccount(this),
        fitnessOptions
    )
} else {
    readData()
}
```
DataTypeの一覧は、[こちら](https://developers.google.com/android/reference/com/google/android/gms/fitness/data/DataType)で見れます。
どのような情報が取得できるか分かるので、見てみると面白いです。

## 3. 情報を取得する
FitAPIの中には、BleApi/RecordingApi/GoalsApiなどなどありますが、情報取得に用いるのは `HistoryApi`になります。

`timeRange（情報が欲しい期間）`と`DataType（欲しい情報の種類）`を指定して`DataReadRequest`を作成し、`HistoryClient`の`readData`を呼び出してあげます。

```Kotlin
val start = 1544540400000 // 2018-12-12 00:00:00
val end = Date().time

val request = DataReadRequest.Builder()
    .setTimeRange(start, end, TimeUnit.MILLISECONDS)
    .read(dataType)
    .build()

Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
    .readData(request)
    .addOnSuccessListener {
        // it: DataReadResponse
        Log.d("onSuccess", it.toString)
    }
}
```

# Fit API を用いた歩数取得
FitAPIでの情報取得について、なんとなくイメージ持っていただけたかと思います。
つづいて、どのような歩数情報を得ることができるかをご紹介します。

歩数情報取得には複数パターンあるのですが、今回は以下の3つのDataTypeについて紹介します。

```Kotlin
DataType.TYPE_STEP_COUNT_CUMULATIVE
DataType.TYPE_STEP_COUNT_DELTA
DataType.AGGREGATE_STEP_COUNT_DELTA
```

それぞれの取得方法と、実際にどのような値が取得できるかを紹介します。

## TYPE_STEP_COUNT_CUMULATIVE
こちらは、`端末起動時からの累積値`が取得できるDataTypeです。

以下のようなコードで取得を行います。

```Kotlin
val start = 1544540400000 // 2018-12-12 00:00:00
val end = Date().time // 現在時刻を指定

// 2018-12-12 00:00 ~ 現在時刻 の累積値を取得したい
val request = DataReadRequest.Builder()
    .setTimeRange(start, end, TimeUnit.MILLISECONDS)
    .read(DataType.TYPE_STEP_COUNT_CUMULATIVE)
    .build()

Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
    .readData(request)
    .addOnSuccessListener {

        // DataTypeを指定し、データセットを取得
        val dataSet = it.getDataSet(DataType.TYPE_STEP_COUNT_CUMULATIVE)

        // データセットの中のdataPointsの中に歩数情報リストが含まれてる
        dataSet.dataPoints.forEach { point ->

            // getStartTime/getEndTime でその情報がどの時間のものかが分かる
            val start = point.getStartTime(TimeUnit.MILLISECONDS)
            val end = point.getEndTime(TimeUnit.MILLISECONDS)

            // getValueの引数にField.FIELD_STEPSを指定することで、歩数値が取得できる
            val value = point.getValue(Field.FIELD_STEPS)
        }
    }
```

そうすると、以下のような情報が取得できました。

```
 start               end                 value
 2018-12-09 21:21:06 2018-12-12 10:40:36 20121
 2018-12-09 21:21:06 2018-12-12 10:41:18 20209
 2018-12-09 21:21:06 2018-12-12 10:41:19 20211
 ...
 2018-12-09 21:21:06 2018-12-12 22:57:15 32691
 2018-12-09 21:21:06 2018-12-12 22:58:04 32761
 2018-12-12 23:52:51 2018-12-12 23:53:32 0
 2018-12-12 23:52:51 2018-12-13 00:25:12 11
 2018-12-12 23:52:51 2018-12-13 00:25:22 23
```

時間範囲指定した間の、最新の累積値だけ取得できるのかと思ったら、その範囲での累積値の変化が取得できるようでした。
注目すべきポイントが12/12 23:52:51のタイミングで、それまで一定だったstartの値が変わっていて、歩数が0にリセットされているところです。
Android端末では、端末を再起動すると歩数累積がリセットされるので、それによるものだと思います。
つまり、その様子も取得できるということになりますね。

## TYPE_STEP_COUNT_DELTA
こちらは、前回計測時との差分を取得できるDataTypeです。
コードとしては、先ほどのコードの`DataType.TYPE_STEP_COUNT_CUMULATIVE`を`DataType.TYPE_STEP_COUNT_DELTA`に変えるだけでOKです。

そうしたら、以下のような情報を取得できました。

```
start               end                 value
2018-12-12 10:39:36 2018-12-12 10:40:36 10
2018-12-12 10:40:36 2018-12-12 10:41:19 90
2018-12-12 10:41:19 2018-12-12 10:42:19 129
...
2018-12-12 22:56:15 2018-12-12 22:57:14 106
2018-12-12 22:57:14 2018-12-12 22:57:15 2
2018-12-12 22:57:15 2018-12-12 22:58:04 70
```

CUMULATIVEでは、端末再起動時以外はstartが固定されてたのに対し、こちらでは毎回startが変わっているのが分かると思います。
このように、DELTAでは、一定時間ごとにその間での歩数を取得することができます。これらを足し合わせていったら、CUMULATIVEで取得した値になるということですね。

## AGGREGATE_STEP_COUNT_DELTA
こちらは、指定した間隔ごとに値が集計された結果を、取得することができるDataTypeです。
例えば、日ごとに集計したい場合は以下のようなコードになります。

```Kotlin
val start = 1544540400000 // 2018-12-12 00:00:00
val end = Date().time // 現在時刻

val request = DataReadRequest.Builder()
    .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
    .setTimeRange(start, end, TimeUnit.MILLISECONDS)
    .bucketByTime(1, TimeUnit.DAYS) // 集計間隔を1日毎に指定
    .build()

Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
    .readData(request)
    .addOnSuccessListener {
        val buckets = it.buckets // 集計データはbucketsというところに入ってくる
        buckets.forEach { bucket ->
            val start = bucket.getStartTime(TimeUnit.MILLISECONDS)
            val end = bucket.getEndTime(TimeUnit.MILLISECONDS)
            val dataSet = bucket.getDataSet(DataType.AGGREGATE_STEP_COUNT_DELTA)
            val value = dataSet.dataPoints.first().getValue(Field.FIELD_STEPS)
            Log.d("Aggregate", "$start $end $value")
        }
    }
```

そうすると、以下のような情報が取得できました。

```
start               end                 value
2018-12-12 00:00:00 2018-12-13 00:00:00 12650
2018-12-13 00:00:00 2018-12-13 02:21:34 52
```

つまりこれは、日毎の歩数ですね。これは大変便利ですね！
歩数計サービスにおいては一番使う機能な気がします。

# まとめ
GoogleFitAPIを使えば、スマホで計測した歩数を、色んなパターンで受け取ることができます。
作りたいサービスによって使い分けることが出来ると良い感じですね！

GoogleFitAPIにはまだまだ色んな機能があります。
こちらを活用して、ヘルスケアサービスをどんどん盛り上げていけたらと思います！