暗号化について勉強中

Androidでユーザデータを暗号化して保護するにはどうしたらいいのでしょうか。 これまで「暗号化のやり方がよくわからないから、機密情報を保存しないようにしよう」と避けてきたのですが、それにも限界があるのかなぁと思って、手を広げてみる気になったのです。 まあ本当の出発点は、ユーザデータの保護ではなく、アプリで扱うデータを秘匿するにはどうしたらいいのだろうだったんですけれど・・・。 例えば、Twitterクライアントを作るとして、そのAPIキーをどうやって秘匿するのかということです。 Androidでこの手のAPIキーを扱う場合、サンプルではJavaのコードに直接書いてありますが、実際に自分でリリースするアプリでもそのままでいいのかという話です。 AndroidではAPKを簡単に抜き出して、しかも簡単にソースコードを確認することもできます。ProGuardで難読化をしても、Javaのコードに埋め込んだ文字列はそのままです。 String api_key = "hogehoge";のapi_keyの部分はProGuardによってaとか意味のない文字に書き換わりますが、”hogehoge”の部分は書き換わりません。(書き換わったらプログラムの動作が変わってしまうので当たり前です) つまり、やろうと思えばAPIキーは見放題ということになります。 だからここの部分、どうするのがセオリーなんだろうってのから始まって、暗号化すれば秘匿できるのかなと思ってみたのです。 多分、ユーザに見せたくないデータはアプリで保持しないのが正解であって、暗号化は関係ないと思いますが、それでも今まで放置していた暗号化に関して勉強するいい機会ではあるのでそのまま続けております。 どう勉強してるのかって話ですが、https://developer.android.com/training/articles/keystore.htmlを見たり、Android Studioのimport Sampleで取り込めるGoogleのサンプルコードを使ったりしてます。 実際に手を動かしてみて初めて知ったのですが、同じ文字列を同じ暗号化鍵で暗号化しても、得られるバイト列が毎回異なることに驚きました。”abc”を同じ暗号化鍵を使って暗号化したら、毎回123になるというイメージを持っていたものですから、なんで毎回異なるバイト配列になるのか不思議です。しかも異なるバイト配列になるのに、復号化したらちゃんと”abc”に戻るのですからなお不思議です。 これは一体どういう仕組なのか。そもそも暗号化の仕組みを理解せずに使うのは逆に危険なんじゃないのかと思い始め、今度はこんな本を読み始めました。 暗号技術入門 第3版 秘密の国のアリス posted with ヨメレバ 結城 浩 SBクリエイティブ 2015-08-26 Amazon Kindle 紀伊國屋書店 まあまだ読んでいる最中なんですけど面白いです。 本書には 弱い暗号は暗号化しないより危険である という考え方が序盤で紹介されています。仕組みを理解せずに暗号化するのもまた良くないと言えるのではないでしょうか。 安定の結城先生なので非常に分かりやすく、楽しく読めそうです。 それにしても、初めはAPIキーを秘匿することがきっかけだったのに、我ながらよく脱線してきたものだなぁと思います。

Contextの使い分けについて私が辿った変遷

