2014年1月28日火曜日



GDKでは、以前お伝えしたCardの仕組みを使わずにAndroidと同様にActivityを使ってアプリを構築することができます。



注意点としては以下があります。



  • 640 × 360 の解像度

  • スワイプダウンが戻るボタンに該当する

  • Androidのようなタッチ操作はできない

しかしActivityだけではアプリが timeline 上に表示されない為、ユーザーがアプリを起動する手段がありません。そこで、アプリ起動用Serviceを用意してonStartCommand()のタイミングで任意のアクティビティを起動してやる必要があります。

なんだかとても面倒に感じますが、とても簡単。

まずサービスクラスを用意します。

単純にアクティビティを起動するだけのサービスクラスに必要なコードはたったこれだけ。

public class HelloService extends Service {
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Intent aIntent = new Intent();
        aIntent.setClassName("com.example.helloactivity","com.example.helloactivity.MainActivity");
        aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        startActivity(aIntent);
        return START_STICKY;
    }
}


あとは timeline からサービスを呼ぶようにマニフェストファイルを設定するだけ。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloactivity"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
         android:icon="@drawable/ic_launcher"
            android:name="com.example.helloactivity.MainActivity"
            android:label="@string/app_name" >
        </activity>
        <service
            android:name="com.example.helloactivity.HelloService"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:enabled="true"
            android:exported="true">
            <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/voice_trigger_start" />
        </service>
    </application>
</manifest>


この intent-filter と meta-data が重要で、これを記述することによってサービスが timeline 上に表示されるようになります。

            <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/voice_trigger_start" />


これだけで、Androidと同様のActivityを使ったアプリをGlassで実現することができます。

しかし、AndroidアプリをGlassに簡単に移植できる、とは考えないで下さい

現時点で Activity は Glass にはコストが高く、非常に動作が重くなり、本体の発熱も凄いです。

現時点では、Glass に Activity を使うのは良い選択肢ではないと考えます。

それを示すように、Activity を使って描画を行っているサンプルは Google から提供されていません。

そもそもソースコードも公開されてませんし、Glass は Android と似て非なるもの なのです。




GDKでActivityを使ってみる



GDKでは、以前お伝えしたCardの仕組みを使わずにAndroidと同様にActivityを使ってアプリを構築することができます。



注意点としては以下があります。



  • 640 × 360 の解像度

  • スワイプダウンが戻るボタンに該当する

  • Androidのようなタッチ操作はできない

しかしActivityだけではアプリが timeline 上に表示されない為、ユーザーがアプリを起動する手段がありません。そこで、アプリ起動用Serviceを用意してonStartCommand()のタイミングで任意のアクティビティを起動してやる必要があります。

なんだかとても面倒に感じますが、とても簡単。

まずサービスクラスを用意します。

単純にアクティビティを起動するだけのサービスクラスに必要なコードはたったこれだけ。

public class HelloService extends Service {
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Intent aIntent = new Intent();
        aIntent.setClassName("com.example.helloactivity","com.example.helloactivity.MainActivity");
        aIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        startActivity(aIntent);
        return START_STICKY;
    }
}


あとは timeline からサービスを呼ぶようにマニフェストファイルを設定するだけ。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloactivity"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
         android:icon="@drawable/ic_launcher"
            android:name="com.example.helloactivity.MainActivity"
            android:label="@string/app_name" >
        </activity>
        <service
            android:name="com.example.helloactivity.HelloService"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:enabled="true"
            android:exported="true">
            <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/voice_trigger_start" />
        </service>
    </application>
</manifest>


この intent-filter と meta-data が重要で、これを記述することによってサービスが timeline 上に表示されるようになります。

            <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/voice_trigger_start" />


これだけで、Androidと同様のActivityを使ったアプリをGlassで実現することができます。

しかし、AndroidアプリをGlassに簡単に移植できる、とは考えないで下さい

現時点で Activity は Glass にはコストが高く、非常に動作が重くなり、本体の発熱も凄いです。

