2015年10月2日金曜日

[Android]AndroidHttpClientがNGになっていたので、HttpURLConnectionでアクセスしてみた

AndroidHttpClientを利用しようとすると利用してはいけないと怒られてしまうので、
HttpURLConnectionを使ってHttp通信を行いました。
今回はヘッダー領域はいらないのでページの内容だけを取得するクラスです。
HttpURLConnectionを使用してHTTP通信を行う
http://techbooster.jpn.org/andriod/application/6812/
HttpClient.java
public class HttpClient {
    private HttpURLConnection connection = null;

    public String get(String url){
        String pageData = "";
        try {
            URL u = new URL(url);
            connection = (HttpURLConnection)u.openConnection();
            connection.setRequestMethod("GET");
            connection.setInstanceFollowRedirects(false);
            connection.connect();

            InputStream is = connection.getInputStream();
            pageData = // ストリームの内容を転記;
            is.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return pageData;
    }
}
URLやHttpURLConnectionのインスタンスを再利用できないかあれこれ頑張ろうとしましたが、
少なくともHttpURLConnectionはインスタンスの再利用はできないようです。
それと非同期でないため注意してください。
// 使い方
HttpClient client = new HttpClient();
String page = client.get("http://localhost:8080/index.html")

2015年9月3日木曜日

[Android]ACRAを利用して好きなタイミングでクラッシュレポートを送信する

ACRAライブラリを利用することでクラッシュレポートの通知ができます。
ただ、ネットワーク環境がない状態でエラーが発生した場合の状況も入手したかったので、
その方法をメモで残そうと思います。
エラー発生時はエラー情報をファイルに保存するだけにし、
ネットワーク環境につながっているときに後から送信するという方法で実装しました。
  1. クラッシュレポート用のクラス作成
  2. ReportSenderの作成
  3. ACRAの設定

クラッシュレポート用のクラス作成

クラッシュレポートの内容をファイルに保存、読み込みを行うクラス
※Read,Write処理部分は省略
CrashReport.java
public class CrashReport {
    private static final String CRASH_REPORT_FILE = "crash_report.txt";

    private Context context;
    private StringBuilder report = new StringBuilder();
    public CrashReport(Context context) {
        this.context = context;
        // ロード処理
        .
        .
        .
        report.append(loadData);
    }

