Google Glassで作る近未来アプリケーション(6)

Google Glassで作る近未来アプリケーション(6)

Google Glass XE16で追加された新機能「Bluetooth LE」「多言語対応」「新たなアイ・ジェスチャー」

2014年5月12日

Google GlassのアップデートXE16で追加された主要な新機能をサンプルコードを交えて解説。特にBLE/iBeaconサポートは要注目だ。

Yahoo, inc 堀川 隆弘(poly.hatenablog.com
  • このエントリーをはてなブックマークに追加

はじめに

 4月15日に、Google Glassの新たなソフトウェア・アップデート「XE16」が配信された。今回のアップデートの目玉はAndroid 4.4 KitKatへのアップデートであり(アップデート前はAndroid 4.0.3 Ice Cream Sandwich)、Google Glassが公開されてから最も大きなソフトウェア・アップデートと言えるだろう(なお次のバージョンXE17も既に公開されているが、変更はバグ修正が主で、機能の変更はほとんどない) 。今回は、XE16のアップデートで追加された新機能の中から個人的に注目している「BLE」「多言語対応」「新たなアイ・ジェスチャー」の3つを紹介する。

BLE(Bluetooth Low Energy)のサポート

 筆者が今回のアップデートで最も注目しているのが、BLE(Bluetooth Low Energy)のサポートである。BLEは省電力で動作する近距離無線通信規格で、「ボタン電池1個で数年動作できる」と言われている。iPhoneは4S以降、AndroidはOSバージョン4.3以上の多くの端末でサポートしている他、FitbitUP24などのスマートフォンと連携するウェアラブルデバイスでもサポートしている端末は多い。

 BLEを利用した仕組みの中で特に注目されているのがiBeaconだ。iBeaconはアップルがiOS 7以降に標準搭載している技術で、BLEを利用して主に屋内測位を行うための仕組みである。電波を発するビーコン端末と、それを受信するデバイス(スマートフォンやウェアラブルデバイス)から成り、受信デバイス側で、ビーコンのIDなどの情報や、ビーコンまでの距離を取得できる。使い方としては、ビーコン端末を店内に設置し、ユーザーが受信デバイスを持って来店すると、デバイス上におすすめ商品などの情報を表示する、といった使い方ができる。

 iBeaconはアップルが商標登録している技術ではあるが、BLEの上に構築された仕様なので、BLEに対応しているAndroid端末でも利用できる。ただし、iOS端末はビーコンと受信デバイス両方の機能をサポートしているが、Androidは受信デバイスとしての機能しかサポートしていない。よってGlass同士や、GlassとAndroid間の通信は今のところできない。これはAndroidが、BLEのperipheral(周辺機器)のロールをまだサポートしていないからで、将来的にperipheralロールがサポートされれば、Glass同士の通信なども可能になると考えられる。

リージョン監視とレンジング

 iBeaconとの通信処理は、リージョン監視レンジングの2種類がある。

 リージョン監視は、ある特定のUUIDやMajor、Minor(同一UUIDの中でビーコンを区別するための属性値)の値を持つビーコンのエリアへの出入りを監視する処理で、バックグラウンドで動作する。

 レンジングは、今現在、エリア内にある、ビーコンの情報を取得する処理だ。

 基本的な流れとしては、まずリージョン監視でビーコンエリアへの出入りを監視し、エリアに入ったらレンジングでそのビーコンの情報を取得する。

リージョン監視とレンジングについて

BLEのサンプルプロジェクト

 今回は、iBeaconデバイスの先駆けとして有名な「Estimote」(次の写真)を利用して実験を行う。実物を持っていない場合でも、Estimoteとほぼ同じ振る舞いをする「Estimote Virtual Beacon」というiOSアプリが公開されているので、iPhone 4S以降のiOS端末を持っている場合はこちらを使ってもよいだろう。

 Estimoteとの通信にはEstimote SDK for Androidを利用する。そのSDKのデモプロジェクトを、筆者がGlass用に書き換えたものをGitHubで公開しているのでそちらも参考にしてほしい。

Estimoteビーコン
リージョン監視

 まずはメインの処理を行うBeaconManagerクラスのオブジェクトを初期化する。以下では、監視の期間・間隔と、ビーコンエリアの出入りを検知した際の処理を記述している。

Java
beaconManager = new BeaconManager(this);

// BeaconManagerクラスは、デフォルトで25秒間隔で5秒のスキャンを行うが、setBackgroundScanPeriodメソッドで変更可能。
beaconManager.setBackgroundScanPeriod(TimeUnit.SECONDS.toMillis(1), 0);

// ビーコンエリアの出入りを検知した際のイベントリスナーを設定
beaconManager.setMonitoringListener(new MonitoringListener() {
  @Override
  public void onEnteredRegion(Region region, List<Beacon> beacons) {
    // ビーコンエリアに入った
    Log.d(TAG, "Entered region");
  }

  @Override
  public void onExitedRegion(Region region) {
    // ビーコンエリアから出た
    Log.d(TAG, "Exited region");
  }
});
リージョン監視のためのBeaconManager初期化処理

 次にRegionクラスのオブジェクトを作り、監視対象となるビーコンのUUID・Major・Minorを指定する。各値はnullにもでき、その場合は全ての値に当てはまることになる。

 実際のリージョン監視は、まずBeaconManager.connectメソッドでBeaconServiceに接続し、接続後、BeaconManager.startMonitoringメソッドで開始する。

Java
// 監視対象のビーコンを指定
region = new Region("PROXIMITY_UUID", MAJOR_NUMBER, MINOR_NUMBER);

// BeaconServiceに接続
beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
  @Override
  public void onServiceReady() {
    try {
      // BeaconServiceに接続できたら、リージョン監視を開始する
      beaconManager.startMonitoring(region);
    } catch (RemoteException e) {
      Log.d(TAG, "Error while starting monitoring");
    }
  }
});
リージョン監視の開始処理

 以下はGlassデモプロジェクトでのリージョン監視の画面だ。出入りを検知して、画面上の表示を書き換えている。

