スマートウォッチ(Wear OS by Google 2.x)で直接iBeacon(Bluetooth Low Energy)を受信してみた

# はじめに

Wear OS by Google 2.x からスマホを介さずにネットワーク接続できるようになったので、スマートウォッチを買う決意をしました！
折角なのでスマートウォッチ単体で、何かできないかな？と思い、単独でiBeaconを受信してみました。

## できたこと

今回できたことは、以下となります。

* Casio Pro Trek smart WSD-F30 で動作
* 単独でiBeaconを受信

## 課題(これからやること)

時間の関係上、ちょっとできなかったのは以下となります。
近いうちに作成して、GitHubに投稿しようかと思ってます。

* onPauseになると受信停止してしまう(サービス化予定)
* 受信データの画面表示

# AltBeacon準備

受信にAltBeaconを利用しました。app.gradleに以下を追加します。

```gradle
...
    implementation 'org.altbeacon:android-beacon-library:2.16.2'
...
```

全体は以下となります。

```gradle:app.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 26
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.android.support:wearable:2.4.0'
    implementation 'com.google.android.gms:play-services-wearable:17.0.0'
    implementation 'androidx.percentlayout:percentlayout:1.0.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.0.0'
    implementation 'com.android.support:wear:28.0.0'

    implementation 'org.altbeacon:android-beacon-library:2.16.2'

    compileOnly 'com.google.android.wearable:wearable:2.4.0'
}
```

# Beacon受信

とりあえず、受信してログに出力してみました。
パーミッションの設定も含めて以下のようにするとできました。

```java:MainActivity.java
package com.example.myapplication;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.wearable.activity.WearableActivity;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.MonitorNotifier;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;

import java.util.Collection;

public class MainActivity extends WearableActivity implements BeaconConsumer {
    protected static final String TAG = "MonitoringActivity";
    private BeaconManager beaconManager;

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text);

        // Enables Always-on
        setAmbientEnabled();

        checkPermissions();
    }

    private void checkPermissions() {
        int isPermittedBluetooth = ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH);
        int isPermittedBluetoothAdmin = ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN);
        int isPermittedCoarseLocation = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);

        if (isPermittedBluetooth != PackageManager.PERMISSION_GRANTED ||
                isPermittedBluetoothAdmin != PackageManager.PERMISSION_GRANTED ||
                isPermittedCoarseLocation != PackageManager.PERMISSION_GRANTED) {
            // https://qiita.com/sho5nn/items/6598268cfc3eda051a2a
            requestPermissions(
                    new String[]{
                            Manifest.permission.BLUETOOTH,
                            Manifest.permission.BLUETOOTH_ADMIN,
                            Manifest.permission.ACCESS_COARSE_LOCATION
                    },
                    0
            );
        } else {
            initialzeBeaconReceiving();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        initialzeBeaconReceiving();
    }

    public static final String IBEACON_FORMAT = "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24";

    private void initialzeBeaconReceiving() {
        beaconManager = BeaconManager.getInstanceForApplication(this);
        // BeaconParseを設定
        beaconManager.getBeaconParsers().clear();
        beaconManager.getBeaconParsers()
                .add(new BeaconParser().setBeaconLayout(IBEACON_FORMAT));
        beaconManager.bind(this);
    }

    @Override
    public void onBeaconServiceConnect() {
        beaconManager.removeAllMonitorNotifiers();

        beaconManager.addRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
                Log.i(TAG, "received beacons: " + collection.size());
            }
        });

        try {
            beaconManager.startRangingBeaconsInRegion(new Region("test", null, null, null));
        } catch (RemoteException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        beaconManager.unbind(this);
    }
}

```

# 参考

* [AltBeacon - Smaple Code](https://altbeacon.github.io/android-beacon-library/samples.html)