現時点では、Glass に Activity を使うのは良い選択肢ではないと考えます。

それを示すように、Activity を使って描画を行っているサンプルは Google から提供されていません。

そもそもソースコードも公開されてませんし、Glass は Android と似て非なるもの なのです。









本ブログ「屋内測位をやってみました」で、始めた屋内測位ですが、あれからいろいろやってみて、だいぶまともに動くようになってきました。今回はある会議室にビーコンをだいたい3m四方に12個配置しました。使用したビーコンは、Estimote社のものを使っています。このビーコン出力が弱いため、精度を出すには3mという短い間隔で置くしかありませんでした。使用した測位アルゴリズムも、トリラテレーション(Trilateration)ではなく、近辺のビーコン位置にRSSI値をもとにした加重平均をとる方法を採用しました。

では、実際の実験の様子をご覧ください。

iBeaconで屋内測位成功のヒントをつかんだ!






本ブログ「屋内測位をやってみました」で、始めた屋内測位ですが、あれからいろいろやってみて、だいぶまともに動くようになってきました。今回はある会議室にビーコンをだいたい3m四方に12個配置しました。使用したビーコンは、Estimote社のものを使っています。このビーコン出力が弱いため、精度を出すには3mという短い間隔で置くしかありませんでした。使用した測位アルゴリズムも、トリラテレーション(Trilateration)ではなく、近辺のビーコン位置にRSSI値をもとにした加重平均をとる方法を採用しました。

では、実際の実験の様子をご覧ください。

2014年1月15日水曜日



Google からGlass Development Kit(以後GDK)が発表されてしばらく経ちました。

合わせて開発者用Glassの販売も行われ、今後市場投入に向けての動きが活発になることが予想されます。

しかしこの開発者用Glass、2014年1月時点で日本からは購入することができません。

USAでも開発者向けの招待メールでしか購入ができないようになっています。

弊社は現地支社がある為、いくつか購入することができました。

Glassを使った開発ノウハウが徐々に溜まってきたので、GDKでHelloWorldを書く方法をお伝えします。



さて、まず一言。

HelloWorld を書くのにこんなに苦労したのは久しぶりでした

完成されたSDKであれば普通、HelloWorldというのはプロジェクトを新規作成すると自動的に生成されるスケルトンプロジェクトに、ちょちょいと追記するだけで簡単に作れるものなのですが、現在のGDK(Rev.2)にはスケルトンコードを出力する機能がありません

従って今回は、GDKの中に含まれるサンプルコードをリファクタリングしながらHelloWorldを作ります。

Google Glassの開発環境


Glassの開発環境は基本的にAndroidと同じで、IDEはEclipseを使うのが最も簡単でしょう。

Android SDK Managerから Android 4.0.3 > GDK を選択して開発環境をインストールします。

f:id:bs-android:20140110095919p:image:w640

HelloWorldを作ってみる


それではGDKに含まれるサンプルコードをリファクタリングしながらHelloWorldを作ってみます。

新規プロジェクト > Android Sample Project > GDK > Timer を選択します。最後の画面でプロジェクト名をHelloWorldに変えておきます。

f:id:bs-android:20140110095920p:image:w360

f:id:bs-android:20140110095921p:image:w360

f:id:bs-android:20140110095922p:image:w360

このサンプルはその名の通りタイマーアプリで、設定した時間をカウントダウンすることができます。

まず、アプリがどのような動作をするか確認します。

遷移図を作りました。

f:id:bs-android:20140110095924j:image:w640

Glassはタップによる文字入力ができませんので入力項目は全て選択式になります。従って、シンプルなアプリですが画面数はとても多くなる傾向にあります。

Timerサンプルを解析してみる


次はTimerサンプルのコードを見て行きます。