デモプロジェクトのリージョン監視画面
レンジング

 レンジングもまずはBeaconManagerクラスのオブジェクトを初期化する。指定されたビーコンが見つかった際の処理では、信号強度や、推定距離を表示している。

Java
// Configure BeaconManager.
beaconManager = new BeaconManager(this);
beaconManager.setRangingListener(new BeaconManager.RangingListener() {
  @Override
  public void onBeaconsDiscovered(Region region, final List<Beacon> beacons) {
    for (Beacon beacon : beacons) {
      // MACアドレス
      Log.d(TAG, "MacAddress:" + beacon.getMacAddress());
      // Proximity UUID
      Log.d(TAG, "ProximityUUID:" + beacon.getProximityUUID());
      // RSSI: 現在の位置での信号強度
      Log.d(TAG, "RSSI:" + beacon.getRssi());
      // MeasuredPower: ビーコンから1m離れていると仮定した際の信号強度
      Log.d(TAG, "MeasuredPower:" + beacon.getMeasuredPower());
      // Major Number
      Log.d(TAG, "Major:" + beacon.getMajor());
      // Minor Number
      Log.d(TAG, "Minor:" + beacon.getMinor());
      // 信号強度から推定されるビーコンまでの距離
      Log.d(TAG, "Distance:" + Utils.computeAccuracy(beacon));
    }
  }
});
レンジングのためのBeaconManager初期化処理

 Regionクラスのオブジェクトを作り、情報取得したいビーコンのUUID・Major・Minorを指定する。

 リージョン監視同様、BeaconServiceに接続し、BeaconManager.startRangingメソッドでレンジングを開始できる。

Java
// 情報を取得するビーコンのUUID・Major・Minorを指定。リージョン監視同様、各値はnullにもできる
region = new Region("regionid", "PROXIMITY_UUID", MAJOR_NUMBER, MINOR_NUMBER);

// BeaconServiceに接続
beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
  @Override
  public void onServiceReady() {
    try {
      // BeaconServiceに接続できたらレンジングを開始する
      beaconManager.startRanging(region);
    } catch (RemoteException e) {
      Toast.makeText(ListBeaconsActivity.this, "Cannot start ranging, something terrible happened",
          Toast.LENGTH_LONG).show();
      Log.e(TAG, "Cannot start ranging", e);
    }
  }
});
}
レンジングの開始処理

 以下はレンジングの実行例である。

