Google Glassで作る近未来アプリケーション(2)
GDKで開発できるGoogle Glassアプリの機能とは?
GDKを使うとGoogle Glassの機能をフルに活用したアプリを開発できる。3種類のUI(Static Card/Live Card/Immersion)/タッチジェスチャー/音声認識/位置情報/センサー/カメラなど、GDKの全体像を、コードを示しながら解説する。
はじめに
Google Glassの機能や特徴を紹介した前回に引き続き、今回はGDKを利用した Google Glassアプリケーション(以下、Glassware)の開発方法について具体的に解説する。前回解説した通り、Glasswareを開発するにはMirror APIとGlass Development Kit(以下、GDK)の2つの方法があるが、現在開発者が好んで使っているのはGDKであり、本稿でもGDKに絞って解説する。
GDK概要
GDKは前回述べた通りAndroid SDKの拡張で、Android SDKにカードUIやタッチジェスチャー、ボイスコマンドなどのGlass特有の機能を追加したものである。ActivityやServiceなど、Android SDKの主要なコンポーネントはそのまま使用できる。
以下GDK特有の機能について概要を解説する。
User Interface
GlasswareのUIを実装する方法は「Static Card」「Live Card」「Immersion」の3種類がある。以下の表にそれぞれの特徴をまとめる。
種類 | タイムライン上に表示されるか | ユーザー入力へのアクセス | UIの自由度 | 主な用途 |
---|---|---|---|---|
Static Card | 表示される | アクセス不可 | Cardのレイアウト(後述)に沿った形で実装する必要がある | 静的コンテンツの表示 |
Live Card | 表示される | 制約があるがアクセス可能 | 制限なし | ユーザーインタラクションの少ない動的コンテンツ |
Immersion | 表示されない | 制限なくアクセス可能 | 制限なし | ユーザーインタラクションの多い動的コンテンツ |
それぞれについて具体的に説明していこう。
Static Card
Static Cardは、タイムライン上に表示される静的な情報を表示するカードである。次のコードに示すように、Cardクラスでカードのコンテンツを設定し、TimelineManagerクラスのinsertやupdateなどのメソッドを利用して、タイムラインへの挿入や更新を行う。
TimelineManager timelineManager = TimelineManager.from(this);
Card card = new Card(context);
card.setText("Hello World!");
long timelineId = timelineManager.insert(card);
|
カードのレイアウトは設定されたコンテンツに応じて、以下のように自動的にレイアウトされる。このデザインはStatic Cardに限らずGlassでは標準的なものなので、Cardクラスを使わずに自力で描画を行う際も、できる限りこのレイアウトに合わせた方がよいだろう。
- 1 Card.setTextメソッドで設定されたテキストが560×240pxの赤い部分に表示される。文字列長によって、文字サイズは自動調整される。
- 2 Card.setFooterメソッドで設定されたフッターが560×40pxの青い部分に表示される。
- 3 全体サイズは640×360px。Card.addImageメソッドで画像が設定されており、かつ「Card.setImageLayout(
Card.ImageLayout.FULL)」が指定されている場合は、この領域にフルで表示される。 - 4 Card.addImageメソッドで画像が設定されており、かつ「Card.setImageLayout(
Card.ImageLayout.LEFT)」が指定されている場合は、この紫色で囲まれた領域に、テキストではなく画像が表示される。
Live Card
Live Cardはタイムライン上に表示され、動的に内容が更新されるカードである。Live Cardを作るには、バックグラウンドで動作するServiceが必要だ。図2はタイムラインとServiceの関係を図解したものである。音声コマンドで発行されるIntentによって、アプリのServiceが起動される。Serviceは、バックグランドに常駐し、必要に応じてカードの更新を行う。
Live Cardはセンサーなどのハードウェアには制限なくアクセスでき、またUIもさまざまなViewコンポーネントを組み合わせて自由に描画できる。ただし、ユーザー入力の取得には制限があり、例えばスワイプなどのイベントは取得できない(画面がタイムライン上に存在するため、スワイプ操作はタイムライン上の移動処理が優先される)。
グーグルがGitHubに公開しているGDKサンプルのほとんどが、このLive Cardを利用したアプリだ。実際の利用例については、後でコンパスアプリのソースを基に解説する。
Immersion
「Immersion」というのは日本語に訳すと「没入」という意味になり、その名が示す通り、「Glassのタイムラインで構成された世界をいったん離れ、別のアプリの中に浸ること」を意味する。AndroidのActivityで実装し、従来のAndroidアプリの開発と実装方法はほぼ同じである。ユーザー入力の取得は、タッチジェスチャーを含めて制限なくアクセスでき、UIも自由に組み立てることもできる。またセンサーやカメラなどのハードウェアもフル活用でき、実装の自由度は最も高い。
タッチジェスチャー
GDKを通じて、タップやスワイプ・スクロールなど、Glassのタッチパッドでよく使われるジェスチャーを検知できる。タッチジェスチャーの検知には、GestureDetectorクラスが使われる。ちなみにAndroid SDKにも同名のクラスが含まれるが、Glass用のGestureDetectorクラスは属するパッケージが異なる。
GestureDetectorの登録
GestureDetectorを利用するには、Activity単位(=画面全体)でジェスチャーを検知する方法と、View単位(=画面の一部)で検知する方法の2種類があるが、ここではActivity単位で検知する方法について解説する。
ジェスチャーを検知するためには、次のコードに示す通り、まずGestureDetectorクラスのオブジェクトを作成し、ジェスチャー発生時のイベントを受け取るためにGestureDetector.BaseListenerインターフェースの実装を登録する。ActivityのonGenericMotionEventメソッドをオーバーライドして、GestureDetector.onMotionEventメソッドにMotionEventオブジェクトを渡せば、ジェスチャー発生時にBaseListener.onGestureメソッドが呼び出される。以下のサンプルコードでは、1本指タップと2本指タップ、左右のスワイプを検知しているが、それに加えて表2に挙げたジェスチャーイベントを受け取ることが可能である。また、GestureDetector.BaseListener以外にも、GestureDetector.FingerListenerインターフェースの実装で指本数の変化、GestureDetector.ScrollListenerインターフェースの実装でスクロール移動量や速度を取得できる。
public class MainActivity extends Activity {
private GestureDetector mGestureDetector;
// ……省略……
@Override
protected void onCreate(Bundle savedInstanceState) {
// ……省略……
mGestureDetector = createGestureDetector(this);
}
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
@Override
public boolean onGesture(Gesture gesture) {
if (gesture == Gesture.TAP) {
// 1本指タップ時の動作
return true;
} else if (gesture == Gesture.TWO_TAP) {
// 2本指タップ時の動作
return true;
} else if (gesture == Gesture.SWIPE_RIGHT) {
// 右スワイプ時の動作
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
// 左スワイプ時の動作
return true;
}
return false;
}
});
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
@Override
public void onFingerCountChanged(int previousCount, int currentCount) {
// 指の本数が変化した際の処理
}
});
gestureDetector.setScrollListener(new GestureDetector.ScrollListener() {
@Override
public boolean onScroll(float displacement, float delta, float velocity) {
// スクロールが発生した際の処理
}
});
return gestureDetector;
}
/*
* Send generic motion events to the gesture detector
*/
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}
}
|
定数名 | イベント内容 |
---|---|
Gesture.TAP | 1本指タップ |
Gesture.SWIPE_DOWN | 1本指下スワイプ |
Gesture.SWIPE_LEFT | 1本指左(後ろ方向)スワイプ |
Gesture.SWIPE_RIGHT | 1本指右(前方向)スワイプ |
Gesture.SWIPE_UP | 1本指上スワイプ |
Gesture.LONG_PRESS | 1本指長押し |
Gesture.TWO_TAP | 2本指タップ |
Gesture.TWO_SWIPE_DOWN | 2本指下スワイプ |
Gesture.TWO_SWIPE_LEFT | 2本指左スワイプ |
Gesture.TWO_SWIPE_RIGHT | 2本指右スワイプ |
Gesture.TWO_SWIPE_UP | 2本指上スワイプ |
Gesture.TWO_LONG_PRESS | 2本指長押し |
Gesture.THREE_TAP | 3本指タップ |
Gesture.THREE_LONG_PRESS | 3本指長押し |
音声認識
GDKを使って、Glasswareを起動するための音声コマンドを定義したり、ユーザーがしゃべった言葉をそのまま取得するための音声認識画面を起動したりできる。なお、現時点では音声認識に対応する言語は英語のみなので、以下の例でも英語の文章を例として解説する。
音声コマンドの定義
Glasswareを起動する(「ok glass」に続く)音声コマンドを定義するためには、まずres/xmlフォルダー内に、XMLリソースファイルを用意する必要がある。ファイル名は自由だが、ここでは仮に「my_voice_trigger.xml」というファイルを作ったと仮定する。以下の例では「hello glass」という音声コマンドを定義している。
<?xml version="1.0" encoding="utf-8"?>
<trigger keyword="hello glass" />
|
以下のように<input>タグをXMLファイルに追加することで、音声コマンドの後にさらに音声認識を促し、しゃべったフレーズを取得できる。「ok glass, google ……検索語句……」の後に検索語句を認識させるのと同じ要領だ。
<?xml version="1.0" encoding="utf-8"?>
<trigger keyword="hello glass">
<input prompt="tell me what's on your mind" />
</trigger>
|
アプリの起動
音声コマンド認識後は、音声コマンド用のアクションがセットされたIntentが発行されるため、Intent FilterをAndroidManifest.xmlファイルに追加し、ActivityまたはServiceが起動するようにしておく。以下の例では、MainActivityクラスが音声コマンドに反応して起動する。
<?xml version="1.0" encoding="utf-8"?>
<application ……省略……>
<activity android:name=".MainActivity">
<intent-filter>
<action
android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="@xml/my_voice_trigger" />
</activity>
// ……省略……
</application>
|
音声認識結果の取得
音声コマンドの後に追加で音声認識を行った場合、IntentのExtraに認識結果が入っているので、ActivityやServiceで以下のように文字列が取得できる。
ArrayList<String> voiceResults = getIntent().getExtras()
.getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
|
音声認識画面の起動
ホーム画面で音声コマンドを使う以外に、GlasswareはRecognizerIntent.ACTION_RECOGNIZE_SPEECHアクションを指定してIntentを発行することで、好きなタイミングで音声認識の画面を呼び出せる。結果はActivity.onActivityResultメソッドをオーバーライドして受け取る。
private static final int SPEECH_REQUEST = 0;
private void displaySpeechRecognizer() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
startActivityForResult(intent, SPEECH_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
List<String> results = data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
// resultsに音声認識された結果が入っている
}
super.onActivityResult(requestCode, resultCode, data);
}
|
位置情報
位置情報の取得に関しては、以下のコードに示すように、Android SDKに含まれるLocationManager/LocationProvider/Criteriaなどのクラスを利用する。
ただし、Glass特有の注意事項もある。前回解説したように、Glass自体はGPSチップを持っていない。位置情報のプロバイダーとしては、Glass自身のWi-Fi接続や、Bluetooth経由でスマートフォンのGPSなどのリモートプロバイダーを含め、複数のリソースが使われる可能性がある。そのためGlassでは、どれか1つの位置情報プロバイダーを使うのではなく、全ての使用可能なプロバイダーから位置情報を検出することを推奨している。
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
// この例ではCriteriaで正確性の高い位置情報のみを取得するように指定しているが、
// 必要に応じてどんな条件(Criteria)でも構わない。
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
// 有効な全ての位置情報プロバイダーに対してリスナーを登録する。
List<String> providers = locationManager.getProviders(criteria, true);
for (String provider : providers) {
locationManager.requestLocationUpdates(provider, minTime, minDistance, listener);
}
|
センサー
各種センサーは、Android SDKに含まれるSensorManagerクラスを通じてアクセスできる。以下が利用可能なセンサーの一覧である。
定数名 | イベント内容 |
---|---|
TYPE_ACCELEROMETER | 加速度センサー |
TYPE_GRAVITY | 重力センサー |
TYPE_GYROSCOPE | ジャイロスコープセンサー |
TYPE_LIGHT | 照度センサー |
TYPE_LINEAR_ACCELERATION | 線形加速度センサー |
TYPE_MAGNETIC_FIELD | 磁気センサー |
TYPE_ORIENTATION | 方向センサー(ただし利用は非推奨) |
TYPE_ROTATION_VECTOR | 回転ベクトルセンサー |
カメラ
Glassでカメラを活用するには、2種類のオプションがある。1つは、Glassデフォルトのカメラ撮影用ActivityをIntentで呼び出す方法、もう1つは、Android SDKのCamera APIを利用する方法だ。
いずれの場合でも、Glassではいくつか注意が必要な点がある。まずデフォルトのActivityを利用する場合、以下のサンプルコードのようにMediaStore.ACTION_IMAGE_CAPTUREアクションのIntentでActivityを起動し、onActivityResultメソッドでその結果の画像を利用するという手順になるが、onActivityResultメソッドが呼ばれた時点で、画像ファイルがまだ作成されていない可能性がある。対応としては、onActivityResultメソッド内ではファイルシステムのObserverを登録し、実際のファイルの作成がObserverに通知された時点で、ファイルを利用した処理を行うことが推奨されている。少し複雑な処理になるので、実際には公式ドキュメントに記載されているソースコードを参考にしてほしい。
private void takePicture() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKE_PICTURE_REQUEST && resultCode == RESULT_OK) {
String picturePath = data.getStringExtra(
CameraManager.EXTRA_PICTURE_FILE_PATH);
// picturePath変数に写真画像が保存されている。
// ただし、ファイルがまだ作成されていない可能性があるので、ファイル作成を待つためのObserverを登録しておく。
}
super.onActivityResult(requestCode, resultCode, data);
}
|
また、Camera APIを利用する場合、カメラがロックされていてアクセスできない(=Camera.open()に失敗する)というケースがまれに発生する。これは、Glassのホームアプリ(=タイムラインを表示しているGlassware)がカメラを利用しており、音声コマンドなどで別のGlasswareを立ち上げると、ホームアプリがカメラの解放を完了するまでに若干の時間がかかることが原因である。Glasswareからカメラにアクセスする際は、起動してから数百ms程度のタイムラグを持たせるなどの工夫が必要だ。
まとめと次回
GDKは、Glass特有のCardやタッチジェスチャー、音声コマンドなど、主にUI回りの機能をAndroid SDKの拡張として提供するものである。今回は、このGDKを使うと、Google Glassの3種類のUI(Static Card/Live Card/Immersion)/タッチジェスチャー/音声認識/位置情報/センサー/カメラなどの機能を実装できることを紹介した。
次回は、実際のGDK開発の手順を解説する。また、サンプルアプリ(=コンパスアプリ)のソースコードを読み解きながら、よりGlassらしいアプリの実装方法について説明する。
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. Google Glassアプリケーション開発の基礎知識
Glassware(=Glassアプリ)開発を始めるなら、日本上陸前の今がチャンス。米国シリコンバレー在住の筆者が、現地ならではの視点でGlassware開発を解説する連載スタート。
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: 拡張現実)アプリの開発を、サンプルソースを交えながら解説。