    public void add(CrashReportData errorContent) throws JSONReportBuilder.JSONReportException{
        // レポートを追加
        report.append("\n------------------------------------------------------------\n");
        report.append(errorContent.toJSON().toString().replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t"));
    }

    public void save() throws IOException{
       // レポートの保存
    }

    public void send(String email){
        // メールでクラッシュレポートを送信
        Intent intent = new Intent();
        intent.setType("message/rfc822");
        intent.setAction(Intent.ACTION_SENDTO);
        intent.setData(Uri.parse("mailto:" + email));
        intent.putExtra(Intent.EXTRA_SUBJECT, String.format("Crash report![%s]", context.getPackageName()));
        intent.putExtra(Intent.EXTRA_TEXT, report.toString());

        context.startActivity(intent);
    }

    public void clear(){
        // クラッシュレポートのクリア
        report = new StringBuilder();
        try {
            save();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

ReportSenderの作成

クラッシュしたときに動作するSenderクラスを作成
CrashReportSender.java
public class CrashReportSender implements ReportSender {

    @Override
    public void send(Context context, CrashReportData errorContent) throws ReportSenderException {
        CrashReport crashReport = new CrashReport(context);

        try {
            crashReport.add(errorContent);
            crashReport.save();
        }catch (Exception e){
            Log.e("CrashReportSender", "CrashReport save is failed.");
            e.printStackTrace();
        }
    }
}

ACRAの設定

最後にACRAを設定して完了!
AcraCrashReportApplication.java
@ReportsCrashes(
        mode= ReportingInteractionMode.TOAST,
        resToastText = R.string.acra_dialog_text,
        resDialogCommentPrompt= R.string.acra_dialog_comment_prompt // 発生状況を入力する欄のラベル
)
public class AcraCrashReportApplication extends Application {
    @Override
    public void onCreate() {
        // The following line triggers the initialization of ACRA
        super.onCreate();

        // ACRAの設定
        ACRA.init(this);
        CrashReportSender sender = new CrashReportSender();
        ACRA.getErrorReporter().setReportSender(sender);
    }
}
AndroidManifest.xml
android:name=lang:AcraCrashReportApplication
あとは、どこかの画面でCrashReportのsendを呼び出せばOKです。

2015年8月12日水曜日

[Unity][Android]Unity画面からfinishしてAndroidの画面に戻す方法

単純にfinish()するだけだとアプリが落ちてしまうようです。
次のように実行したところ元画面に遷移しました。
UnityPlayerNativeActivityを継承したActivityを作成する。
次の内容のメソッドを実装する。
public void end() {
  runOnUiThread(new Runnable() {
      @Override
      public void run() {
          mUnityPlayer.quit();
          finish();
      }
  });
}
一応これで元画面に戻ったのですが、
内部的には一回アプリを落として再起動しているようで、
static変数ですら初期化されてしまいました。

2015年7月8日水曜日

Android と Unity の座標系

ども、モーション認識部分を担当している太田です。

meleap では Android + Unity で開発を進めています。端末の位置情報なりを入力として用いてますがこれが一筋縄では行きません。なぜなら、両者で空間座標系の定義が異なるんです。涙
今回はそんな面倒くささをちょこっと紹介しておきます。

【Unity の座標】


上の図は Unity マニュアルから引っ張ってきました。Unity を使ったことのある人からすると、見慣れた座標系ですよね?でもこの座標系、ちょっと違和感感じませんか?上向きに y 軸があるって、3次元座標系として見慣れない感じじゃありません?少なくとも僕は違和感ありまくりで、初見でとても気持ち悪かったです。

この違和感、数学や物理での3次元空間座標の表現と『異なる』からです。
数学や物理はいわゆる「右手系」で「右ねじの法則」からなる座標系を設定することが多いです。対して Untiy では上図のように「左手系」を採用しています。

「だからどうした?それのどこが問題なんだ!」と思われるかもしれません。問題はここからです。
同じく Unity マニュアルから引用しましょう。
モバイルデバイス: 
(中略) 
各軸に沿った加速が重力の値としてハードウェアにより直接報告されます。 値が 1.0 の場合、与えられた軸に対する +1 G の力を示し、-1.0 の値は -1 G を示します。 目の前にデバイスを垂直に持ち(ホームボタンが下)、X 軸は右向きが正の値を示し、 Y 軸は上向きが正の値を示し、Z 軸は自身に向かう向きが正の値を示します。
Unity からもデバイスの加速度センサの値を取得することができます。上記は Input のリファレンスから一部抜粋して引用しました。ここで出てくる3軸の定義は、なんと「右手系」です!つまり、Input.acceleration で得られる値を直接 Unity 内の座標系に適応すると、期待通りには動いてくれません。

これは何も加速度に限ったことではありません。ジャイロに関しても同様のことが言えます。回転方向の定義も「右ねじ」と「左ねじ」で異なるので注意が必要です。

というわけでデバイスからの入力を Unity 内で使うには都合の良い座標変換を入れる必要が有ります。座標変換の一例として下記のサイトを参考にしてください。
http://qiita.com/fuqunaga/items/b1a3e38af71f062f0781
座標変換は一意に決まるものではないので、仕様に合った選択をするようにしましょう。

ではでは今日はこの辺で。。。


2015年6月30日火曜日

[Node.js]ファイルDB「NeDB」を使ってみた

先日「Node学園 16時限目 ES2015発行記念」に参加させていただきました。
その発表の中でファイルDBである「NeDB」を知れたので試してみました。
基本的には以下のパワポの内容を実行しているだけです。

http://www.slideshare.net/isamusuzuki54/loop-backapiswift-46901252?next_slideshow=1


準備:
npm install nedb --save

※これだけ!


ソースコード:(今回は「nedb_test.js」というファイルで作成しています。)
var NeDB = require('nedb');
var db = {};
db.users = new NeDB({
  filename: 'usersfile'
});

db.users.loadDatabase();

// insert
db.users.insert({name: 'hoge'});
db.users.insert({name: 'fuga'});
db.users.insert({name: 'uga'});

db.users.insert([
  {name: 'foo'},
  {name: 'bar'}
  ], function(err, newDoc){
    console.log("[INSERT]");
    console.log(newDoc);
});

// find
db.users.find({name: 'fuga'},
  function(err, docs){
    console.log("[FIND]");
    console.log(docs);
});
db.users.find({name: /f*uga/},
  function(err, docs){
    console.log("[FIND F*]");
    console.log(docs);
});

// remove
db.users.remove(
  {name: 'fuga'},
  {multi: true},
  function (err, numRemoved){
    console.log("[REMOVE]");
    console.log(numRemoved);
});
db.users.remove(
  {name: 'uga'},
  {multi: true},
  function (err, numRemoved){
    console.log("[REMOVE]");
    console.log(numRemoved);
});


実行結果:
%]node nedb_test.js
[INSERT]
[ { name: 'foo', _id: 'ShGylbRFFiR4nZcR' },
  { name: 'bar', _id: '7Kkhma6FdLUzQI7o' } ]
[FIND]
[ { name: 'fuga', _id: '8AKesKQfsnvVOdob' } ]
[FIND F*]
[ { name: 'fuga', _id: '8AKesKQfsnvVOdob' },
  { name: 'uga', _id: 'vbDsvmXtaB5xHNYo' } ]
[REMOVE]
1
[REMOVE]
1

実行後のファイル(usersfile)の内容:
{"name":"hoge","_id":"WuA7LFB50CWMnSX2"}
{"name":"fuga","_id":"8AKesKQfsnvVOdob"}
{"name":"uga","_id":"vbDsvmXtaB5xHNYo"}
{"name":"foo","_id":"ShGylbRFFiR4nZcR"}
{"name":"bar","_id":"7Kkhma6FdLUzQI7o"}
{"$$deleted":true,"_id":"8AKesKQfsnvVOdob"}
{"$$deleted":true,"_id":"vbDsvmXtaB5xHNYo"}


いやぁこんな簡単にDBを利用できるようになるなんてすばらしいですね!
利用できるAPIはMongoDBに準拠しているらしいので、
しっかりとしたDBに移行する際にも楽に対応できるかもしれないのがまた素敵ですね。

インストールするとついてくる次のマニュアルを見れば使い方も大体把握できると思います!

マニュアル:
node_modules/nedb/README.md

DroidKaigiに参加してきました 後半

前半を書いたのがひと月前で、
DroidKaigi自体がもっと前で、
いまさら感が強いですが、
感想後半戦を始めます!

[ROOM:A]開発を効率的に進められるまでの道程
[ROOM:B]ゲームアプリケーションのアップデートサイクル
[ROOM:B]初学者にうれしいAndroid開発環境
[ROOM:B]Android学ぶ君へ。生き抜くためのナレッジ共有
ここから下
[ROOM:B]新言語KotlinでAndroidプログラミング
[ROOM:B]Bitmapは怖くない。
[ROOM:B]モバイルにおける電力最適化のための1プラクティス
[ROOM:B]デザイナーがXMLを書くことでできる改善しやすいアプリ開発
[ROOM:B]JellyBeanとKitKatで実現するマテリアルデザイン
[ROOM:B]僕らのデータ同期プラクティス
[ROOM:B]AndroidとSELinux

■[ROOM:B]新言語KotlinでAndroidプログラミング

KotlinかわいいよKotlin
JVM上で動作するプログラミング言語です。
開発はAndroidStudioの元のIntelliJ IDEAを開発している
「JetBrains」だそうです。

詳しくは次のURLをご参照ください!
https://sites.google.com/site/tarokotlin/home

Androidアプリの開発もすでにできるようになっているようで、
Kotlinを利用すればラムダ式などが使えるようになるそうです。
Javaのめんどくさい部分もKotlinを使えばかなり楽になりそうでよさげ。


■[ROOM:B]Bitmapは怖くない。

と言いつつもやっぱり怖いそうです(笑)

Bitmapを扱えるPicasso,Glide,Frescoの3種を紹介していただきました。
講師曰く、Bitmapを利用する際に多少面倒な指定が必要になるが、
基本的にはGlideがいい感じだそうです。
Picassoは利用したことはありますが、
Glideはないので、次に利用するシーンがあればGlideを試そうと思います。

「android:largeHeap="true"」は最終兵器


■[ROOM:B]モバイルにおける電力最適化のための1プラクティス

少しハードよりな話でした。
アプリの動作上で何を行っているときに
大量の電力が発生しているかを実験するための装置の説明でした。

この装置なんと自作!すごい!!
たしか計5000円くらい(もう数か月前なのでまったく覚えていない)だったと思います。

WebViewはかなりの電力食いなので気を付けよう。
2Dより3Dの方が電力食い。
Unityも電力食い。

はい。弊社の製品は全部該当ですね。。。
いつか利用電力の問題をクリアして皆様に提供できるようがんばります!


■[ROOM:B]デザイナーがXMLを書くことでできる改善しやすいアプリ開発

デザイナーさん話でした。
デザイナーさんとプログラマーでバトルしているところが多い中、
そこをなんとか上手にできましたよって話。

デザイナーでもAndroidのUI作成なら何とかできるので、
それ以外(開発環境の準備など)をしっかり面倒見てくださいとのこと。

プログラマーはとにかくよりよい製品を作るために、
デザイナーさんにコードを触ってもらう努力をしましょう!


■[ROOM:B]JellyBeanとKitKatで実現するマテリアルデザイン

ごめんなさい。。。体力切れで休んでいた模様。。。
AppCompatActivityを使っていこうとだけメモが書いてありました(笑


■[ROOM:B]僕らのデータ同期プラクティス

通信で過酷な状況での話をおっしゃってました。
広い畑の中心部だと通信が届かないそうです。
まずはそこに驚きましたね。

バックグラウンド通信で動機で一応可能だけれども、
とても大変かつバッテリー食いになってしまうので、
過酷な環境の場合はNG。

SyncAdapterというAndroid提供の機能を利用すれば解決できるかもとのこと。


■[ROOM:B]AndroidとSELinux

バージョンが上がるたびにセキュリティが厳しくなっていくため、
よくわからないエラーが発生している場合は、
SELinuxを疑ってみてくださいとのこと。

セキュリティの外し方は講演資料に記載されているので、
そこをご参照ください。

マニフェストで指定できない部分もあるのですね。。。



無料なのにとても意義のあるところに参加ができました!
DroidKaigiのスタッフ様、講演していただいた皆様には感謝しかありません。


2015年6月22日月曜日

HoloLensまとめ

Microsoftが開発したARヘッドマウントディスプレイ(HMD)「HoloLens」についてまとめました。


ARヘッドマウントディスプレイの特徴

ヘッドマウントディスプレイとは、頭にかぶり、眼前のディスプレイにCGによる表示映像をするデバイスですが、これはOculus RiftやsonyのProject MorpheusのようなVR用と異なり、現実世界も透けて見えます。

また、Oculus RiftとMorpheusはディスプレイ機能がメインで、PCやゲーム機につなげて処理する必要がありますが、HoloLensは,それ自体にWindows 10を搭載しており、PCに接続する必要はありません。

業界筋ではプロセッサして「Atom」SoC(System-on-a-Chip)の搭載が有力視されています。


距離センサーで空間にCGを貼り付ける

現実視界にCGをオーバーラップ表示できるシースルータイプのHMDとしては,すでにセイコーエプソンがAndroidベースのMOVERIOシリーズを出しています。

ただ、MOVERIOとHoloLensは周辺環境の認識という点において大きく異なります。HoloLensには,「Kinect」と同じ投射型深度センサーが使用されています。これは赤外光を面照射して,その反射光が返ってくるまでの時間をCMOSベースの距離イメージセンサからToF(Time of Flight)方式で測定するものです。照射範囲は120度。

ToFとは,照射された赤外光が反射されて照射側に戻ってくるまでの時間差から、シーンの深度分布を計測する技術です。これはMicrosoftが2009年に買収したイスラエルの3DV Systemsが持つ技術をベースとしています。Xbox One用KinectのToF測距精度は130億分の1秒だといわれ、HoloLensでもこれに準じた精度で深度値を取得しているものと思われます。

このため、「現実視界にCGが完全に張り付いている」という感覚を得られるのです。
mine craftのデモ


網膜投影型は焦点調整が不要だが、デメリットもある

Oculus RiftやMorpheusでは,直視型の液晶ディスプレイを眼前において見せているので、眼球を動かしても映像が見切れたり消失することはありません。一方で、HoloLensのような網膜投射型デバイスの場合、網膜に映像を直接投射する関係で、眼球が常に正面を向いていることが前提になっています。なので、眼球を動かすと途端に映像が消失したり,外周が消えてしまったりするとのことです。

そもそも、網膜投影型とはどのようなものなのでしょうか。
通常、物体を立体視する際、光は水晶体で収束し、網膜上で結像します。物体までの距離が変化すれば、水晶体の厚みを変え、光を屈折させます。それに対し、網膜投影型では、光を瞳孔の中心で収束させるため、水晶体の屈折率の影響はうけません。
つまり、現実の視界で遠くのものを見ても、近くのものを見ても、ディスプレイのCGがぼやけないのです。近視、乱視、老眼なども関係ありません。

また、ディスプレイには表示部が存在しないため、解像度・輝度・コントラスト・表示色とも従来のディスプレイを凌駕する性能が実現できます。



ジェスチャー操作、音声入力が可能

HoloLensのデモでは、空中をタップする、つまむ、引き延ばす、などのジェスチャーでCGを実際のモノのように操作できる様子が公開されています。
指の認識はHMDの前面に付いているセンサーで行っているようです。現状、可能な操作は限られており、あまり複雑な指の動きまでは対応していません。
また、音声の入力も可能で、かなりの精度で認識してくれるそうです。(英語)家の中で使うのであれば、音声入力はかなり便利になりそうですね。



画角が今後の課題

また、体験した方によると、映像画角はかなり狭いといいます。30°×17.5°というデータもあります。
少し頭の向きを変えるとCGが途切れてしまうため、仮想世界への没入感は少なくなってしまいます。
平面の2D映像を見たり、サインを表示する分にはいいのですが、3Dのゲームなどをやろうとすると、物足りない感があると思います。
おそらく、網膜投影の仕組み的に、この画角の問題はすぐに解決されるものではないと思われます。
弊社のHADOのような没入感のあるゲームではある程度の画角が必須なので、初期のHoloLensに対応させるのは難しいかもしれませんね。
今後に期待です。


その他のデモ動画