デモプロジェクトのビーコン情報表示画面
デモプロジェクトのビーコン距離表示画面

 実際には、複数のビーコンに対する距離を取得して、より局所的な位置を推定できる。ユーザーがどこにいるかに基づいて情報を通知できるBLE/iBeaconは、Google Glassのようなウェアラブルデバイスと非常に親和性が高く、期待できる技術領域だと言えるだろう。

日本語を含む多言語への対応

 すでに一部では話題になっていたが、XE16で日本語を含む英語以外の言語リソースが追加され、Glassの言語設定を日本語に切り替えることにより、日本語表示や日本語による音声認識/音声合成にも対応するようになった。

 Glassの標準機能で言語を切り替えることは今のところできないが、「MoreLocale 2」などの言語切り替えが可能なアプリを使うのが簡単だ。.apkファイルをダウンロードし、以下のコマンドでGlassにインストールしよう。

コンソール
$ adb install MoreLocale-2.3.1.apk
MoreLocale 2のインストール

 Android 4.2以降の制約で、このままではアプリに言語設定を切り替える権限が付与されないので、以下のコマンドをPCから実行し、権限を付与する必要がある。

コンソール
$ adb shell pm grant jp.co.c_lis.ccl.morelocale android.permission.CHANGE_CONFIGURATION
設定権限を書き換える権限の付与

 「ok glass, more locale」の音声コマンドでアプリを起動できる。さっそく日本語に切り替えてみよう。

MoreLocale 2での地域/言語設定画面

 その後、ホーム画面に戻ると、画面上の一部が日本語化されているのが分かる。

日本語化されたGlassの画面

 音声コマンドでは、日本語はまだ認識されないようだが、音声コマンドの後に続くキーワードには日本語を使うことができる。以下は「ok glass, google」の後の検索クエリに日本語を認識させた例だ。

日本語の音声認識結果

 また、音声合成も日本語に対応している。以下のようにAndroid SDKに含まれるTextToSpeechクラスを使って、アプリから日本語をしゃべらせることも可能だ。

Java
final TextToSpeech tts = new TextToSpeech(context, new OnInitListener() {
  @Override
  public void onInit(int status) {
    tts.setLanguage(Locale.JAPANESE);
    tts.speak("こんにちわ、日本語で話しています。", TextToSpeech.QUEUE_ADD, null);
  }
});
音声合成で日本語をしゃべらせるサンプル

新たなアイ・ジェスチャーのサポート

 一般には公開されていないのだが、XE16の内部を解析すると、従来の「Wink」などのアイ・ジェスチャーに加えて、「LookAtScreen」という新たなアイ・ジェスチャーがサポートされていることが分かっている。これはGlassのスクリーンに目を向けた瞬間に発動されるアイ・ジェスチャーだ。このジェスチャーには非公開のAPIを使ってアクセスできるので、一足先に実験として使ってみるのも面白いだろう。

 LookAtScreenを有効にするには、まず、キャリブレーションが必要だ。Glass内部にはキャリブレーション画面が用意されているが、通常のホーム画面からはアクセスできない。PC上でadbコマンドを使って、直接、キャリブレーション画面を起動する。

コンソール
$ adb shell am start -n com.google.glass.settings/.ui.LookAtScreenCalibrationActivity
LookAtScreenキャリブレーション画面の起動

 上記コマンドを実行すると、以下のようなキャリブレーション画面が立ち上がる。画面の指示に従い、いったん目を下にそらしてから、画面上に戻すと、キャリブレーション完了の通知が表示される。