まずはManifestから。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.android.glass.sample.timer"
    android:versionCode="2"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_timer"
        android:label="@string/app_name" >

        <activity
            android:name="com.google.android.glass.sample.timer.MenuActivity"
            android:label="@string/app_name"
            android:theme="@style/MenuTheme"
            android:enabled="true" >
        </activity>

        <activity
            android:name="com.google.android.glass.sample.timer.SetTimerActivity"
            android:label="@string/app_name"
            android:enabled="true" >
        </activity>

        <activity
            android:name="com.google.android.glass.sample.timer.SelectValueActivity"
            android:label="@string/app_name"
            android:enabled="true" >
        </activity>

        <service
            android:name="com.google.android.glass.sample.timer.TimerService"
            android:icon="@drawable/ic_timer"
            android:label="@string/app_name"
            android:enabled="true"
            android:exported="true">
            <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/voice_trigger_start" />
        </service>

    </application>

</manifest>


Activity が三つにServiceが一つ宣言されています。

こんなに小さなアプリでActivityが三つもあるのは何故か?

Glassでは基本的にActivityはコンテンツを描画する目的では無くメニューを表示する目的で使われます。従って、メニュー(設定項目や選択項目)が増えるとActivityがどんどん増えていく傾向があります。

Service内のmeta-dataは音声認識によるアプリ起動をサポートします。

次はソースコードを見て行きます。



  • MenuActivity.java

  • SelectValueActivity.java

  • SelectValueScrollAdapter.java

  • SetTimerActivity.java

  • SetTimerScrollAdapter.java

  • Timer.java

  • TimerDrawer.java

  • TimerService.java

  • TimerView.java

この中で最低限必要なクラスは以下です。



  • MenuActivity.java

  • TimerDrawer.java

  • TimerService.java

一つのGlassアプリには必ず一つのサービスが必要です。

サービスである為、アプリを終了する為のメニューが必要となるでしょう。必然的にメニューを表示するActivityも一つは必要となります。

さっき、Activityはメニューを表示する為に使うと説明しました。では、肝心のコンテンツはどのように描画するか?

GlassではCardというAndroidには無い仕組みが有ります。

Cardとは


Androidでは一つのActivityで一画面を表現しますが、Glassでは一つのCardで一つの画面を表現することができます。

CardにはStatic CardLive Cardの二種類があり、画面の更新頻度に応じて使い分けるとDocには書かれています。

TimerサンプルはLive Cardを利用している為、今回はLive Cardを使うことにします。

Live Cardは以下のような仕組みになっています。

http://developers.google.com/glass/images/diagrams/live-card-service.png

Glassではアプリ一覧が並ぶUIの事をTimelineと呼びます。

Timeline からアプリのサービスが起動し、サービスでLive Cardを生成しコンテンツの描画を行います。

HelloWorldを作ってみた


Timerサンプルを元に作成したHelloWorldのプロジェクト一式はこちら




重要なのはTimerServiceのonStartCommand()で、それ以外はAndroidと全く同じです。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (mLiveCard == null) {
        //LiveCardを生成したい
        mLiveCard = mTimelineManager.createLiveCard(LIVE_CARD_TAG);

        //レンダリング用Drawerを追加したい
        mLiveCard.setDirectRenderingEnabled(true).getSurfaceHolder().addCallback(mTimerDrawer);
        
        //Menu用Activityの生成と追加をしたい
        Intent menuIntent = new Intent(this, MenuActivity.class);
        menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));

        //LiveCardを表示したい
        mLiveCard.publish(PublishMode.REVEAL);
    } else {
        // TODO(alainv): Jump to the LiveCard when API is available.
    }

    return START_STICKY;
}


尚、Cardを使わずAndroidと同様にActivityのみでアプリを構築する方法もあります。

しかしこの場合、そのままではTimelineからアプリを起動することができない為、アプリを起動する為だけのGlassアプリを用意する必要があります。これに関してはまた別の機会に書きます。

Glassの開発難易度


残念ながら現時点ではGlass用のシミュレータはありません。実機が無いとアプリのテストができない為、早急なシミュレータ環境の提供を期待するばかりです。

コードを書く事だけを見れば、Cardの概念さえ理解すれば後はAndroidとほとんど同じである為、Androidアプリ開発経験者はスムーズに開発を行うことができるでしょう。

