PebbleでAndroid上の画像スライドを遠隔操作

以前[Pebbleでパワポを遠隔操作](http://qiita.com/daiki7nohe/items/cb784e437c6831c016ca)に挑戦したんですが、今回は自分でPebbleアプリを作ってみたかったのでやってみました。ついでにAndroidとの連携にも挑戦しました。

Pebbleのボタンからもジェスチャーからでも遠隔操作できます。

[デモ動画](https://youtu.be/lRDhp5ZHVnA)



だいたいドキュメンテーションなどにあるサンプルをそのまま使っているだけだったりするのでざっくりと説明していきます。


#準備

Pebbleアプリ開発
- Pebbleウォッチ（デバッグ用、初代Pebble使用）
- Pebbleアカウント
- CloudPebble IDE (https://cloudpebble.net)


Androidアプリ開発
- Androidデバイス (デバッグ用)
- Android Studio


基本Pebbleアプリ開発はクラウド上でできるので、ブラウザさえあればOKです。アプリの動作確認はCloudPebbleでできますが、今回は加速度センサのデータを取得するので実機の方が便利です。


#Pebbleアプリ開発

まず、Pebble側の方からやっていきましょう。基本的に[Pebble開発者サイト](https://developer.pebble.com)を参考にして開発しました。
開発言語はJavaScriptかCで選べるんですが、今回はCを使いました。 

Cがわからない人でも親切に[チュートリアル](https://pebble.gitbooks.io/learning-c-with-pebble/content/)が用意されているのでそれを参考にしてください。


[ソースコード](https://github.com/7nohe/pebble-remote-gallery)はGitHubに公開してあります。

一つ一つソースコードを説明すると長くなるのでドキュメンテーションのどのページを参考にしたかだけ説明していきます。


##グラフィックス

![download.png](https://qiita-image-store.s3.amazonaws.com/0/52622/527106ca-b7c5-28d4-a290-616a2f227f4d.png)

グラフィックスについてですがボタンでコントロールできるようにこんな感じにしてみました。

上ボタンで前スライド、下ボタンで次スライド、真ん中でジェスチャーモードのON/OFFになります。

[DRAWING PRIMITIVES, IMAGES AND TEXT](https://developer.pebble.com/guides/graphics-and-animations/drawing-primitives-images-and-text/)

を参考にすればできますが、今回は四角と文字の表示だけなのでコピペで簡単にできました。

##ボタンイベント

[BUTTONS](https://developer.pebble.com/guides/events-and-services/buttons/)

の「Single Clicks」のところを使いました。Up、Select、Downの三つのイベントそれぞれについて必要です。


##加速度センサ

[ACCELEROMETER](https://developer.pebble.com/guides/events-and-services/accelerometer/)

このアプリでの一番の肝となるのがこの加速度センサです。
やりたかったのはPebbleを左右に振ることでスライドが振った方向にページが切り替わるという操作です。

なので左右へ強く振ったときの加速度を検知する必要があります。物理とか考えるの苦手なんでコードは実際にPebbleで何回も実験して得た値をもとになんとなくで作りました(笑)。なにかもっといいアルゴリズム的なものがあるかもしれません。

実際に加速度センサの値を扱う部分accel_data_handler()だけを紹介します。


```c:main.c
.
.

static void accel_data_handler(AccelData *data, uint32_t num_samples) {
  if(!gesture_mode)return;
  
  // Read sample 0's x, y, and z values
  //   int16_t x = data[0].x;
  //   int16_t y = data[0].y;
  int16_t z = data[0].y;
 
  
  // Determine if the sample occured during vibration, and when it occured
  bool did_vibrate = data[0].did_vibrate;
  uint64_t timestamp = data[0].timestamp;
 
  if(!did_vibrate) {
    // Print it out
    //     APP_LOG(APP_LOG_LEVEL_INFO, "x: %d, y: %d, z: %d", x, y, z);
    APP_LOG(APP_LOG_LEVEL_INFO, "z: %d preZ: %d (z-preZ): %d", z, preZ, (z-preZ));
    if(delay > 0){
      preZ = z;
       delay--;
    }else if((z-preZ) > 400){
      APP_LOG(APP_LOG_LEVEL_DEBUG, "Next: %d", (z-preZ));
      send_data(1);
      delay = 5;
    }else if((z-preZ) < -400){
      APP_LOG(APP_LOG_LEVEL_DEBUG, "Back %d", (z-preZ));
       send_data(2);
      delay = 5;
    }else{
      preZ = z;
    }
  } else {
    // Discard with a warning
    APP_LOG(APP_LOG_LEVEL_WARNING, "Vibration occured during collection");
  }
  
}


```

内容としては、

加速度のz値のみを毎回読んでひとつ前のｚ値（preZ）と現在のｚ値の差が大きいとき(-400 < z-preZ < 400)振ったことを検知しています。

delayに関しては、振り始めと振り終わり両方とも値の大きな変化が起こるので、振り始めのみ検出するように少し遅延？というかただ少しの間スキップするようにしています。




##通信

[SENDING AND RECEIVING DATA](https://developer.pebble.com/guides/communication/sending-and-receiving-data/)

AndroidとPebble間の通信なんですが、シンプルにint型の1（次スライド）か2（前スライド）の値をジェスチャーを検知したらAndroid側へ送るだけです。

コードについてなんですが、いろいろとコールバックを用意してます。Inboxの受信成功、失敗コールバック。Outboxの送信成功、失敗コールバック。

送信については送る値のタイプによってメソッドが変わるんですが、基本的な流れとしては

Outboxバッファ用意　→　送信したいデータを辞書へ書き込み　→　送信

となります。


以上が今回行ったPebble側での開発です。


##実機確認

CloudPebbleではAndoridデバイス上のPebble公式アプリの設定で"Enable Developer Mode"をオンにして、"Developer Connection"を"Enable"にすることでCloudPebbleのBuildボタンでPebble実機に直接インストールしてアプリの動作とログを確かめることができます。



#Androidアプリ開発

メインの[ソースコード](https://github.com/7nohe/pebble-remote-gallery-android)はGitHubに公開してまります。

##セットアップ

Android側での受信は

[PEBBLEKIT ANDROID](https://developer.pebble.com/guides/communication/using-pebblekit-android/)

を見ると分かると思いますが、まずAndroidでPebbleKitを使えるようにします。
Android StudioのプロジェクトのModule:appの方のbuild.gradleに


```java:app/build.gradle
dependencies {
    compile 'com.getpebble:pebblekit:3.1.0@aar'
}
```

を追加します。

さらにdependenciesのすぐ下にSonatype OSSレポジトリも追加します。

```java:app/buid.gradle
repositories {
    mavenCentral()
    maven { url "https://oss.sonatype.org/content/groups/public/" }
}
```

これでPebbleKitが使えるようになります。


##メッセージ受信

アンドロイド側のメッセージの受信は簡単で、PebbleKit.PebbleDataReceiverのインスタンスを定義してreceiveData()オーバーライドメソッドの中身で受けとったデータをどうにかしてやればいいのです。

コードはPebbleDataReceiverに関する部分だけを記述しています。


```java:MainActivity.java
public class MainActivity ... {
 final UUID APP_UUID = UUID.fromString("自分のアプリUUID");
 PebbleKit.PebbleDataReceiver dataReceiver;
 .
 .
 .


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        .        
        .
        .


        // Create a receiver to collect logged data
        dataReceiver = new PebbleKit.PebbleDataReceiver(APP_UUID) {

            @Override
            public void receiveData(Context context, int transaction_id,
                                    PebbleDictionary dict) {
                // A new AppMessage was received, tell Pebble
                PebbleKit.sendAckToPebble(context, transaction_id);

                // If the tuple is present...
                Long value = dict.getInteger(0);
                if(value != null) {
                    // Read the integer value
                    int data = value.intValue();

                    Log.d(TAG, "Data: " + data);


                }else{
                    Log.d(TAG, "Data is null");
                }
            }

        };
    }

    @Override
    public void onResume() {
        super.onResume();

        // Register the receiver
        PebbleKit.registerReceivedDataHandler(getApplicationContext(), dataReceiver);
    }
}
```

「自分のアプリUUID」はCloudPebble IDEの自分のプロジェクトページの"Setting" > "APP UUID"から知ることができます。



##スライドの作成

ViewPageを使って複数の画像をスライド形式で表示させます。

[Using ViewPager for Screen Slides](https://developer.android.com/training/animation/screen-slide.html)

この公式チュートリアルとほぼ同じことをしているのでコードは割愛します。スライドの中身をテキストから画像に差し替えただけです。

手順としては、

スライドの中身となるViewを作成　→　ViewPager用Fragment作成　→　メインのActivityとレイアウトにViewPager追加の記述

となります。


##スライド切り替え

最後にPebble側から受信した値によってスライドを切り替えます。

さきほどのreceiveData()内で受けとった値dataをつかってViewPager mPagerを操作していきます。


```
 if(data == 1){
   int currentPage = mPager.getCurrentItem();
   mPager.setCurrentItem(currentPage - 1);
 }else if(data == 2){
   int currentPage = mPager.getCurrentItem();
   mPager.setCurrentItem(currentPage + 1);
 }

```

このように1を受けとったら前スライドへ、２を受けとったら次スライドへと操作します。


#まとめ

これでAndroidとPebbleプロジェクト両方ビルドして動かしてみるとPebbleのボタンまたはジェスチャーでAndroid上の画像スライドをBluetoothで遠隔操作できます。

余談になりますが、私はいまだに初代Pebbleを使っています。
知らぬ間に新しいPebbleがカラーになったり、丸くなったりフィットネス対応しちゃったりでいろいろありますが、日本でももっと広まればいいなと願っております。