LookAtScreenキャリブレーション画面

 キャリブレーションが完了したら、非公開APIを使ってジェスチャーを検知できる。

 これには、EyeGesture用のライブラリプロジェクトをGitHubに公開しているので、まずはそれをダウンロードする。

 ダウンロードした後、EyeGestureStub以下をライブラリプロジェクトとして自分のプロジェクトに追加する。このプロジェクトは、ソースコードを見ると分かるが、クラスとメソッドの定義だけが含まれるダミーのプロジェクトである。実際には同名のクラスとメソッドが、Glass実機のフレームワーク上に存在しており、apkをGlassにインストールして動かすと、ダミーではなく、実体が使われるという仕組みになっている。

 以下がEyeGestureStubを実際に使用するサンプルコードだ。EyeGestureManagerというクラスを使って、アイ・ジェスチャー検知の開始と終了、そして検知した際のイベントリスナー登録を行う。

Java
@Override
protected void onCreate(Bundle savedInstanceState) {
  ……省略……
  // EyeGestureManagerの取得
  mEyeGestureManager = EyeGestureManager.from(this);
  // アイ・ジェスチャーを検知した際のイベントリスナーを作成
  mEyeGestureListener = new EyeGestureListener();
  ……省略……
}

// アイ・ジェスチャーを検知した際のイベントリスナーを作成
private class EyeGestureListener implements EyeGestureManager.Listener {

  @Override
  public void onEnableStateChange(EyeGesture eyeGesture, boolean paramBoolean) {
  }

  @Override
  public void onDetected(final EyeGesture eyeGesture) {
    // アイ・ジェスチャーが検知された
    Log.i(TAG, eyeGesture + " is detected");
  }
}

@Override
protected void onStart() {
  super.onStart();

  // LookAtScreen検知を有効化
  mEyeGestureManager.enableDetectorPersistently(EyeGesture.LOOK_AT_SCREEN, true);
  // LookAtScreenジェスチャーに対してイベントリスナーを登録
  mEyeGestureManager.register(EyeGesture.LOOK_AT_SCREEN, mEyeGestureListener);
}

@Override
protected void onStop() {
  super.onStop();

  // LookAtScreenジェスチャーのイベントリスナーを解除
  mEyeGestureManager.unregister(EyeGesture.LOOK_AT_SCREEN, mEyeGestureListener);
  // LookAtScreen検知を無効化
  mEyeGestureManager.stopDetector(EyeGesture.LOOK_AT_SCREEN);
}
LookAtScreenを利用するサンプル

 これでLookAtScreenのアイ・ジェスチャーを検知できるようになる。ユーザーが画面を見た瞬間に何か処理を発動するなど、面白い使い方ができそうだ。

まとめ

 Google GlassのアップデートXE16で追加された新機能について、筆者が注目している3つについて解説した。特にBLE/iBeaconについてはGoogle Glassでの利用ケースが思い付きやすく、エンドユーザーからの期待も大きい領域だと思うので、今後も要注目だ。

※以下では、本稿の前後を合わせて5回分(第2回~第6回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

2. GDKで開発できるGoogle Glassアプリの機能とは?

GDKを使うとGoogle Glassの機能をフルに活用したアプリを開発できる。3種類のUI(Static Card/Live Card/Immersion)/タッチジェスチャー/音声認識/位置情報/センサー/カメラなど、GDKの全体像を、コードを示しながら解説する。

3. 初めてのGoogle Glassアプリ開発(GDK編)

いよいよGlass開発を実践。GDKの開発環境の構築手順と、Glassware(=Glassアプリ)の作成/実行方法を説明。また、サンプルアプリのソースコードを読み解きながら、よりGlassらしいアプリの実装方法について説明する。

4. Google Glassで動くARアプリケーションの実装

Google Glassの「眼鏡型」という特性を生かしたAR(Augmented Reality: 拡張現実)アプリの開発を、サンプルソースを交えながら解説。

5. Google Glassでハンドジェスチャーを認識させてみよう

Google Glassの上で動くジェスチャーUIの実装方法を、サンプルコードを交えながら解説する。

6. 【現在、表示中】≫ Google Glass XE16で追加された新機能「Bluetooth LE」「多言語対応」「新たなアイ・ジェスチャー」

Google GlassのアップデートXE16で追加された主要な新機能をサンプルコードを交えて解説。特にBLE/iBeaconサポートは要注目だ。

サイトからのお知らせ

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • グレープシティ株式会社
  • 日本マイクロソフト株式会社