Application Contextを渡してはいけないという記事を読みました。 https://ytrino.hatenablog.com/entry/2016/05/26/033936 この記事を読んで改めて自分のContextに対する認識があまいことを実感したので、思ったことをまとめてみようと思います。 趣旨は「僕はContextに対してこういうふうに思ってるんだけど、違う・違わないが自信持ててないから誰か突っ込んでくれ」です。たぶんそんなに間違ってないと思うんですけど、相談できるような相手がいないんだ、察しておくれ。 「私もそういう認識です」と言ってもらえれば自信になるし、違う部分があれば指摘をもらって学びの機会になり私のためになります。また、こういう変遷を経て学んできたという情報が初学者の役に立てばなぁなんて思ってもいます。 私のAndroidレベルは初学者というわけでもないですが、Contextにまつわる話を聞くと理解が曖昧でモヤモヤするレベルです。上記記事に倣えばAndroid2級でしょうか。 私は最近でこそライフサイクル考えてContextを使い分けるようになりましたが、ちょっと前まで「困ったらApplication Context渡しとけば問題ない」という考えの人でした。前までというか、今もそういう部分があるんですけどね。だからこそ「Application Contextを渡してはいけない」というのを見て不安になってしまいました。 渡してはいけないの意味 Application Contextを渡してはいけないというのは、どういう意味なのでしょうか。 アプリがクラッシュするから渡してはいけない 表示がおかしくなるから渡してはいけない 渡しても動作上は問題ないが、コードの見た目上・意味的に美しくないので渡してはいけない 実はApplication Contextをなるべく使おうというのも、Application Contextを渡してはいけないというのも、あるコンテキストにおいては間違ってないんじゃないかなと思います。それぞれ違うコンテキストで話しているので、そこを混同すると混乱してしまいます。 前者は「メモリリークを回避する」という文脈での話で、Activityのリークを防ぐにはApplication Contextを使えばいいのは正しい(はず)です。 一方後者はthemeの適用の観点での話で、Application Contextでは意図した動きにならない・変にハマることがあるからApplication Contextを安易に使ってはいけないという話で、これはこれで正しいわけです。 どっちも正しいのですが、残念ながらコードを書いていてContextを要求された時に、私たちは何らかのContextを渡さないと先に勧めません。何を渡せばいいかは「ケースバイケースなんで一概にどれを使えとは言えない」んで、Contextの要求に対しては、それぞれ適切なContextを渡す必要があります。 ではどのようにしたら、何を使うのが適切かを判断できるのでしょうか。ライフサイクルを考えろということでしょうか。そのライフサイクルはどうやって判断するんでしょうか。 私はその判断を、今はソースコードを読むことで行っています。Contextを要求するメソッドが、クラスが、いったい渡されたContextをどのように利用しているのか。それをもって何を渡すか考えています。 Contextについて私の辿った道 Androidを学び始めた当初は、Contextなんて意識していませんでした。本やサンプルコードの写経する分には意識しないですみますから。 しかし写経から脱し、自分でコードを書き始めるとそうもいきません。こういう処理を実装したいな→このメソッド使えばなんとかなりそう→Contextが必要らしい。はたとキーを打つ手が止まります。 そのメソッドを使うにはContextを渡すしかない。渡さないと先に進まない。とりあえずthisって書いたら動いた。よし、これで先へ進める。なんていうのが、Androidを学び始めた人が辿る道ではないでしょうか。私はそうでした。 学び始めの頃はActivityからなんかすることが多いので、this、すなわちActivityを渡していればとりあえずは動いてくれました。私はそうして「ああ、ContextっていうのはActivityを渡せばいいのだな」と認識するようになりました。 しかしActivity Contextを渡してしまうとメモリリークが発生するぞという話を耳にします。そこで登場するのがApplication Context。getApplicationContext()を使えばメモリリーク対策になるという話を聞いて、「ああ、じゃあとりあえずApplication Contextを渡しておけば問題ないのか」となりました。 しかし今度はApplication Contextを渡すと想定通りにViewが表示されないことがあるという。無思考にApplication Contextを渡すのもどうやらダメらしい。 一周回ってきてしまいました。もう一体どうしろと。このメソッドContext要求してくるのに僕は一体何を渡せばいいんだ。 私のContextとのつきあい方 そんな私が多少なりとも指針を持てるようになったのは、一言で言ってしまえば慣れてきたからなんだと思います。 とりあえずコード書いて、動かしてみて。それを繰り返すうちに慣れてきて。ソースコードを読むようになって「多分こうやれば大きく間違ってはいないはず」という、そんな指針を持てるようになりました。 Contextを要求されたら何を渡すか。重要なのは考え方、つきあい方だと思います。これが今回の記事の本題です。 私はまずライフサイクルを考えるより前に、Contextを要求するメソッドのソースコードを確認しに行きます。そいつがContextへの参照を保持するのか、それともContextを使ってなんかするだけなのか。それを確認するのです。 Contextへの参照を保持するなら、Activity Contextを渡していいのか、ライフサイクルを考えなければなりません。ライフサイクルを考えるというよりは、Activityとともに役目を終えるのか、そうでないのかで判断していますが、正直このあたりは曖昧です。 該当のメソッドが単にStringリソースを読みだすのに使っているとかだったら、別にActivity Contextを使っても問題ないですよね。そもそもActivityがリークするのは、Activityへの参照を持ち、渡した先のオブジェクトがActivityより長生きする場合だからです。 Contextへの参照を持たないのであれば、別にどっちを使おうが問題ないので、好きな方使えばいいじゃんって感じですが、Activityから呼び出すのであれば、わざわざApplication Context渡すのも大げさなので、Activity Contextでいいかと思います。 Androidと付き合っていくうちに、なんとくこんな感じに行き着きました。それでもメモリリークが怖いなら、Contextに何を使えばいいか迷うよりも、それでメモリリークするのかを確認する方に力を注いだほうが良いと思います。 でも、独学でやってるとこれで本当に問題ないのか確証が持てないので、いつもどこかで不安です。誰かに聞く機会もなくてつらい。 見えないメモリリークの影 そもそもContextについて意識し始めるキッカケは、私の場合はActivityのメモリリークです。 このメモリリークも私にとってはContext以上によく分からない存在でした。最初のうちはメモリリークしているかどうかをどうやって確認すればいいのかがわからなかったからです。確認方法が分からないから、メモリリークしないコードを書かなきゃという気持ちだけが肥大化していました。 そんな中で「とりあえずApplication Context渡しておけばライフサイクルの関係でActivityがリークすることはない」という1つの指針は、私にとっては心強かったです。 実際にはApplication Contextを渡すからメモリリークしなくなるわけではないというのは、今であれば分かります。しかしはじめの頃はそんな違いも分からなくて、そんなことよりContextとして何を渡せばいいのかという指針があることがありがたかったのです。 これに関しては、メモリリークしているかどうかを確認する方法を学ぶ方が大切だと、今であれば思いますけどね。当初は確認方法がわからないけど、メモリリークしたら困るからApplication Context渡しとけっていう感じでコード書いてました。 初学者に向けてステップアップのために 初学者がもっとも優先すべきはとりあえず先に進むことだと思います。動くアプリを作ることです。そしてAndroidに慣れることです。 Contextを要求するメソッドに対して、何らかのContextを渡す。Activity Context渡すのかApplication Context渡すのか迷うと思います。最初のうちはとりあえずどっちか渡して動いてればいいと思います。動けば正義です。迷って足を止めるより、いっぱい作ってAndroidに慣れる方が大事だと思います。 慣れてきたらContextを渡すときに「こいつはActivityより長生きする奴なのかな」と考えましょう。そんなときはソースコードを読むことが助けになると思います。 Contextを要求するメソッドは、渡されたContextをどのように使っているのか。そいつもContextが必要なメソッドを呼び出すために必要としているのか。それともContextへの参照を保持するのか。 Contextに何を使うべきなのかはケースバイケースで一概には言えません。Activity Contextじゃないとダメな場合もあれば、Application Contextの方が適切な場合もあり、はたまたどっち渡しても問題ない場合だってあります。・・・なんでこんなややこしいことになってるんでしょうね? とりあえず、動けば正義でトライアンドエラーを繰り返してAndroidに慣れる。慣れてきたらソースコードを読んでみて、Contextがどう使われているかを気にしてみる。そうやってステップアップしていくしかありません。 私のContextとの現在のつきあい方 長くなったので最後にまとめ。 私はActivity Contextを基本的に使うようにしていて、利用先でContextへの参照を持つ場合にはApplication Contextの利用を考える、というような感じでやってます。 Activity Context使っているのはThemeのためとかじゃなくて、単にgetApplicationContext()を書くと長くなるからとかそんな理由です。明らかにActivityのライフサイクルより長生きするオブジェクトに対しては、Application Context渡していますけれども。 正直な所、メモリリークをおそれてContextにどれを使うか悩むより、メモリリークの確認の仕方を調べて、リークしていないかを確認することに力入れたほうが建設的なんじゃないかなと思います。 何を使うのが適切か迷ってまごまごする前に、どう使われているのかをまず確認する。Contextの使い分けに関してはこれが私の指針なんですが、そんなに大きく間違ってはないですよね?

