Androidのヒンジ角度センサに関しての補足

# はじめに
- [ヒンジ角度センサに関する記事](https://qiita.com/etctaro/items/058aa8495f3457aae34e)をすでに投稿しましたが、いくつか積み残しのタスクがありました。
- ということで、今回は積み残しのそれぞれに対応してみます。

# 2番目のヒンジ角度センサの値を取得する
こんな感じで変更を加えました。

- Before

```kotlin
val hingeSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
sensorManager.registerListener(this,hingeSensor,SensorManager.SENSOR_DELAY_NORMAL)
```

- After

```kotlin

val hingeSensors = sensorManager.getSensorList(Sensor.TYPE_HINGE_ANGLE)
for (hingeSensor in hingeSensors) {
    sensorManager.registerListener(this, hingeSensor, SensorManager.SENSOR_DELAY_NORMAL)
}
```

- なんてことはありませんでした。複数のセンサがあるのだから、それぞれを登録する、というただそれだけですね。

ただし、onSensorChangedで値を得て、何かをする際に意識すべきこととして、
値を上げてきたセンサはどちらのセンサか？という点があります。

前回の記事のログより、センサの情報は以下の様になるので、区別する方法はnameくらいしかなさそうです。このため、センサの値を集める時は、nameもセットにする必要がありそうです。

```
{Sensor name="Goldfish hinge sensor0 (in degrees)", vendor="The Android Open Source Project", version=1, type=36, maxRange=360.0, resolution=1.0, power=3.0, minDelay=10000}, 
{Sensor name="Goldfish hinge sensor1 (in degrees)", vendor="The Android Open Source Project", version=1, type=36, maxRange=360.0, resolution=1.0, power=3.0, minDelay=10000},
```

# Postureを扱う

※JetpackのWindow Managerは2020/7/10時点ではリリースされたばかりですのでご注意ください。

現時点の端末の折りたたみの状態(Posture)を取得するためには、[DeviceState.getPosture()](https://developer.android.com/reference/androidx/window/DeviceState#getPosture())を使います。

上記のAPIを使う部分がわかりづらかったので、WindowManagerの使い方含めてサンプル実装してみました。
ボタンをタップするとその時点での端末のPostureの値を取得する様な処理になります。

## WindowManagerの利用設定(dependencyを設定すれば良い)

```groovy
dependencies {
    implementation "androidx.window:window:1.0.0-alpha01"
}
```

## WindowManagerの取得

```kotlin
class MainActivity : AppCompatActivity(), SensorEventListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(findViewById(R.id.toolbar))

        val wm = WindowManager(this, null)
        // ... (略)
    }
```

WindowManagerコンストラクタの第二引数である[WindowBackend](https://developer.android.com/reference/androidx/window/WindowBackend)は端末の状態などを取得しようとした時に、特殊な処理を入れる場合に指定します。
デフォルトはnullでよいです。

## DeviceState.getPosture()の呼び出し

```kotlin
        findViewById<Button>(R.id.getPosture).setOnClickListener { view ->

            val posture = wm.deviceState.posture
            Log.d("POSTURE_TEST", posture.toString())
        }
```

例えばヒンジの角度を変え、開いている状態なら3、半開きなら2、閉じているなら1などとpostureの値を取得できます。

# Postureの変更を検知して処理を実行する

Postureの変更を検知する場合は、[WindowManager#registerDeviceStateChangeCallback](https://developer.android.com/reference/androidx/window/WindowManager#registerDeviceStateChangeCallback(java.util.concurrent.Executor,%20androidx.core.util.Consumer%3Candroidx.window.DeviceState%3E))にExecutorと変更検知の際のコールバックを登録してあげればよいです。

例えば、登録ボタンタップ時に変更の検知を開始して、解除ボタンタップ時に検知を終了する様な処理については以下の通りです。
実装の際は、registerを複数回実行を避ける様にしてください。

```kotlin
        val mainThreadExecutor = Executor { Handler(Looper.getMainLooper()).post(it) }

        val deviceStateChangeCallback = Consumer<DeviceState> {
            Log.d("CHANGE_POSTURE", it.posture.toString())
        }

        findViewById<Button>(R.id.registerChangePosture).setOnClickListener { view ->
            Log.d("CHANGE_POSTURE", "register")
            wm.registerDeviceStateChangeCallback(mainThreadExecutor,
                deviceStateChangeCallback)
        }

        findViewById<Button>(R.id.unregisterChangePosture).setOnClickListener { view ->
            Log.d("CHANGE_POSTURE", "unregister")
            wm.unregisterDeviceStateChangeCallback(deviceStateChangeCallback)
        }
```

# 参考
- WindowManagerについては[公式のサンプル](https://android.googlesource.com/platform/frameworks/support/+/6225ee655392b2e674b6da38895d1bb0f78c5baf)を一部参考にしました。