しかし、実際にGlassを身につけるとよくわかるのですが、この最低限のアプリケーションでも、起動すると本体が非常に熱くなり、継続した装着が困難になります。

Glassで実用的なアプリケーションを構築する為には高度な省エネのスキルが要求されることでしょう。

しかし、Glassはソースコードが公開されていません。その為、基本的に Java 層で省エネを実現する必要があります。

実験的なアプリケーションはAndroidの延長線上で作れるものの、現時点のGlassの性能で実用的なアプリケーションをFixする為には非常に高度な開発スキルが求められると考えます。

Java で省エネって、アメ車に低燃費を求めるようなもんですよね




GDKでHelloWorldを作ってみる



Google からGlass Development Kit(以後GDK)が発表されてしばらく経ちました。

合わせて開発者用Glassの販売も行われ、今後市場投入に向けての動きが活発になることが予想されます。

しかしこの開発者用Glass、2014年1月時点で日本からは購入することができません。

USAでも開発者向けの招待メールでしか購入ができないようになっています。

弊社は現地支社がある為、いくつか購入することができました。

Glassを使った開発ノウハウが徐々に溜まってきたので、GDKでHelloWorldを書く方法をお伝えします。



さて、まず一言。

HelloWorld を書くのにこんなに苦労したのは久しぶりでした

完成されたSDKであれば普通、HelloWorldというのはプロジェクトを新規作成すると自動的に生成されるスケルトンプロジェクトに、ちょちょいと追記するだけで簡単に作れるものなのですが、現在のGDK(Rev.2)にはスケルトンコードを出力する機能がありません

従って今回は、GDKの中に含まれるサンプルコードをリファクタリングしながらHelloWorldを作ります。

Google Glassの開発環境


Glassの開発環境は基本的にAndroidと同じで、IDEはEclipseを使うのが最も簡単でしょう。

Android SDK Managerから Android 4.0.3 > GDK を選択して開発環境をインストールします。

f:id:bs-android:20140110095919p:image:w640

HelloWorldを作ってみる


それではGDKに含まれるサンプルコードをリファクタリングしながらHelloWorldを作ってみます。

新規プロジェクト > Android Sample Project > GDK > Timer を選択します。最後の画面でプロジェクト名をHelloWorldに変えておきます。

f:id:bs-android:20140110095920p:image:w360

f:id:bs-android:20140110095921p:image:w360

f:id:bs-android:20140110095922p:image:w360

このサンプルはその名の通りタイマーアプリで、設定した時間をカウントダウンすることができます。

まず、アプリがどのような動作をするか確認します。

遷移図を作りました。

f:id:bs-android:20140110095924j:image:w640

Glassはタップによる文字入力ができませんので入力項目は全て選択式になります。従って、シンプルなアプリですが画面数はとても多くなる傾向にあります。

Timerサンプルを解析してみる


次はTimerサンプルのコードを見て行きます。

まずはManifestから。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.android.glass.sample.timer"
    android:versionCode="2"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_timer"
        android:label="@string/app_name" >

        <activity
            android:name="com.google.android.glass.sample.timer.MenuActivity"
            android:label="@string/app_name"
            android:theme="@style/MenuTheme"
            android:enabled="true" >
        </activity>

        <activity
            android:name="com.google.android.glass.sample.timer.SetTimerActivity"
            android:label="@string/app_name"
            android:enabled="true" >
        </activity>

        <activity
            android:name="com.google.android.glass.sample.timer.SelectValueActivity"
            android:label="@string/app_name"
            android:enabled="true" >
        </activity>

        <service
            android:name="com.google.android.glass.sample.timer.TimerService"
            android:icon="@drawable/ic_timer"
            android:label="@string/app_name"
            android:enabled="true"
            android:exported="true">
            <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/voice_trigger_start" />
        </service>

    </application>

</manifest>


Activity が三つにServiceが一つ宣言されています。

こんなに小さなアプリでActivityが三つもあるのは何故か?