Kotlin使ってみて感じる便利さと葛藤

最近アプリやAndroid Studio用プラグインを作るのにKotlinを使っています。 始めたばかりの頃は「Javaだとああ書くんだけど、Kotlinだとどう書けばいいんだ」ということが多かったです。Javaでまともに書けないのにKotlinに手を出すのは早いんじゃないかとも思っていました。 しかし少しずつ試していくと、Kotlinの便利な部分が分かってきてきました。 私の場合、「Kotlinで書き始めたんだけどやっぱ使い方よくわからないからJavaに戻そう」とう場面が初期の頃はよくありました。はじめはKotlinで書いていたけど、やっぱりJavaで実装しようとという感じです。 そんなときに、「Javaに戻すのめんどくせえ」と感じる部分があって、そこで改めて「Kotlinってやっぱ便利やなぁ」なんて実感しました。 それからというもの、Kotlinの比重が徐々に増えてきて、今では逆にJavaで書く方が面倒くさいと感じるようになってしまいました。 一方で、Kotlinが無敵というわけではありません。Annotation Processingを使うライブラリがKotlinだとうまく使えないことがあったり(基本的には大丈夫ですが、Javaで書けば動くコードがKotlinで同じように書くと動かないことがあったりします)、Javaと比べるとコード補完が遅かったり、Kotlinを使うことで感じるストレスもあります。 ですが、不便さを差し置いてもKotlinで書いた方がすっきり書けるのはやっぱり快適だと思っています。 テストコードから始めるといいかも どなたかの記事で、Kotlinはテストコードから導入してみたらどうかという記事を読みました。私もいい方法だと思います。Kotlinの便利さを実感するためではなく、どう書くかを知るのにちょうどいいと思います。 私もJUnitでのユニットテストをKotlinで書いています。テスト対象をKotlinで書いてるからとか、セミコロンつけなくてもいいから、とかそんな理由です。ユニットテストについてはKotlinが便利だからという理由はあまりないかもしれません。 ユニットテストにおいてKotlinが便利だと思うのは、バッククオート(`)で囲むことで、メソッド名やクラス名を数字から始めることができたり、途中に空白を含めることができたりすることでしょうか。 私はテスト名に日本語を使うことが多いです。そしてそのときに、メソッド名に使える文字に制約があるのが微妙に困ります。 例えば各月の最終日を求めるメソッドのテストをするのに「4月の場合は30日を返す」というテスト名にしたくてもできません。Javaではメソッド名を数字から始めることができないからです。だからこんなときは「月に4月を指定したら30日を返す」という感じのメソッド名にするのですが、これが微妙なストレスになります。(頭に「月を」つけるだけやんという感じですが、微妙にストレス感じるんですよこれ) Kotlinではこの制約に煩わされることがありません。メソッド名をバッククオートで囲めば、数字から始めようが、途中に空白を挟もうが問題ないのです。 @Test fun `2つの時刻の差を求める`(){ val time1 = LocalDateTime.of(2014, 1, 1, 23, 58, 30) val time2 = LocalDateTime.of(2014, 1, 2, 0, 4, 30) val actual = Duration.between(time1,time2).seconds assertThat(actual, `is`(360L)) } なにそれ気持ち悪いと思われるかもしれませんが、これはれっきとしたKotlinの仕様です。 Grammar – SimpleName Javaのメソッド名規約によってテストメソッド名を考えるのが面倒くさいなぁと感じている人は私だけではないと思いたい。 一方でKotlinでユニットテスト書けば便利なことばかりではありません。例えばassertThatなどを使おうとするとimport文を手書きで書かないと認識してくれないのが不便です。(私の環境の問題なのかもしれません。JavaだとALT+Enterでimportできるんですけどね・・・) セミコロンつけなくてもいい 単純なことですが、Kotlinは文末にセミコロンをつけなくてもいいのです。 これが便利・・・と言いたいところですが、私は半々かなぁと感じています。 確かにいちいちセミコロンつけなくてもいいので楽です。たまにJavaでコードを書くときに、しょっちゅうセミコロンつけ忘れます。それくらいには快適です。 一方セミコロンが不要なせいで、メソッドチェーンするときに私は微妙にストレスを感じます。 Javaだとメソッドチェーンするときに改行をするとインデントを一段深くしてくれます。 しかしKotlinでは改行した時に文末なのか次の文に移るのかが判別不能なので、インデントを深くしてくれたりしません。これが毎回微妙にめんどうくさいです。私はいつもドットを打ってカーソル戻して改行するという方法をとって回避しています。 多分Reformat Code(Cmd+Alt+l)を使うのが楽なんでしょうけども。みんなどうしてるんだろう・・・。 文字列の扱いが便利 Strings Javaだと文字列に変数を埋め込もうと思うと、+演算子で連結しなければなりません。もしくはString.format()を使うかですね。 Kotlinだとそんな面倒くさいことをせずとも、文字列中に変数を埋め込めるので便利です。こんな感じに書けるわけです。 val hoge = "num is $num" 埋め込む変数が多くなればなるほど、これはとても便利になります。デバッグのために変数の中身を文字列として出力して確認することがよくあると思いますが、そんなときに特に楽だと思います。 複数行に渡る文字列も、"""で囲むことでそのまま文字列として扱うことができます。ただしこれを使うと、インデントによる空白も文字列に含まれてしまうので、使いドコロが難しい気もします。 配列操作が便利 例えば配列の要素の中から最大値を取得しようと思ったら、Javaだとこんな感じになるでしょう。 int[] array = {1,20,3,40,5,16,7}; int max = 0; for (int num : array) { max = Math.max(num, max); } Kotlinだとこうです。 val array = arrayOf(1,20,3,40,5,16,7) val max = array.
Read full post gblog_arrow_right

Android Studio用のプラグインADB Friendlyを作ってみた

以前から作ってみたいなぁとは思っていたのですが、このたびやや必要性が増したこともあってAndroid Studio用のプラグインを作りました。 作成時間の半分くらいは環境構築に手間取っていたと思います。 ソースコードはGitHubで公開していますが、クローンしてもそのままビルドしたりできるのかよく分かりません。一応自分でgit cloneして確認したりしてみましたが、Androidのプロジェクトと比べると一手間必要で面倒くさい感じです。 参考にさせていただいたプラグインはほぼほぼgit cloneしただけでは動かせなかったので、Gradleは偉大だなということを再認識しました。 ADB Friendly ADB Friendlyという名前ですが、現状では端末の画面を回転させることしかできません。どんな感じかはYouTubeをご覧ください。 私は端末の画面を回転させながらメモリ使用量のグラフを見て、作成したアプリがメモリリークしていないかどうかを確認することがあります。グラフが右肩上がりに上がり続けていると、それはメモリリークが発生しているということです。 今までは端末を手に持って、縦横縦横・・・とやっていました。ところがつい最近、こんなものを買いました。Macbookのモニタ横に、スマホを固定するクリップです。 【日本正規代理店品】Ten One Design Mountie (iPhone、iPad用サブディスプレイ・マウントアダプタ) グリーン TEN-OT-000002 Twitterのタイムラインで見かけて一目惚れして買いました。実に便利です。 便利なのはいいのですが、モニタにスマホを固定していると、画面を回転させることができません。そもそも手で画面回転させるのも面倒くさいです。そこでプラグインを作ってやることにしたわけです。 環境構築が大変 参考にさせて頂いたサイトは最後にまとめました。偉大な先達たちに感謝です。 私はSDKを準備するところからつまづきました。開発に使っているのはIntelliJ IDEA 2016.1.1になるのですが、このバージョンをもとにIntelliJ Platform Plugin SDKを作るとInternal Java Platformに1.6を指定することができませんでした。 これに関しては開発に使うIntelliJと、SDKに使うIntelliJのバージョンは別物であると考えたほうがよいのだと思います。 IntelliJ Platform Plugin SDKを追加するには、プラグインを作るにあたって対象とするバージョンのIntelliJ IDEAを別途インストールし、それを指定してやるのが正しいのだと思います。 プラグインを作成する際に、AndroidでいうminSdkVersionのような指定がIntellij pluginにもあります。(私の場合<idea-version since-build="141.0"/>と指定しました) このバージョンはIntelliJ14.1を意味するので(参考:Build Number Ranges)、実際にコーディングする最新のIntelliJとは別に14.1.6をダウンロードしてインストールしました。 Previous IntelliJ IDEA Releases また、プラグインを開発していくにはソースコードがないとつらいと思います。別途IntelliJ-Community – GitHubをクローンしてソースコードを入手しておく方がいいでしょう。ちなみにcloneする際には自分がSDKに指定したブランチになっているかを確認しましょう。SDKで利用するclassファイルとソースコードの中身で食い違いが生じて余計に混乱します。 正直な所、公式のDeveloper Guideはお世辞にも分かりやすいとはいえないので、ソースコードとすでにある先人たちのPluginこそがお手本でした。 Kotlin + Gradle このプラグインはKotlinとGradleを使って作りました。既にやってくださっている方がいらしたので非常に助かりました。 KotlinとGradleで始めるAndroid Studioプラグイン開発 Kotlinを使った理由は、そんなに深い理由があるわけではありません。単に直前に作っていたアプリでKotlinを使った開発をしていた影響です。正確にはJDK1.6による開発のため、ラムダ式とか使うのにバックポートライブラリを入れるよりはKotlin使ったほうが楽かなとか、Javaで書いたときにセミコロンつけるのが面倒くさかったとか、そんな感じです。 Gradleを使ったのは、依存関係の処理に困ったからです。jarを拾ってきてlibフォルダに入れたらなんとかなるんでしょうが、どうやればいいのかがよく分からなくて、少しでも慣れているGradleを使いたかったのです。 最近読んだAndroid Studio本格活用バイブルのおかげで、「この.imlファイルを削除しても、最悪Gradleから復元できる」みたいなことが分かっていたのが大いに役立ちました。 Android Studio本格活用バイブル ~効率的にコーディングするための使い方 GitHubで公開中 ソースコードはGitHubで公開してあるので、ご意見ご感想待ってます。 細々した問題はあるものの、一応動くと思います。多分。 正直な所、自分以外の環境だと動くのかどうか分からないので、動いた・動かないの報告をいただけるだけでもありがたいです。 参考サイト・情報 参考にさせていただいた方々に感謝を。 初めてのAndroid Studioプラグイン開発入門 KotlinとGradleで始めるAndroid Studioプラグイン開発 IntelliJ Platform SDK Documentation AdbCommander for Android – BitBucket ADB Idea – GitHub Android Material Design Icon Generator – GitHub

式の即時評価を利用してオブジェクトの状態を調べる

式の即時評価が便利だよねという話です。 私は以前Calendarクラスを使って日付の処理をしようとしていました。そのとき、どのフィールドを参照すれば目的の値が引っ張ってこれるかを確認するのに、愚直にLog.d()を使っていました。1つ1つメソッドの返り値を出力して(文字列の連結でさらにカオスになる)、目的の数値がちゃんと取れているのか確認していたのです。 ドキュメントを読めよっていう話なんですが、読んでもどういう値が取れるのかいまいち分からなかったんですよね・・・。 まあそんなアホなことをやっていたので、当然のようにバグを仕込んでいました。そんなバグに気づくきっかけとなったのが式の即時評価機能です。以来、とてもお世話になっています。 式の即時評価を使えば、ブレークポイントを設定してデバッグ実行するだけで、任意のメソッドや変数の確認ができるようになります。 ブレークポイントで一時停止させないと使えないので、状態の変化を追うのには向かないかもしれません。それでもlogcat頼みのデバッグより捗る場面があると思います。 どんなときに便利か 今日遭遇したエラーで、なんかのタイミングでNullPointerExceptionが発生してクラッシュする現象が発生しました。 例外の発生する箇所はわかっているものの、どういう状況でそれが生じているのかがよく分かりませんでした。 そこで例外の発生する部分をtry-catch文で囲み、例外をキャッチした所にブレークポイントを置いて調べてみることにしました。 ブレークポイントで止めればコールスタックを遡ってオブジェクトの状態を確認できますが、目当ての変数を探すのが大変なので、そういうときに式の即時評価が便利です。だと思います。

画面をタッチして線を描く お絵かきアプリを作るための第一歩

今回の記事のサンプルコードは、GitHubで公開しています。 お絵かきアプリを作ろうと思って格闘中です。とりあえず線を描くだけでも学びがいろいろあったのでまとめておこうと思います。 Pathを使って描画するとカクカクする問題 線を描くにはPathを使うのがオーソドックスのようですが、何も考えずにパスを使った描画を行うと、線がカクカクしてしまいます。(サンプルコードのPathPaintView) path.lineTo(e.getX(), e.getY()); drawCanvas.drawPath(path, paint); これはなぜ起こるのでしょうか。 MotionEventが配信される間隔の問題 その理由はまず線をPathではなく点で描画してみると分かります。(DotPaintView) drawCanvas.drawPoint(e.getX(), e.getY(), paint); 描画される点がまばらになっています。このドットはonTouch()が呼ばれるタイミングで描画されています。このドットの間隔がタッチイベントがViewに伝えられているタイミングだということです。これはスクリーンをタッチした情報が、逐一間断なくonTouch()に渡されているわけではないことを意味しています。 Historical情報を利用する ではドットとドットの間のタッチイベントの情報は失われているのかというと、決してそうではありません。onTouchに渡されるMotionEventには、MotionEventが配信されていない時に生じた座標を保持しています。 その情報はMotionEvent.getHistoricalX()などで取得することができます。これを利用すれば、MotionEventの情報をより精細に取得することができます。(HistoricalDotPaintView) int history = e.getHistorySize(); for (int h = 0; h < history; h++){ drawCanvas.drawPoint(e.getHistoricalX(h), e.getHistoricalY(h), paint); } drawCanvas.drawPoint(e.getX(), e.getY(), paint); ドットの間隔が狭まりました。指をゆっくり動かせばキレイな線が描画できます。しかしこのHistorical情報にも限度があり、指を少しでも早く動かすとやはり間隔が空いてしまいます。 Historical情報を使ってPathによる描画を行う Historical情報を利用すれば、精度の高い座標情報を取得できることが分かりました。この座標情報をPathによる描画で利用してみます。(HistoricalPathPaintView) int history = e.getHistorySize(); for (int h = 0; h < history; h++){ path.lineTo(e.getHistoricalX(h), e.getHistoricalY(h)); } path.lineTo(e.getX(), e.getY()); drawCanvas.drawPath(path, paint); 単にpath.lineTo(x, y)で描画した時に比べると随分なめらかになりました。しかし、高速で動かしたらやっぱりカクカクしてしまうのは避けられません。なぜならpath.lineTo()による描画は、HistoricalDotPaintViewで描画した点と点の間を直線で結んでいるにすぎないからです。 これを解決するには、点と点の間をなめらかな曲線で結べば解決できそうです。 ベジェ曲線を利用する ベジェ曲線によりスムーズな線をひく方法はいろいろ考えられるでしょう。1つの方法としてこんなやり方ができます。(BezierPathPaintView) private void onTouchMove(MotionEvent e){ float midX = (previousX + e.getX()) / 2; float midY = (previousY + e.getY()) / 2; path.quadTo(previousX, previousY, midX, midY); previousX = e.getX(); previousY = e.getY(); } 自分で作っておきながら分かりやすく説明できないのですが、この処理のポイントは3つです。 前回のMotionEventで配信された座標点を記憶すること 前回の座標と今回の座標の中間点を計算すること 前回の座標を調整点とする、前回の中間点から今回の中間点までの2次ベジェ曲線を描く この方法では、正確にタッチした通りの線が描けるわけではないのですが、比較的簡単な処理でカクカクしない線を描くことができます。
Read full post gblog_arrow_right

DataBindingを試す

DataBindingがアツいらしいと聞いて試してみました。簡単な使い方をするなら想像以上に簡単でした。 今までActivityなどでfindViewByIdを書きたくないから、ButterKnifeをどのプロジェクトでも使っていたのですが、DataBindingを使えば同じようなことができます。 両者を使ってみて感じたのは、ButterKnifeがレイアウトXMLをJavaコードに持ってくるイメージであるとすれば、DataBindingはJavaコードをレイアウトXMLに持っていくイメージであるということです。 DataBindingを使うことで、Javaで作成したコードを、レイアウトXMLに埋め込むことができるようになります。レイアウトXMLでどのデータを使うか指定しておけば、Activityで「このクラス(のインスタンス)を使ってくれ」と指定するだけでその内容を表示できたりします。 具体的な使い方はData Binding Guide – Android Developersを参照してください。 DataBindingを使う設定 Android Studio 1.3以上であることが必須です。 Android Gradle Plugin 1.5.0-alpha1以上を使っていることが必須、でした。 Android Studio 2.0 betaになると、コード補完のサポートがより強力になってます。 build.gradleでDataBindingの設定を有効にすることで利用できます。 android { .... dataBinding { enabled = true } } 表示するデータを保持するクラスの作成 public class Character{ public String name; public int age; public String skill; public Character(String name, int age, String skill){ this.name = name; this.age = age; this.skill = skill; } } DataBindingを使ってアクセスするには、publicなフィールドであるか、privateなフィールドである場合publicなgetterがあることが必須です。 レイアウトXML <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" > <data> <variable name="chara" type="jp.gcreate.sample.databinding.Character" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="jp.gcreate.sample.databinding.MainActivity" > <TextView android:id="@+id/chara_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{chara.name}" /> <TextView android:id="@+id/chara_age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{Integer.toString(chara.age)}" /> <TextView android:id="@+id/chara_skill" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{chara.
Read full post gblog_arrow_right

タッチイベントについて

端末の画面をタッチした情報はMotionEventとしてActivityやViewに通知されます。 MotionEventはさまざまな情報を持っています。 MotionEvent – Android Developers アクション(触れたのか、動かしたのか、離したのか) ポインタの数(何本の指で触っているのか) タッチした座標 これらは全てポインタごと別々に識別されていて、全てポインタのインデックスでアクセスすることが出来ます。(ポインタのIDではありません) その辺りをごっちゃにしてハマった結果、Stackoverflowに投稿した質問がこちらです。Androidでマルチタッチ時のポインターIDを検出する方法(ちなみに投稿後に勘違いが原因であることに気づいた) ポインタインデックス ポインタのインデックスは必ず0から始まり、getPointerCount() - 1まで割り振られます。 例えば2本の指でタッチしている場合、getPointerCount()は2を返します。1本目の指がポインタインデックス0で、2本目がインデックス1となります。 さらにこの状態で1本目の指を離すと、2本目の指のインデックスが0に変わります。 指を離す順番によってインデックスはころころ変わるため、特定のポインタを識別するのには使えません。 例えば人差し指、中指、薬指を使ったタップを考えましょう。途中で人差し指、薬指は離したり触れたりしているとします。しかし常に中指はつけたままにして、これをトラッキングしたいとします。この場合にはポインタインデックスを使うことは出来ません。 特定のポインタを識別するにはポインタIDを利用します。 ポインタID 一度タッチするとポインタにはIDが割り当てられ、そのIDは指を離すまで変わりません。 上記の例で言うと、中指を画面から離さないかぎり中指を示すポインタのIDは常に同じです。 一方で注意しなければいけないのは、座標を取得したりするメソッドの引数はポインタインデックスであるということです。 ポインタはIDで識別するけど、そのポインタの情報を取得するために必要なのはポインタインデックスです。 そのため、特定のポインタIDの座標を取得したりするには、findPointerIndex()メソッドを使って、IDからポインタインデックスを引き出す必要があります。 インデックスとIDの違い ポインタインデックスは常に0から始まり、他のポインタが増減する度に再割当てされます。一方でポインタを識別するIDは、指が触れたときに割り振られ画面に触れている限りその値は変わりません。 例えばこんな感じになります。 インデックス0 ID0 人差し指 インデックス1 ID1 中指 インデックス2 ID2 薬指 ↓この状態で人差し指を離す インデックス0 ID1 中指 インデックス1 ID2 薬指 ↓人差し指でタッチする インデックス0 ID0 人差し指 インデックス1 ID1 中指 インデックス2 ID2 薬指 ポインタIDとポインタインデックスの値は、指を押した順番と反対に離す分には一致したままですが、押した順番とは異なる離し方をすると値がズレます。 ヒストリー タッチイベントはリアルタイムに配信されるわけではありません。 開発者向けオプションでポインタの位置を表示するようにすると、ポインタの軌跡がそのまま表示されますが、onTouchEvent()にMotionEventが配信される間隔はマチマチです。例えばgetX()で取得できる座標は飛び飛びになってしまいます。 手書きの文字を描画しようと思うと、getX()メソッドだけを使っていると、描画処理の分MotionEventが配信される間隔が空いてしまい、描画できる線がカクカクしてしまうことでしょう。 しかしちゃんとMotionEventには、前回onTouchEventに配信されてから今回配信されるまでの間に記録している情報が格納されて配信されています。 getHisorySize()を使うことで、以前のonTouchEventが呼ばれてから今回のイベントが呼ばれるまでに、いくつのイベントを保持しているかが分かります。 ヒストリー情報を使ってポインタの情報を取得するには、getHistoricalX()といったメソッドを利用することになります。 アクション タッチイベントの種類(触れたのか、離したのか、動かしたのか)はgetAction()で取得できます。 しかしgetAction()で取得できる情報は、ポインタのインデックスとポインタごとのアクションがごちゃまぜになった情報になります。例えば2本指同時押しだとgetAction()では261という数字が返ります。ちなみに1本でタッチすれば0です。 これはgetAction()がアクションの発生したポインタインデックスと、ポインタインデックスごとのアクションを全てまとめた値を取得するメソッドだからです。 getActionIndex()でアクションが発生したポインタのインデックスが分かります。 getAcitonMasked()は動作を表す純粋なアクションだけを返します。 つまりタップ(MotionEvent.ACTION_DOWN)を検出したい場合、マルチタッチを考慮するとgetActionMasked()を使う必要があるということです。getAciton()では二本指での同時押しを検出できない可能性があります。 座標 座標はgetX()でX座標、getY()でY座標を取得できます。 引数にポインタインデックスを渡すことで、指定したポインタインデックスの示す座標を取得できます。引数を省略した場合には、インデックス0の座標が取得できます。 getRawX()やgetRawY()と、getX()やgetY()の違いは、どこを基準とした座標数値が取得できるかです。 getRawX()などは座標の補正を行わない、端末のスクリーン上の座標を示します。スクリーンの左上をX=0,Y=0とした座標になります。Raw座標はポインタインデックス0のものしか取得できないみたいです。 対してgetX()はMotionEventを受け取るViewの左上をX=0,Y=0とした座標に変換されます。 サイズ getSize()でサイズが取得できます。 このサイズは何かというと、多分タッチパネルが認識しているタッチの範囲とでも言いましょうか、指のサイズみたいなイメージです。 指の触れる範囲を増やしていくとサイズも大きくなります。 圧力 getPressure()で圧力を取得できます。 感圧式のタッチパネルならそのまま圧力(どれくらいの強さで押しているのか)が分かるのだと思います。 静電気を検出する静電容量方式タッチパネルでも値は変動しますが、純粋な意味での圧力を示しているわけではありません。指の触れている範囲が大きくなれば圧力も大きくなるみたいです。 ツールタイプ 指で触れているのか、スタイラスなのかというのが、getToolType()を使うことで検出できます。 しかしこの情報でスタイラスを識別するには、当然ながらスタイラスが端末に「自分はスタイラスである」と情報を送信している必要があります。 スタイラスを識別する万能メソッドではないことは注意が必要でしょう。少なくとも端末とペアリングするタイプのスタイラスでないと、ダメだと思います。 試していませんが、Bluetoothのマウスを端末にペアリングして使うと、これでマウスのポインタが識別できるのかもしれません。 タッチイベントを確認するサンプル ActivityであればonTouchEventをオーバーライドすればタッチイベントを受け取ることが出来ます。例えばこんなコードを利用することでタッチイベントを確認することが出来ます。 public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.
Read full post gblog_arrow_right

Android Testing Codelabやってみた

Android Testing CodelabはEspressoなどのテストツールの使い方を学べるサンプルです。 全篇Englishですが、大体雰囲気でわかるレベルだと思います。 このレッスンをやれば、アプリ開発におけるテストツールの使い方、 JUnitを使ったユニットテスト(Andoridの端末を必要としないテスト) Espressoを使ったUIテスト(実機orエミュレータを必要とするテスト) が学べます。 ちょっとお得だなと思ったのが、アプリがMVPパターンで作られていることです。テストツールの使い方の勉強のついでに、MVPパターンも学べるなんて一石二鳥だな、なんて思ったのでちょっとやってみました。 思っていたよりもざっくりとした解説なので、雰囲気をつかめるものくらいに考えるといいと思います。 それでもテストのやり方よく分かっていない私からすると、学びの多いレッスンでした。 パッケージを機能で分けるやり方もある このサンプルではパッケージをレイヤーごとではなく機能ごとに分けてありました。(機能ごとというよりはActivityごとに近い分け方だと思いましたが) 私はこれまでずっと、ModelはModelパッケージに、というレイヤーごとにパッケージを分けていましたが、「機能ごとに分けた方が見やすくていいだろ」と書かれていて目からうろこでした。 ProductFlavorを使ったクラスの切り替え テストのためにモック用のクラスに差し替えるやり方の解説があります。 XMLのリソースファイル(strings.xmlなど)は異なるFlavorで同一のリソース名が存在した場合、Flavorのものが優先されmainで定義したリソースは上書きされます。 一方でJavaのクラスだと挙動が異なり、同一名のクラスが存在するとエラーになります。そのため、全てのFlavor共通で利用するクラスだけをmainに配置し、切り替えが必要なクラスはFlavorのディレクトリに配置するという工夫が必要になります。 モックを利用したJUnitのテスト Mockitoを使ったJUnit4のテストのやり方が勉強になりました。これは単純に私がMockitoの使い方がよく分かっていなかったからですが。 @Mockアノテーションに寄る初期化とか、ArgumentCaptorの使い方とか。 EspressoによるUIテスト Espresso-IntentsによるIntentのモック方法、Espresso-Contribを使ったナビゲーションドロワーのUIテストなどが紹介されています。 Espressoテストの章になると、一部修正が必要な部分がありましたが、それもまた勉強になりました。(EditTextへ文字入力をエミュレートした後は、croseKeyboard()しないとエラーになるとか、上へボタンを参照する部分が英語以外の環境だとエラーになるとか)

jarファイルで配布されているライブラリをAndroid Studioで取り込む

Android StudioはビルドツールにGradleを使っているので、ライブラリはbuild.gradleのdependenciesに書くことで簡単に取り込むことが出来ます。 しかし、ライブラリによってはjarファイルで配布されているものもあります。(この例ではNiftyのMobile backend) jarで配布されるライブラリを組み込む手順は簡単です。app/libsディレクトリにjarファイルを置くだけで完了です。 これはapp/build.gradleにて、libsディレクトリにあるjarファイルをビルド時にコンパイルするよう指定されているからです(compile fileTreeの部分)。 dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.+' compile 'com.android.support:design:23.+' } libsディレクトリなんかない、という場合、プロジェクトビューがAndroidになっている可能性が考えられます(デフォルトではAndroidになっています)。この場合、Projectに表示を切り替えることでディレクトリ階層が表示されるようになるはずです。 それでも見つからなければappディレクトリの下にlibsディレクトリを作成し、app/build.gradleにcompile fileTree(dir: 'libs', include: ['*.jar'])を追加すれば組み込めると思います。