Glassでは基本的にActivityはコンテンツを描画する目的では無くメニューを表示する目的で使われます。従って、メニュー(設定項目や選択項目)が増えるとActivityがどんどん増えていく傾向があります。

Service内のmeta-dataは音声認識によるアプリ起動をサポートします。

次はソースコードを見て行きます。



  • MenuActivity.java

  • SelectValueActivity.java

  • SelectValueScrollAdapter.java

  • SetTimerActivity.java

  • SetTimerScrollAdapter.java

  • Timer.java

  • TimerDrawer.java

  • TimerService.java

  • TimerView.java

この中で最低限必要なクラスは以下です。



  • MenuActivity.java

  • TimerDrawer.java

  • TimerService.java

一つのGlassアプリには必ず一つのサービスが必要です。

サービスである為、アプリを終了する為のメニューが必要となるでしょう。必然的にメニューを表示するActivityも一つは必要となります。

さっき、Activityはメニューを表示する為に使うと説明しました。では、肝心のコンテンツはどのように描画するか?

GlassではCardというAndroidには無い仕組みが有ります。

Cardとは


Androidでは一つのActivityで一画面を表現しますが、Glassでは一つのCardで一つの画面を表現することができます。

CardにはStatic CardLive Cardの二種類があり、画面の更新頻度に応じて使い分けるとDocには書かれています。

TimerサンプルはLive Cardを利用している為、今回はLive Cardを使うことにします。

Live Cardは以下のような仕組みになっています。

http://developers.google.com/glass/images/diagrams/live-card-service.png

Glassではアプリ一覧が並ぶUIの事をTimelineと呼びます。

Timeline からアプリのサービスが起動し、サービスでLive Cardを生成しコンテンツの描画を行います。

HelloWorldを作ってみた


Timerサンプルを元に作成したHelloWorldのプロジェクト一式はこちら




重要なのはTimerServiceのonStartCommand()で、それ以外はAndroidと全く同じです。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (mLiveCard == null) {
        //LiveCardを生成したい
        mLiveCard = mTimelineManager.createLiveCard(LIVE_CARD_TAG);

        //レンダリング用Drawerを追加したい
        mLiveCard.setDirectRenderingEnabled(true).getSurfaceHolder().addCallback(mTimerDrawer);
        
        //Menu用Activityの生成と追加をしたい
        Intent menuIntent = new Intent(this, MenuActivity.class);
        menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0));

        //LiveCardを表示したい
        mLiveCard.publish(PublishMode.REVEAL);
    } else {
        // TODO(alainv): Jump to the LiveCard when API is available.
    }

    return START_STICKY;
}


尚、Cardを使わずAndroidと同様にActivityのみでアプリを構築する方法もあります。

しかしこの場合、そのままではTimelineからアプリを起動することができない為、アプリを起動する為だけのGlassアプリを用意する必要があります。これに関してはまた別の機会に書きます。

Glassの開発難易度


残念ながら現時点ではGlass用のシミュレータはありません。実機が無いとアプリのテストができない為、早急なシミュレータ環境の提供を期待するばかりです。

コードを書く事だけを見れば、Cardの概念さえ理解すれば後はAndroidとほとんど同じである為、Androidアプリ開発経験者はスムーズに開発を行うことができるでしょう。

しかし、実際にGlassを身につけるとよくわかるのですが、この最低限のアプリケーションでも、起動すると本体が非常に熱くなり、継続した装着が困難になります。

Glassで実用的なアプリケーションを構築する為には高度な省エネのスキルが要求されることでしょう。

しかし、Glassはソースコードが公開されていません。その為、基本的に Java 層で省エネを実現する必要があります。

実験的なアプリケーションはAndroidの延長線上で作れるものの、現時点のGlassの性能で実用的なアプリケーションをFixする為には非常に高度な開発スキルが求められると考えます。

Java で省エネって、アメ車に低燃費を求めるようなもんですよね




Related Posts Plugin for WordPress, Blogger...