<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Unmotivated]]></title>
  <link href="http://blog.lciel.jp/atom.xml" rel="self"/>
  <link href="http://blog.lciel.jp/"/>
  <updated>2014-06-13T12:01:31+09:00</updated>
  <id>http://blog.lciel.jp/</id>
  <author>
    <name><![CDATA[lciel]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Strings などのリソースを動的に取得する]]></title>
    <link href="http://blog.lciel.jp/blog/2014/06/13/get-all-resource-ids/"/>
    <updated>2014-06-13T11:58:51+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/06/13/get-all-resource-ids</id>
    <content type="html"><![CDATA[<p>Android において、静的にリソース名を指定せずに、動的にリソースIDを取得したいことが時々あります。</p>

<p>ある範囲のリソースが欲しいなど、一定の規則でリソース名が決まっている場合は以下の方法でリソースが取れます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="c1">// prefix0, prefix1, prefix2, ... と言う名前のリソースを取得する</span>
</span><span class='line'><span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="o">;;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">resourceId</span> <span class="o">=</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getIdentifire</span><span class="o">(</span><span class="s">&quot;prefix&quot;</span> <span class="o">+</span> <span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">i</span><span class="o">),</span> <span class="s">&quot;string&quot;</span><span class="o">,</span> <span class="n">getPackageName</span><span class="o">());</span>
</span><span class='line'>    <span class="k">if</span><span class="o">(</span><span class="n">resourceId</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">break</span><span class="o">;</span>
</span><span class='line'>    <span class="c1">// リソースを取得</span>
</span><span class='line'>    <span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">resourceId</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>全てのリソースが欲しい場合は Reflection でなんとかなります。<br/>
例えば Strings に定義されたリソースを全て取得したい場合は、以下で取得可能です。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">Field</span><span class="o">[]</span> <span class="n">fields</span> <span class="o">=</span> <span class="n">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getFields</span><span class="o">();</span>
</span><span class='line'><span class="k">for</span><span class="o">(</span><span class="n">Field</span> <span class="nl">field:</span><span class="n">fields</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">try</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">resourceId</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="na">getInt</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
</span><span class='line'>        <span class="k">if</span><span class="o">(</span><span class="n">resourceId</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="c1">// リソース名</span>
</span><span class='line'>            <span class="n">String</span> <span class="n">resourceName</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="na">getName</span><span class="o">();</span>
</span><span class='line'>            <span class="c1">// リソースを取得</span>
</span><span class='line'>            <span class="n">String</span> <span class="n">str</span> <span class="o">=</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">resourceId</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span><span class="k">catch</span><span class="o">(</span><span class="n">IllegalAccessException</span> <span class="n">e</span><span class="o">){</span>
</span><span class='line'>        <span class="n">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Google Glass レビュー]]></title>
    <link href="http://blog.lciel.jp/blog/2014/06/09/google-glass-review/"/>
    <updated>2014-06-09T21:00:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/06/09/google-glass-review</id>
    <content type="html"><![CDATA[<p>ついにねんがんの Google Glass をてにいれたぞ！(今更)</p>

<p><img src="http://blog.lciel.jp/images/glass_review0.jpg" alt="Google Glass Box" /></p>

<p>ざっと触ってみたところで、使用感などのレビューをしてみます。</p>

<h2>目次</h2>

<ul>
<li>Glass の見え方</li>
<li>操作

<ul>
<li>音声入力</li>
<li>タッチパネル</li>
<li>その他の入力</li>
</ul>
</li>
<li>デザイン</li>
<li>スペックやバッテリなど</li>
<li>まとめ</li>
</ul>


<!-- more -->


<h2>Glass の見え方</h2>

<p>Glass に関して最も興味があったのが、どう見えるのか？という点でした。</p>

<p>Glass は右目の視界に入るように設置されたプリズムに、映像が投射される仕組みになっています。<br/>
この<a href="https://www.youtube.com/watch?v=4EvNxWhskf8">動画</a>だと視界の中央にディスプレイが表示されているように見えますが、実際は視界の右上に映像が浮かぶように表示され、右目の視界を占有するわけではありません。</p>

<p><img src="http://blog.lciel.jp/images/glass_review1.jpg" alt="Glass Prism" /></p>

<p>初見の感想としては、『未来感あるな』という感じです。<br/>
ディスプレイが浮かんで見える様子は、同じウェアラブルでもスマートウォッチなどとは比べ物にならないわくわく感があります。</p>

<p>一方で、映像は右目前に設置されたガラスのプリズムにむすばれるので、焦点をそこに合わせなければ Glass のディスプレイはほとんど認識できないのがかなり残念な点です。</p>

<p><img src="http://blog.lciel.jp/images/glass_review2.jpg" alt="Glass Display" /></p>

<p>ディスプレイを見つめると、瞳が右上方向に動き、若干あさっての方向を向いたような怪しい表情になります。
また、焦点を目からとても近い位置に合わせることになるので、偉い疲れます。</p>

<p>そして、見え方に関してなにより残念だったのが、実際に見ている風景とディスプレイを同時に見ることができないことです。</p>

<p>ディスプレイと同時に風景が見えないとなると、 AR 的な展開への期待感はかなり薄れる感じがします。
Word Lens のやり方のように、カメラからキャプチャした画像を置き換えるという方法が主流になるのでしょうか。
AR を主眼に置いているらしい <a href="http://tele-pathy.org/">Telepathy One</a> はどういう見え方をするのか、とても気になるところです。(みてみたい)</p>

<p>また、ディスプレイが小さいため、写真や動画などを見る際は『サムネイルくらい』の見え方になります。
たとえば、レシピを Glass で撮影し、表示しながら料理を作るということにトライしてみたのですが、文字が小さすぎてとてもじゃないけど読めるレベルではありませんでした。</p>

<p>割とネガティブな感想が続いてしまいましたが、一言で見え方をまとめると『疲れるし小さいが、確かなわくわく感がそこにある』という感じかなと思います。</p>

<h2>操作</h2>

<p>Glass への入力は、主に音声入力や、本体横のタッチパネルを通して行われます。<br/>
インタフェースは無理なくうまく作られているなーと感じました。</p>

<h3>音声入力</h3>

<p>ホーム画面(？)で「OK, glass」と声をかけ、その後続けて各種 GlassWare(アプリケーション) の起動に割り当てられたコマンドを音声入力する事で、GlassWare を起動します。</p>

<p>アプリケーション内でも「Share to」など、いくつかのコマンドを音声入力で拾ってくれます。
音声入力を受け付けている場合、「OK, glass」の文字が小さく表示され、その後受付可能コマンドがディスプレイに表示されるため、仕組みを理解すれば迷う事無く音声入力できるようになります。</p>

<p>音声入力は感度が高く、静かな所なら呟くような小声でも拾ってくれます。(ささやき声では無理でした)</p>

<p>また、発音が悪すぎることで認識してくれないのではないか？とかなり危惧していたのですが、意外とすんなり入力可能でした。
骨伝導マイクで音を拾っているのか、Glass を着けた状態でしか音声は認識されませんでした。</p>

<h3>タッチパネル</h3>

<p>Glass 右側、つるの部分についているタッチパネルを使う事で、音声入力無しでも Glass を操作する事が出来ます。</p>

<p><img src="http://blog.lciel.jp/images/glass_review3.jpg" alt="Glass Touch Panel" /></p>

<p>音声で操作するよりも、タッチパネルで操作する事のほうが実用的かと思います。<br/>
Siri とかどのくらい使われてるんでしょうかね。</p>

<p>タッチ操作はどのシーンにおいても、シングルタップ(決定)、下スワイプ(キャンセル・戻る)、左右スワイプ(選択)というシンプルなルールになっています。
このルールのおかげで、タッチパネルの操作では迷う事がほぼありませんでした。</p>

<h3>その他の入力</h3>

<p>本体内側の近接センサー？(赤外線センサー？)でウィンクを判定しているようです。
ウィンクを入力する事で写真が撮影できるのですが、反応しなかったり誤爆したりと、ウィンクよりも Glass の『つる』部分についている物理撮影ボタンを押す方に信頼感があります。ウィンク撮影機能を OFF にできるオプションが用意されていることからも、ウィンク判定には苦労していそうに感じます。</p>

<p>頭を30度上に傾ける事で、Glass の sleep/wakeup を切り替えることができます。
これはなかなか感度が良く、かなり実用的に思います。
ディスプレイに表示される要素が多くてはみだす場合は、頭を傾ける事でスクロールが可能です。</p>

<p>また、 Glass を外すと自動的に sleep し、着けると自動的に wakeup します。
近接センサーと加速度センサーの組み合わせでしょうか、この機能の感度もいい感じです。</p>

<h2>デザイン</h2>

<p>思ったよりもデザインは洗練されていて、高級感もあり、ファッションとしてもなんとか受け入れられそうなレベルに感じました。
着けた人に対して「あー、わりと似合う」というやり取りが発生したくらいです。
デザイン的に日本には浸透できないんじゃないかと思っていましたが、全然そんなことは無さそうに思いました。</p>

<p><img src="http://blog.lciel.jp/images/glass_review4.jpg" alt="Glass Design" /></p>

<p>もちろん、ディスプレイが目立つため、街で着けていたらぎょっとすると思います。<br/>
でも、それは昔 iPad を電車内で開いている人を見たときに感じたものと似た気持ちじゃないかなーと個人的には思います。</p>

<h2>スペックやバッテリなど</h2>

<p>Glass はヌルサクからはまだ程遠いです。</p>

<p>タッチパネル入力の反応が悪かったり、動画の再生がコマ落ちしたり、固まったりする事が多々あります。
初期の Android を思い出す動きです。</p>

<p>パフォーマンスが極端に落ちる時は、同時にバッテリー(CPU？)が発熱している場合がほとんどなので、もしかしたら熱にやられているのかもしれません。
色々なところで言われていますが、 Glass は連続して使用していると、がんがん発熱します。
火傷しそうで着けていられない！という程ではないですが、夏場はちょっと辛そうに思います。</p>

<p>バッテリの持ちに関しては、『通常使用で一日程度』と銘打たれているものの、実際は『ほとんど利用しないで一日程度』だと思った方が良さそうです。
sleep させているときはそうでもないものの、 GlassWare を起動するとぐりぐりとバッテリが減っていきます。
個人的には、むしろこの大きさでこの機能でこのくらい持つのが凄いなと思うのですが、一日着用して利用する場合を考えると、圧倒的に足りない気がします。</p>

<h2>まとめ</h2>

<p><strong>『とても未来を感じる面白いデバイスだが、すぐに必需品にはならなそう』</strong>というのが素直な感想です。</p>

<p>現状のスペックと $1500 という値段を考えると、しばらくは高いおもちゃという位置づけになりそうです。</p>

<p>そして何よりも、夢あふれるこのデバイスをどう使う？というのがやはり難しいです。
Glass を実際に触ってみて、 Google が Explorer を集めていた理由をリアルに感じた気がします。<br/>
かなり凄い機械なんですが、かなりやる事が無いのです。</p>

<p>First Person の視点で写真や動画を撮ってシェアも面白かったですが、ほとんどの場合はスマホで十分であり、このために Glass を常用するものではなさそうです。
ナビも感動しましたがこれもスマホで十分ですし、文字を認識して翻訳する Word Lens はおもしろかったですが、現状の認識速度だと実用には厳しそうです。
(この辺りはハードウェアの向上で解決されるのかもしれませんが&hellip;)</p>

<p>キラーコンテンツが生み出されるかどうかに、 Glass の今後がかかっていそうです。</p>

<p>次は GlassWare を書いて遊んでみようと思います。</p>

<p>※ Hangouts など、他にも面白そうだけれどまだ触っていないものもあるので、この辺りを触って印象が変わったらまた追記します</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[9-Patch のコンテンツ領域は伸縮しない]]></title>
    <link href="http://blog.lciel.jp/blog/2014/04/09/ninepatchs-content-bounds-is-not-flexible/"/>
    <updated>2014-04-09T20:39:16+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/04/09/ninepatchs-content-bounds-is-not-flexible</id>
    <content type="html"><![CDATA[<p>9-Patch でコンテンツ領域を指定することはよくあるけれど、実は NinePatchDrawable を Background とした View のサイズを変更しても、コンテンツ領域(というか Padding) はうまい感じに伸縮してくれない。</p>

<p>たとえば次のような 9-Patch の画像を用意してコンパイル、NinePatchDrawable として読み込んだ場合を考える。</p>

<p><img src="http://blog.lciel.jp/images/star.9.png" alt="star" /></p>

<!-- more -->


<p>以下のようなレイアウトだった場合を考えてみる。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;LinearLayout</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">xmlns:tools=</span><span class="s">&quot;http://schemas.android.com/tools&quot;</span>
</span><span class='line'>    <span class="na">android:id=</span><span class="s">&quot;@+id/rootView&quot;</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:orientation=</span><span class="s">&quot;vertical&quot;</span> <span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;FrameLayout</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;100dp&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;100dp&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@drawable/star&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;TextView</span>
</span><span class='line'>            <span class="na">android:layout_width=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:text=</span><span class="s">&quot;@string/aaa&quot;</span>
</span><span class='line'>            <span class="na">android:background=</span><span class="s">&quot;#ff0000&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/FrameLayout&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;FrameLayout</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;@dimen/original_drawable_width&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;@dimen/original_drawable_height&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@drawable/star&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;TextView</span>
</span><span class='line'>            <span class="na">android:layout_width=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:text=</span><span class="s">&quot;@string/aaa&quot;</span>
</span><span class='line'>            <span class="na">android:background=</span><span class="s">&quot;#ff0000&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/FrameLayout&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;FrameLayout</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;200dp&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;200dp&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@drawable/star&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;TextView</span>
</span><span class='line'>            <span class="na">android:layout_width=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:text=</span><span class="s">&quot;@string/aaa&quot;</span>
</span><span class='line'>            <span class="na">android:background=</span><span class="s">&quot;#ff0000&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/FrameLayout&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/LinearLayout&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>なんとなく次のように伸縮してくれそうな気がするが&hellip;</p>

<p><img src="http://blog.lciel.jp/images/ninepatch-expand-success.png" alt="理想" /></p>

<p>実際に表示されるレイアウトは以下のようになる。</p>

<p><img src="http://blog.lciel.jp/images/ninepatch-expand-failure.png" alt="現実" /></p>

<p>View.java が setBackgroundDrawable() のときにしか padding を設定してくれないために、このようになってしまう。</p>

<p>コンテンツ領域が伸縮しない場合もあるので当然といえば当然だけれど、今回のような 9-Patch 画像のように、View のサイズについてきてほしい場合もある。</p>

<h2>コンテンツ領域を伸縮させる</h2>

<p>そこで、 NinePatchDrawable から元々の padding を取得して、現在の View のサイズに合うように伸縮させてみる。</p>

<div><script src='https://gist.github.com/10258303.js'></script>
<noscript><pre><code>package jp.lciel.example;

import android.app.Activity;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ViewGroup rootView = (ViewGroup)findViewById(R.id.rootView);
        // View のサイズが決まってから実行
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int originalDrawableWidth  = getResources().getDimensionPixelSize(R.dimen.original_drawable_width);
                int originalDrawableHeight = getResources().getDimensionPixelSize(R.dimen.original_drawable_height);
                for (int i=0; i&lt;rootView.getChildCount(); i++) {
                    View targetView = rootView.getChildAt(i);
                    updatePadding(targetView, originalDrawableWidth, originalDrawableHeight);
                }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private void updatePadding(View targetView, int originalWidth, int originalHeight) {
        Drawable background = targetView.getBackground();
        if(background instanceof NinePatchDrawable) {
            float scaleX = (float)targetView.getWidth() / (float)originalWidth;
            float scaleY = (float)targetView.getHeight() / (float)originalHeight;

            Rect padding = new Rect();
            ((NinePatchDrawable) background).getPadding(padding);
            int left   = (int)(padding.left * scaleX);
            int right  = (int)(padding.right * scaleX);
            int top    = (int)(padding.top * scaleY);
            int bottom = (int)(padding.bottom * scaleY);
            targetView.setPadding(left, top, right, bottom);
        }
    }

}
</code></pre></noscript></div>


<p>これで以下のように伸縮してくれる。</p>

<p><img src="http://blog.lciel.jp/images/ninepatch-expand-success.png" alt="結果" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[XVim を Xcode 5.1 にインストール]]></title>
    <link href="http://blog.lciel.jp/blog/2014/03/17/installation-of-xvim/"/>
    <updated>2014-03-17T13:48:43+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/03/17/installation-of-xvim</id>
    <content type="html"><![CDATA[<p>vim キーバインドじゃないとなにもやる気が起きないので、 Xcode 5.1 に <a href="https://github.com/Jugglershu/XVim">XVim</a> を導入します。</p>

<h2>インストール</h2>

<h4>1. リポジトリをクローン</h4>

<ul>
<li>clone</li>
</ul>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span>git clone https://github.com/JugglerShu/XVim.git
</span></code></pre></td></tr></table></div></figure>


<ul>
<li>XCode 5.1 の場合は develop Branch を使うように指定があるので、 develop Branch を Checkout</li>
</ul>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="nv">$ </span><span class="nb">cd </span>XVim
</span><span class='line'><span class="nv">$ </span>git branch -a
</span><span class='line'>* master
</span><span class='line'>  remotes/origin/HEAD -&gt; origin/master
</span><span class='line'>  remotes/origin/bang
</span><span class='line'>  remotes/origin/dev/buffer-refactor
</span><span class='line'>  remotes/origin/develop
</span><span class='line'>  remotes/origin/features/hlcolor#458
</span><span class='line'>  remotes/origin/features/substitute
</span><span class='line'>  remotes/origin/features/unittest
</span><span class='line'>  remotes/origin/features/vs-sp#365
</span><span class='line'>  remotes/origin/gh-pages
</span><span class='line'>  remotes/origin/handlingMouseEvents
</span><span class='line'>  remotes/origin/master
</span><span class='line'>  remotes/origin/v2.0-dev/Logging#449
</span><span class='line'>  remotes/origin/windowing
</span><span class='line'><span class="nv">$ </span>git checkout develop
</span><span class='line'><span class="nv">$ </span>git branch
</span><span class='line'>* develop
</span><span class='line'>  master
</span></code></pre></td></tr></table></div></figure>


<h4>2. ビルド〜インストール</h4>

<ul>
<li>Xcode を開いて <code>XVim.xcodeproj</code> をロード</li>
<li>スキームを Xcode5 に変更
<img src="http://blog.lciel.jp/images/xvim_01.png" alt="xvim 01" /></li>
<li>Edit Scheme を開いて
<img src="http://blog.lciel.jp/images/xvim_02.png" alt="xvim 02" /></li>
<li>Build Configuration を Release に変更
<img src="http://blog.lciel.jp/images/xvim_03.png" alt="xvim 03" /></li>
<li>ビルド&amp;実行すると自動的にプラグインに登録される</li>
<li>Xcode を再起動</li>
</ul>


<h2><code>.xvimrc</code> を設置</h2>

<ul>
<li><code>~/.vimrc</code> の代わりに <code>~/.xvimrc</code> が適用される</li>
<li>使用可能コマンドの一覧は<a href="https://github.com/JugglerShu/XVim/blob/master/Documents/Users/FeatureList.md">こちら</a>を参照</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android の Resources における画像(Drawable)についての話]]></title>
    <link href="http://blog.lciel.jp/blog/2014/03/09/about-resources-and-drawables/"/>
    <updated>2014-03-09T02:13:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/03/09/about-resources-and-drawables</id>
    <content type="html"><![CDATA[<p>Android で Resources から getDrawable() などして画像をとった場合、一体それはいつどんなタイミングでメモリに読み込まれているのか？
キャッシュはされているのか？</p>

<p>いい加減把握しておきたかったので、これも調べました。</p>

<p>API 17(4.2.2_r1)で見た結果なので、他のバージョンのSDKでも同様かはわかりませんが、多分同じ感じだと思います。</p>

<!-- more -->


<h2>リソース画像は getDrawable() 時に初めてメモリにロードされる</h2>

<p>リソースの画像ファイルは、いい感じに起動時にロードしてメモリにキャッシュしてくれているのだろうと思っていたのですが、
普通に<strong>「Resources#getDrawable() 時に初めてファイルからメモリへロードされる」</strong>というのが正解でした。</p>

<p>そもそも、Resources からメモリにビットマップが展開されると、デフォルトの RGBA_8888 で読み込まれるため、
たとえば読み込まれた結果 600 x 800 ピクセルになる画像でも、色情報だけで600*800*4byteで約1.9MBとなり、
全部ロードしておくなどというのは到底無茶な話でした。</p>

<p>一度読み込んだビットマップは Resources がキャッシュしてくれています。
ただし WeakReference で保持されているため、実参照を切ったら割と簡単に消えそうです。</p>

<p>まとめると以下のようになります。</p>

<ul>
<li><strong>getDrawable() のタイミングでファイルI/Oが発生する</strong></li>
<li><strong>Resources の画像はキャッシュはされるが揮発性が高い</strong></li>
</ul>


<p>ちなみに上記は BitmapDrawable についての話でしたが、 ColorDrawable についても同様で、
getDrawable() のタイミングで生成されており、同様に WeakReference によるキャッシュも作成されていました。</p>

<h2>一部のシステムリソースは常にメモリに乗っている</h2>

<p>getDrawable() 時にファイルからロードされると書きましたが、一部のシステムリソースは preload としてシステムの起動時に読み込まれ、常にメモリ上に乗っているようです。<br/>
なので、このシステムリソースを使う際は、ファイルI/Oなし、かつ追加でメモリを消費することなく使えてお得そうです。</p>

<p>具体的には以下に書かれた Drawable が preload としてシステムの起動時に読み込まれていました。</p>

<ul>
<li><a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/frameworks/base/core/res/res/values/arrays.xml">core/res/res/values/arrays.xml</a>

<ul>
<li>preloaded_drawables</li>
<li>preloaded_color_state_lists</li>
</ul>
</li>
</ul>


<h2>(おまけ)画面密度ごとに画像ファイルを作るべき？</h2>

<p>リソースを読み込む際、ざっと見た感じ density の値を考慮して、BitmapFactory.Options の inScreenDensity を設定して Bitmap を読み込んでいます。<br/>
そのため、メモリ上に保持される Bitmap は画面密度にあったサイズ(容量)になります。</p>

<p>「画面密度の小さい端末(例えばmdpi)で、大きい画面密度の画像(例えばxhdpi)を読み込むとメモリを余計に食うので、画面密度にあった画像を用意するべき」
という tips がありますが、これって正しいの？という疑問を持ったので、こちらも軽く調べました。</p>

<p>結論から言うと、<strong>「自分より大きい画面密度の画像に限定されず、画面密度が異なる画像を読み込むと余計にメモリもCPUも食う」</strong>ということになりそうです。
なんてこった。<br/>
ただし、メモリを余計に食うのは Bitmap 生成時のみです。</p>

<p>BitmapFactory.createFromResourcesStream() などで Bitmap を生成する場合、 inScreenDensity などが inDensity と異なって設定されている場合、
一度原寸大で Bitmap を生成し、その Bitmap から Bitmap.createScaledBitmap() で density にあった scale された画像を作るようです。
原寸大の Bitmap はその後すぐ recycle() されていますが、原寸大と scale された両方の Bitmap がメモリ上にロードされることになります。</p>

<p>というわけで、画面密度にあったサイズの画像を用意した方が、メモリとCPUに優しいということになりそうです。</p>

<p>シェアが多い hdpi xhdpi あたりはカバーしといた方が良さそうです。<br/>
<a href="https://developer.android.com/about/dashboards/index.html">dashboard</a> ではまだそうでもないですが、体感的には xxhdpi もかなり増えてる気がします。<br/>
アプリサイズとのにらみ合いが辛い今日この頃。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[GestureDetector でリスナに渡ってくる MotionEvent が null になる]]></title>
    <link href="http://blog.lciel.jp/blog/2014/02/27/onfling-onscroll-getting-a-null-motionevent/"/>
    <updated>2014-02-27T19:30:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/02/27/onfling-onscroll-getting-a-null-motionevent</id>
    <content type="html"><![CDATA[<p>タッチジェスチャを検出する場合は、 GestureDetector に次のようなリスナを渡して判定するのが常套手段ですが、<a href="http://developer.android.com/reference/android/view/GestureDetector.OnGestureListener.html#onScroll%28android.view.MotionEvent,%20android.view.MotionEvent,%20float,%20float%29">onScroll()</a> や <a href="http://developer.android.com/reference/android/view/GestureDetector.OnGestureListener.html#onFling%28android.view.MotionEvent,%20android.view.MotionEvent,%20float,%20float%29">onFling()</a> の第一引数の e1 にはジェスチャの開始地点の MotionEvent が入ります。<br/>
ところが、時々 e1 に null が渡ってくることがあって困りました。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kd">class</span> <span class="nc">MyGestureListener</span> <span class="kd">extends</span> <span class="n">SimpleOnGestureListener</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onScroll</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">e1</span><span class="o">,</span> <span class="n">MotionEvent</span> <span class="n">e2</span><span class="o">,</span>
</span><span class='line'>            <span class="kt">float</span> <span class="n">distanceX</span><span class="o">,</span> <span class="kt">float</span> <span class="n">distanceY</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// なぜか e1 が null !!</span>
</span><span class='line'>        <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onFling</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">e1</span><span class="o">,</span> <span class="n">MotionEvent</span> <span class="n">e2</span><span class="o">,</span>
</span><span class='line'>            <span class="kt">float</span> <span class="n">velocityX</span><span class="o">,</span> <span class="kt">float</span> <span class="n">velocityY</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// なぜか e1 が null !!</span>
</span><span class='line'>        <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>ググるといくつか stackoverflow が見つかったけど、どれも根本解決には至っていない様子。</p>

<ul>
<li><a href="http://stackoverflow.com/questions/4151385/android-simpleongesturelistener-onfling-getting-a-null-motionevent">Android SimpleOnGestureListener.onFling getting a null MotionEvent</a></li>
<li><a href="http://stackoverflow.com/questions/17390873/onfling-motionevent-e1-null">OnFling MotionEvent e1 null?</a></li>
</ul>


<p>というわけで、原因を調べてみました。</p>

<p>結論を先に言うと、 ACTION_DOWN のタッチイベント(MotionEvent)を GestureDetector#onTouchEvent() に渡せていないのが原因でした。</p>

<!-- more -->


<h2>原因特定</h2>

<p>GestureDetector のコードを見てみる。</p>

<figure class='code'><figcaption><span>GestureDetector.java(2.2_r1)</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">ev</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">mIsDoubleTapping</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// Give the move events of the double-tap</span>
</span><span class='line'>        <span class="n">handled</span> <span class="o">|=</span> <span class="n">mDoubleTapListener</span><span class="o">.</span><span class="na">onDoubleTapEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">mAlwaysInTapRegion</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">int</span> <span class="n">deltaX</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">x</span> <span class="o">-</span> <span class="n">mCurrentDownEvent</span><span class="o">.</span><span class="na">getX</span><span class="o">());</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">int</span> <span class="n">deltaY</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">y</span> <span class="o">-</span> <span class="n">mCurrentDownEvent</span><span class="o">.</span><span class="na">getY</span><span class="o">());</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">distance</span> <span class="o">=</span> <span class="o">(</span><span class="n">deltaX</span> <span class="o">*</span> <span class="n">deltaX</span><span class="o">)</span> <span class="o">+</span> <span class="o">(</span><span class="n">deltaY</span> <span class="o">*</span> <span class="n">deltaY</span><span class="o">);</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">distance</span> <span class="o">&gt;</span> <span class="n">mTouchSlopSquare</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="c1">// onScroll が呼ばれる</span>
</span><span class='line'>            <span class="n">handled</span> <span class="o">=</span> <span class="n">mListener</span><span class="o">.</span><span class="na">onScroll</span><span class="o">(</span><span class="n">mCurrentDownEvent</span><span class="o">,</span> <span class="n">ev</span><span class="o">,</span> <span class="n">scrollX</span><span class="o">,</span> <span class="n">scrollY</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mLastMotionX</span> <span class="o">=</span> <span class="n">x</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mLastMotionY</span> <span class="o">=</span> <span class="n">y</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mAlwaysInTapRegion</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mHandler</span><span class="o">.</span><span class="na">removeMessages</span><span class="o">(</span><span class="n">TAP</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mHandler</span><span class="o">.</span><span class="na">removeMessages</span><span class="o">(</span><span class="n">SHOW_PRESS</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mHandler</span><span class="o">.</span><span class="na">removeMessages</span><span class="o">(</span><span class="n">LONG_PRESS</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">distance</span> <span class="o">&gt;</span> <span class="n">mBiggerTouchSlopSquare</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mAlwaysInBiggerTapRegion</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">((</span><span class="n">Math</span><span class="o">.</span><span class="na">abs</span><span class="o">(</span><span class="n">scrollX</span><span class="o">)</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">||</span> <span class="o">(</span><span class="n">Math</span><span class="o">.</span><span class="na">abs</span><span class="o">(</span><span class="n">scrollY</span><span class="o">)</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="o">))</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// onScroll が呼ばれる</span>
</span><span class='line'>        <span class="n">handled</span> <span class="o">=</span> <span class="n">mListener</span><span class="o">.</span><span class="na">onScroll</span><span class="o">(</span><span class="n">mCurrentDownEvent</span><span class="o">,</span> <span class="n">ev</span><span class="o">,</span> <span class="n">scrollX</span><span class="o">,</span> <span class="n">scrollY</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mLastMotionX</span> <span class="o">=</span> <span class="n">x</span><span class="o">;</span>
</span><span class='line'>        <span class="n">mLastMotionY</span> <span class="o">=</span> <span class="n">y</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">mIsDoubleTapping</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// Finally, give the up event of the double-tap</span>
</span><span class='line'>        <span class="n">handled</span> <span class="o">|=</span> <span class="n">mDoubleTapListener</span><span class="o">.</span><span class="na">onDoubleTapEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">mInLongPress</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mHandler</span><span class="o">.</span><span class="na">removeMessages</span><span class="o">(</span><span class="n">TAP</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mInLongPress</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">mAlwaysInTapRegion</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">handled</span> <span class="o">=</span> <span class="n">mListener</span><span class="o">.</span><span class="na">onSingleTapUp</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="c1">// A fling must travel the minimum tap distance</span>
</span><span class='line'>        <span class="kd">final</span> <span class="n">VelocityTracker</span> <span class="n">velocityTracker</span> <span class="o">=</span> <span class="n">mVelocityTracker</span><span class="o">;</span>
</span><span class='line'>        <span class="n">velocityTracker</span><span class="o">.</span><span class="na">computeCurrentVelocity</span><span class="o">(</span><span class="mi">1000</span><span class="o">,</span> <span class="n">mMaximumFlingVelocity</span><span class="o">);</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">float</span> <span class="n">velocityY</span> <span class="o">=</span> <span class="n">velocityTracker</span><span class="o">.</span><span class="na">getYVelocity</span><span class="o">();</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">float</span> <span class="n">velocityX</span> <span class="o">=</span> <span class="n">velocityTracker</span><span class="o">.</span><span class="na">getXVelocity</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="o">((</span><span class="n">Math</span><span class="o">.</span><span class="na">abs</span><span class="o">(</span><span class="n">velocityY</span><span class="o">)</span> <span class="o">&gt;</span> <span class="n">mMinimumFlingVelocity</span><span class="o">)</span>
</span><span class='line'>                <span class="o">||</span> <span class="o">(</span><span class="n">Math</span><span class="o">.</span><span class="na">abs</span><span class="o">(</span><span class="n">velocityX</span><span class="o">)</span> <span class="o">&gt;</span> <span class="n">mMinimumFlingVelocity</span><span class="o">)){</span>
</span><span class='line'>            <span class="c1">// onFling が呼ばれる</span>
</span><span class='line'>            <span class="n">handled</span> <span class="o">=</span> <span class="n">mListener</span><span class="o">.</span><span class="na">onFling</span><span class="o">(</span><span class="n">mCurrentDownEvent</span><span class="o">,</span> <span class="n">ev</span><span class="o">,</span> <span class="n">velocityX</span><span class="o">,</span> <span class="n">velocityY</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>どちらも mCurrentDownEvent がそのまま渡されるだけなので、 mCurrentDownEvent を確認する。</p>

<figure class='code'><figcaption><span>GestureDetector.java(2.2_r1)</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">ev</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_DOWN</span><span class="o">:</span>
</span><span class='line'>        <span class="c1">// ...</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mCurrentDownEvent</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mCurrentDownEvent</span><span class="o">.</span><span class="na">recycle</span><span class="o">();</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="n">mCurrentDownEvent</span> <span class="o">=</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">obtain</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>というわけで ACTION_DOWN のイベントを GestureDetector#onTouchEvent() に渡せていないのが原因でした。</p>

<p>ジェスチャを判定したい View において dispatchTouchEvent() や onInterceptTouchEvent() なんかでイベントの分配をしている状況だと、 View の onTouchEvent() に ACTION_DOWN の MotionEvent が渡らなかったりするので、そう言うときに発生していたみたい。</p>

<p>今回は別のところでタッチ時の情報を保存していたので、その情報を使って e1 の代わりとさせました。<br/>
そもそも GestureDetector が ACTION_DOWN 時に色々初期化しているので、これを渡せないと onScroll() とか onFling() は判定されたものの、そもそも全く判定されないジェスチャが盛りだくさんかと思われます。<br/>
ちゃんと全てのイベントを渡せるようにした方がよさそう。</p>

<p>ちなみに、どんな時でもジェスチャを判定させたいなら View#dispatchTouchEvent() で GestureDetector#onTouchEvent() を呼び出したりすれば、ややこしいことは一切抜きで子供の View に邪魔されずにジェスチャ判定できたりします。(その View にタッチイベントが回って来てさえいれば:<a href="http://blog.lciel.jp/blog/2013/12/03/android-touch-event/">参考</a>)</p>

<h2>余談</h2>

<p>GestureDetector のジェスチャ判定のためのパラメータを変更できないのかな？と前々から疑問に思っていたのでついでに読んでみたけど、どうも定数がぶち込まれるようになっているのでやっぱりできないっぽいです。<br/>
onFling() で拾った後に velocity でさらに絞る&hellip;とかいつもやっているので、 GestureDetector 自体にパラメータを渡せた方が楽そうなんだけど&hellip;。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android デフォルトのアニメーションなどを調べる]]></title>
    <link href="http://blog.lciel.jp/blog/2014/02/12/android-framework-resources/"/>
    <updated>2014-02-12T12:21:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/02/12/android-framework-resources</id>
    <content type="html"><![CDATA[<p>フレームワークに組み込まれた標準のアニメーションなど、Android のデフォルトのリソースを調べるときは、この辺りを見ると便利。</p>

<ul>
<li><a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/frameworks/base/core/res/res/">GrepCode/com.google.android/android/4.2.2_r1/frameworks/base/core/res/res</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android におけるストレージまとめ]]></title>
    <link href="http://blog.lciel.jp/blog/2014/02/08/android-about-storage/"/>
    <updated>2014-02-08T23:29:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2014/02/08/android-about-storage</id>
    <content type="html"><![CDATA[<p>Android で外部ファイルを保存する場合、どこに何を保存すれば良いのか？それぞれの違いは何なのか？<br/>
内蔵メモリなのか？SDカードなのか？</p>

<p>いい加減しっかり把握しておきたいと思ったので、まとめてみました。</p>

<!-- more -->


<h2>ざっくりまとめ</h2>

<p>それぞれの領域の名前は、この記事の中で区別するためにつけたもので、アクセス権減は非 root ユーザから見た図です。</p>

<table>
<thead>
<tr>
<th align="left"></th>
<th align="left">ディレクトリ取得メソッド                   </th>
<th align="left">アプリ専用？</th>
<th align="left">ユーザがアクセス可能？</th>
<th align="left">クリア方法      </th>
<th align="left">アプリ削除時に</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">内部データ領域      </td>
<td align="left">Context.getFilesDir()                      </td>
<td align="left">yes         </td>
<td align="left">no                    </td>
<td align="left">データを消去    </td>
<td align="left">消える        </td>
</tr>
<tr>
<td align="left">内部キャッシュ領域  </td>
<td align="left">Context.getCacheDir()                      </td>
<td align="left">yes         </td>
<td align="left">no                    </td>
<td align="left">キャッシュを消去</td>
<td align="left">消える        </td>
</tr>
<tr>
<td align="left">外部データ領域      </td>
<td align="left">Context.getExternalFilesDir()              </td>
<td align="left">yes         </td>
<td align="left">yes                   </td>
<td align="left">データを消去    </td>
<td align="left">消える        </td>
</tr>
<tr>
<td align="left">外部キャッシュ領域  </td>
<td align="left">Context.getExternalCacheDir()              </td>
<td align="left">yes         </td>
<td align="left">yes                   </td>
<td align="left">キャッシュを消去</td>
<td align="left">消える        </td>
</tr>
<tr>
<td align="left">外部公開領域    </td>
<td align="left">Environment.getExternalStorageDirectory()      </td>
<td align="left">no          </td>
<td align="left">yes                   </td>
<td align="left">提供されず      </td>
<td align="left">消えない      </td>
</tr>
<tr>
<td align="left">外部公開共有領域</td>
<td align="left">Environment.getExternalStoragePublicDirectory()</td>
<td align="left">no          </td>
<td align="left">yes                   </td>
<td align="left">提供されず      </td>
<td align="left">消えない      </td>
</tr>
</tbody>
</table>


<p>　</p>

<ul>
<li>ユーザに見せたくないファイルは内部の領域を使う</li>
<li>消えるとアプリが維持できなくなるようなファイルは、内部データ領域</li>
<li>消えても全く問題ないような一時ファイルは、ユーザが消しやすいキャッシュ領域が良さそう</li>
<li>アプリが消えても消したくないファイルは、外部公開領域にディレクトリ掘って作る</li>
<li>端末全体に共有したいようなファイルは外部公開共有領域に入れる

<ul>
<li>カメラから取得した画像を保存するなら Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) にディレクトリ掘るとか</li>
<li>アプリで生成した画像を保存するなら Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURE) にディレクトリ掘るとか</li>
</ul>
</li>
</ul>


<h2>その他のまめ知識</h2>

<ul>
<li>キャッシュ領域にサイズ制限はないが、ストレージが圧迫されてくるとシステムによって消されることがあるらしい(未実験)

<ul>
<li><a href="http://stackoverflow.com/questions/2175843/limit-size-of-cache-directory">http://stackoverflow.com/questions/2175843/limit-size-of-cache-directory</a></li>
<li>逆に言うと消えることが保証されているわけではないので、容量制限などを行う場合は自分で実装する</li>
<li><a href="http://techbooster.org/android/application/16004/">こちら</a>によると 1MB 以下が推奨とあるが、現在もそうであるか不明。キャッシュ容量二桁MB越えのアプリは珍しくない気がする</li>
</ul>
</li>
<li>マルチアカウント利用されている場合でも、 Context からディレクトリを取得していれば良きに計らってくれるみたい

<ul>
<li><a href="http://techbooster.org/android/application/16004/">http://techbooster.org/android/application/16004/</a></li>
</ul>
</li>
<li>アプリをアンインストール時にも残しておきたいが、ユーザに見られたくない！消されたくない！は「できない」

<ul>
<li>このようなデータは公開領域に置くのが主流っぽいが、隠蔽することはできない</li>
<li>せいぜい見つけづらいところに置くくらいしかできないので、補助的に使うしかない</li>
</ul>
</li>
</ul>


<h2>保存先はSDカード？内蔵ストレージ？</h2>

<p>結論から言うと、 getExternal 系のメソッドでとれるディレクトリは、SDカードの場合もあれば内蔵ストレージの場合もあるようです。<br/>
基本的にアプリ側からSDカードを指定して扱うようなことは <strong>できない</strong> というのが正しそうです。</p>

<p>getExternal〜 でとれるディレクトリはシステムに決められたプライマリストレージであり、それがSDカードである保証はないということ。
よく getExternalStorageDirectory() でSDカード内のディレクトリがとれるという記事を見ますが、正確にはSDカードである可能性が高いディレクトリがとれるというのが正しそうです。</p>

<p>External という名前がついているので紛らわしいですが(というか完全に勘違いする)、これはSDカードのことをさしている訳ではなく、
システム領域の外のストレージという意味で External とついているようです。(<a href="http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory%28%29">参考</a>)</p>

<p>とはいえ getExternal〜 で取得したディレクトリを使う場合は、プライマリストレージがSDカードである可能性を考慮しなくてはいけないため、マウントされているかどうかなどを確かめる必要があります。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">String</span> <span class="n">state</span> <span class="o">=</span> <span class="n">Environment</span><span class="o">.</span><span class="na">getExternalStorageState</span><span class="o">()</span>
</span><span class='line'><span class="k">if</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">Environment</span><span class="o">.</span><span class="na">MEDIA_MOUNTED</span><span class="o">)){</span>
</span><span class='line'>    <span class="c1">// マウントされていて read/write 可能</span>
</span><span class='line'><span class="o">}</span><span class="k">else</span> <span class="k">if</span><span class="o">(</span><span class="n">state</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">Environment</span><span class="o">.</span><span class="na">MEDIA_MOUNTED_READ_ONLY</span><span class="o">)){</span>
</span><span class='line'>    <span class="c1">// マウントされているが read 権限しかない</span>
</span><span class='line'><span class="o">}</span><span class="k">else</span><span class="o">{</span>
</span><span class='line'>    <span class="c1">// マウントされていない</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>今指定されているプライマリストレージが取り外し可能(普通はイコールSDカードになると思います)かどうかは以下を確認することで分かるので、取り外されるとまずい場合などは判別できそうです。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="k">if</span><span class="o">(</span><span class="n">Environment</span><span class="o">.</span><span class="na">isExternalStorageRemovable</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>    <span class="c1">// 取り外し可能</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>ちなみに手持ちの 206SH / Android 4.2.2 で確認してみたところ、Environment のさしているプライマリストレージは内蔵メモリのようでした。<br/>
ついでに 206SH でプライマリストレージを切り替えられるのかどうかを調べてみたけれど、結局切り替わる条件は不明でした。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="err">端末設定</span> <span class="o">&gt;</span> <span class="err">ストレージ</span> <span class="o">&gt;</span> <span class="err">優先インストール先</span>
</span></code></pre></td></tr></table></div></figure>


<p>あたりで切り替えられそうだなーと睨んで色々と試行錯誤してみましたが、プライマリストレージは変わりませんでした。</p>

<h2>(おまけ)各ディレクトリのファイルパスなど</h2>

<p>Nexus7 のほうは getExternal〜 でとれるディレクトリがマルチアカウント対応の Emulated なものになってました。<br/>
4.2 で追加されたマルチアカウントですが、 206SH では封じられているようです。</p>

<figure class='code'><figcaption><span>206SH/Android4.2.2</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># 各種ディレクトリ
</span><span class='line'>Context.getFilesDir()                           :/data/data/com.example/files
</span><span class='line'>Context.getCacheDir()                           :/data/data/com.example/cache
</span><span class='line'>Context.getExternalCacheDir()                   :/storage/sdcard0/Android/data/com.example/cache
</span><span class='line'>Context.getExternalFilesDir()                   :/storage/sdcard0/Android/data/com.example/files
</span><span class='line'>Environment.getExternalStorageDirectory()       :/storage/sdcard0
</span><span class='line'>Environment.getExternalStoragePublicDirectory() :/storage/sdcard0/DCIM
</span><span class='line'>Environment.isExternalStorageEmulated()         :false
</span><span class='line'>Environment.isExternalStorageRemovable()        :false
</span><span class='line'>
</span><span class='line'># マウント状況 - getFilesDir() などでとれるところ
</span><span class='line'>/dev/block/platform/msm_sdcc.1/by-name/userdata /data ext4 rw,nosuid,nodev,noatime,discard,noauto_da_alloc,data=ordered 0 0
</span><span class='line'># マウント状況 - getExternalStorageDirectory() でとれるところ
</span><span class='line'>/dev/fuse /storage/sdcard0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
</span><span class='line'># マウント状況 - 実際のSDカードがマウントされているところ
</span><span class='line'>/dev/block/vold/179:33 /storage/sdcard0/external_sd vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>Nexus7(2013)/Android4.4.2</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># 各種ディレクトリ
</span><span class='line'>Context.getFilesDir()                           :/data/data/com.example/files
</span><span class='line'>Context.getCacheDir()                           :/data/data/com.example/cache
</span><span class='line'>Context.getExternalCacheDir()                   :/storage/emulated/0/Android/data/com.example/cache
</span><span class='line'>Context.getExternalFilesDir()                   :/storage/emulated/0/Android/data/com.example/files
</span><span class='line'>Environment.getExternalStorageDirectory()       :/storage/emulated/0
</span><span class='line'>Environment.getExternalStoragePublicDirectory() :/storage/emulated/0/DCIM
</span><span class='line'>Environment.isExternalStorageEmulated()         :true
</span><span class='line'>Environment.isExternalStorageRemovable()        :false
</span><span class='line'>
</span><span class='line'># マウント状況 - getFilesDir() などでとれるところ
</span><span class='line'>/dev/block/platform/msm_sdcc.1/by-name/userdata /data ext4 rw,seclabel,nosuid,nodev,noatime,nomblk_io_submit,errors=panic,data=ordered 0 0
</span><span class='line'># マウント状況 - getExternalStorageDirectory() でとれるところの実体？
</span><span class='line'>/dev/fuse /mnt/shell/emulated fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
</span><span class='line'>
</span><span class='line'># /storage/emulated に置いてあるシンボリックリンク
</span><span class='line'>shell@flo:/ $ ls -la /storage/emulated/
</span><span class='line'>lrwxrwxrwx root     root              2014-01-30 19:47 legacy -&gt; /mnt/shell/emulated/0
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[View のキャプチャを撮る]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/16/android-capture-view-image/"/>
    <updated>2013-12-16T20:52:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/16/android-capture-view-image</id>
    <content type="html"><![CDATA[<p>Android で View のキャプチャ画像を取得する方法を二種類紹介します。</p>

<p>どちらも UI スレッド以外のスレッドから呼び出し可能でした。</p>

<h2>View の描画キャッシュを使用する方法</h2>

<p>View の描画のためのキャッシュを利用する方法。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">View</span> <span class="n">view</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">view</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">view</span><span class="o">.</span><span class="na">setDrawingCacheEnabled</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>      <span class="c1">// キャッシュを取得する設定にする</span>
</span><span class='line'><span class="n">view</span><span class="o">.</span><span class="na">destroyDrawingCache</span><span class="o">();</span>             <span class="c1">// 既存のキャッシュをクリアする</span>
</span><span class='line'>
</span><span class='line'><span class="n">Bitmap</span> <span class="n">bmp</span> <span class="o">=</span> <span class="n">view</span><span class="o">.</span><span class="na">getDrawingCache</span><span class="o">();</span>    <span class="c1">// キャッシュを作成して取得する</span>
</span></code></pre></td></tr></table></div></figure>


<p>描画キャッシュが有効になっているかどうかや、最新のキャッシュが存在するかどうかは状況によるので、自分で設定してやることで View のキャプチャを取得することができます。</p>

<h2>Canvas に View を描画する方法</h2>

<p>自分で用意した Canvas に View を描画する方法。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">View</span> <span class="n">view</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">view</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">Bitmap</span> <span class="n">bmp</span> <span class="o">=</span> <span class="n">Bitmap</span><span class="o">.</span><span class="na">createBitmap</span><span class="o">(</span><span class="n">view</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">view</span><span class="o">.</span><span class="na">getHeight</span><span class="o">(),</span> <span class="n">Config</span><span class="o">.</span><span class="na">ARGB_8888</span><span class="o">);</span>
</span><span class='line'>                                        <span class="c1">// view のサイズで Bitmap を作成</span>
</span><span class='line'><span class="n">Canvas</span> <span class="n">canvas</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Canvas</span><span class="o">(</span><span class="n">bmp</span><span class="o">);</span>        <span class="c1">// bmp をターゲットにした Canvas を作成</span>
</span><span class='line'>
</span><span class='line'><span class="n">view</span><span class="o">.</span><span class="na">draw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>                      <span class="c1">// canvas に view を描画する</span>
</span></code></pre></td></tr></table></div></figure>


<p>View のサイズで作った Bitmap を Canvas の書き込み先にし、draw() メソッドで書き込んでやることで、 View が描画された Bitmap を取得することができます。</p>

<h2>[おまけ] getDrawingCache() まわりの豆知識</h2>

<p>今までなんとなく使っていたけれど、View のキャプチャに buildDrawingCache() を必ず呼ぶようにしているスニペットがあったり、 getDrawingCache() で null が返ってくることがあったりと挙動を不審に思っていたので軽く調査(Android 4.2.2)。</p>

<ul>
<li>直前に setDrawingCacheEnabled(true) さえすれば、 getDrawingCache() の前に自分で buildDrawingCache() を呼ぶ必要はない

<ul>
<li>View のフラグに PFLAG_DRAWING_CACHE_ENABLED が立っていれば getDrawingCache() で buildDrawingCache() を呼んでいる</li>
</ul>
</li>
<li>キャッシュを確実に更新したい場合は View を invalidate() するか destroyDrawingCache() でキャッシュをクリアする

<ul>
<li>フラグに PFLAG_DRAWING_CACHE_VALID が立っている、かつ DrawingCache が確保されていると buildDrawingCache() が呼ばれてもキャッシュが更新されない</li>
<li>invalidate() するだけだと Bitmap が recycle() されなそうなので、連打するとメモリ不足に陥るかも</li>
</ul>
</li>
<li>setDrawingCacheEnabled() するだけでは destroyDrawingCache() が呼ばれないことがある

<ul>
<li>フラグが &ldquo;変わった&rdquo; ときだけ destroyDrawingCache() が呼ばれるようなので、オーバーヘッドも少ないし自分で destroyDrawingCache() を呼んだ方が無難そう</li>
</ul>
</li>
<li>そもそも何に使われている &ldquo;キャッシュ&rdquo; なのか？

<ul>
<li>draw() 時に caching の条件を満たしていれば、 canvas に直接 drawBitmap() するために使われているので、まさに描画キャッシュのように見える</li>
<li>条件については今回は追いきれず(LayerType や HardwareAccelerated など Android の描画周りの知識が足りなすぎた..)</li>
<li>ご存知の方がいたら教えて下さい！</li>
</ul>
</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android Library Project と JAR の違いを理解する]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/13/difference-between-jar-and-library-project/"/>
    <updated>2013-12-13T19:57:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/13/difference-between-jar-and-library-project</id>
    <content type="html"><![CDATA[<p>Android でライブラリを使用する際、プロジェクトを作成する必要のあるライブラリプロジェクトと、クラスライブラリの JAR と2種類存在するけれど、それぞれどう違うのか軽く調べました。</p>

<h2>ライブラリプロジェクトと JAR の違い</h2>

<p>最も根本的な違いは Resources を内包しているかどうかのようです。<br/>
ライブラリプロジェクトは Resources を保持できるので、 JAR のように静的に APK に組み込むことができません。
そのためプロジェクトとして作成した上で、組み込みたいプロジェクトに依存させて、ビルド時に R.java を一緒に作成する必要があります。</p>

<ul>
<li>参考: <a href="http://www.growprogress.com/vcommon/?p=3059">Android Application, Android Libraries and Jar Libraries</a></li>
</ul>


<h2>Android APK のビルドの流れを軽く理解する</h2>

<p>完全に上記参考サイトの受け売りですが、Android APK のビルドの流れも要点だけ追っておきます。
(これを以前追っておいたおかげで、 Gradle のビルドで詰まったときなどにとても役立ちました)</p>

<p>もっと詳しく理解する場合は、リンク先をご確認下さい。</p>

<h3>Android APK のビルド</h3>

<ul>
<li>リソースと ID の対応づけを持った R.java を作る</li>
<li>.java を .class にコンパイル</li>
<li>.class(bin/classes) をまとめて Dalvik ByteCode である .dex にコンパイル</li>
<li>.dex を APK に追加する</li>
</ul>


<h3>JAR を含んだ Android APK のビルド</h3>

<ul>
<li>Android APK のビルドにおいて、 .dex を作るときに JAR Library(実体は.class) を .dex に一緒にまとめてコンパイルするだけ</li>
</ul>


<h3>Android Library を含めた Android APK のビルド</h3>

<ul>
<li>依存関係を計算</li>
<li>R.java を作る

<ul>
<li><strong>Library Project の AndroidManifest.xml は無視される</strong></li>
</ul>
</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>aapt package –f –m –auto-add-overlay
</span><span class='line'>    –M /absolute/path/to/app/AndroidManifest.xml
</span><span class='line'>    –S /absolute/path/to/app/res
</span><span class='line'>    -S /absolute/path/to/library-project/res
</span><span class='line'>    -I /absolute/path/to/android.jar
</span><span class='line'>    -J /absolute/path/to/app/gen</span></code></pre></td></tr></table></div></figure>


<ul>
<li>Android Library を含めた .java を .class にコンパイル</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>javac &lt;other options&gt; –sourcepath
</span><span class='line'>    /absolute/path/to/app/src;/absolute/path/to/app/gen/;absolute/path/to/library-project/src</span></code></pre></td></tr></table></div></figure>


<ul>
<li>.class を .dex にコンパイル</li>
<li>resources を Library Project の分もまとめてマージしてパッケージ</li>
<li>マージされた resources と、マージされた .dex を .apk に追加する</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android のタッチイベントを理解する(その2)]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/12/android-touch-event-2/"/>
    <updated>2013-12-12T21:32:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/12/android-touch-event-2</id>
    <content type="html"><![CDATA[<h2>Activity にタッチイベントが流れてくるまで</h2>

<p><a href="http://blog.lciel.jp/blog/2013/12/03/android-touch-event/">前回</a>は View のヒエラルキーのなかをどうやってタッチイベントが伝搬するかを追いました。<br/>
参考にした資料には、 Activity#dispatchTouchEvent() からイベントが始まるとありますが、折角なのでそこまではどうなっているかも確認します。</p>

<p>先に概要としてまとめてしまうとこんな雰囲気でした。</p>

<p><img src="http://blog.lciel.jp/images/android-touch-event-flow.png" alt="Activity に渡るまでのタッチイベント概要" /></p>

<p>View システムの根っこの部分をきちんと理解できてないので、勘違いがあるかもしれません。
(親子関係が特に怪しい)</p>

<!-- more -->


<h3>参考にしたスタックトレース</h3>

<p>206SH(Android 4.2.2) でとったものなので、完全に純正なコードでない可能性もありますが参考にしつつ追っていきます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>12-02 22:58:25.726: D/TOUCH_TEST(27219):
</span><span class='line'>    at onTouch(TouchTest.java:35)
</span><span class='line'>    at dispatchTouchEvent(View.java:7319)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at dispatchTransformedTouchEvent(ViewGroup.java:2205)
</span><span class='line'>    at dispatchTouchEvent(ViewGroup.java:1948)
</span><span class='line'>    at superDispatchTouchEvent(PhoneWindow.java:1974)
</span><span class='line'>    at superDispatchTouchEvent(PhoneWindow.java:1426)
</span><span class='line'>    at dispatchTouchEvent(Activity.java:2417)
</span><span class='line'>    at dispatchTouchEvent(PhoneWindow.java:1922)
</span><span class='line'>    at dispatchPointerEvent(View.java:7504)
</span><span class='line'>    at deliverPointerEvent(ViewRootImpl.java:3356)
</span><span class='line'>    at deliverInputEvent(ViewRootImpl.java:3301)
</span><span class='line'>    at doProcessInputEvents(ViewRootImpl.java:4436)
</span><span class='line'>    at enqueueInputEvent(ViewRootImpl.java:4415)
</span><span class='line'>    at onInputEvent(ViewRootImpl.java:4507)
</span><span class='line'>    at dispatchInputEvent(InputEventReceiver.java:179)
</span><span class='line'>    at nativePollOnce(MessageQueue.java:-2)
</span><span class='line'>    at next(MessageQueue.java:125)
</span><span class='line'>    at loop(Looper.java:124)
</span><span class='line'>    /**
</span><span class='line'>     * ↑ActivityThread の Looper にイベントが登録されてくるようなので、ここからみていく
</span><span class='line'>     * ----
</span><span class='line'>     * ↓ここまでは Activity が Zygote によって立ち上げられている関係上、スタックトレースにのってきているっぽい
</span><span class='line'>     */
</span><span class='line'>    at main(ActivityThread.java:5159)
</span><span class='line'>    at invokeNative(Method.java:-2)
</span><span class='line'>    at invoke(Method.java:511)
</span><span class='line'>    at run(ZygoteInit.java:810)
</span><span class='line'>    at main(ZygoteInit.java:577)
</span><span class='line'>    at main(NativeStart.java:-2)
</span></code></pre></td></tr></table></div></figure>


<h3>Activity 配下の View へとタッチイベントがわたるまで</h3>

<p>このあたりのメソッドの引き回し方は、マイナバージョンの変更でもちょこちょこ変わっているようで、たとえば 4.2.2 と 4.3 でも違いがありました。<br/>
大枠の流れまでは変わっていなそうでしたので、スタックトレースと比較するために 4.2.2 でコードを追っています。</p>

<ul>
<li>どこかの誰かが ActivityThread の Looper にイベントを登録してくる(どこの誰かは今のところ追えてません)</li>
<li>ActivityThread の Looper がメッセージを dispatch していくなかで、入力イベントを ViewRootImpl の onInputEvent() に渡す</li>
<li>ViewRootImpl にて、入力イベントのキューを順に処理していく</li>
</ul>


<figure class='code'><figcaption><span>ViewRootImpl#deliverInputEvent()</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kt">void</span> <span class="nf">deliverInputEvent</span><span class="o">(</span><span class="n">QueuedInputEvent</span> <span class="n">q</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="n">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_VIEW</span><span class="o">,</span> <span class="s">&quot;deliverInputEvent&quot;</span><span class="o">);</span>
</span><span class='line'>    <span class="k">try</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">q</span><span class="o">.</span><span class="na">mEvent</span> <span class="k">instanceof</span> <span class="n">KeyEvent</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">deliverKeyEvent</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">source</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="na">mEvent</span><span class="o">.</span><span class="na">getSource</span><span class="o">();</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">((</span><span class="n">source</span> <span class="o">&amp;</span> <span class="n">InputDevice</span><span class="o">.</span><span class="na">SOURCE_CLASS_POINTER</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="c1">// タッチイベントは SOURCE_CLASS_POINTER に分類されるため、 deliverPointerEvent() が呼ばれる</span>
</span><span class='line'>                <span class="c1">// ここに分類されるのはマウス、ペン、タッチ、トラックボールなどらしい</span>
</span><span class='line'>                <span class="n">deliverPointerEvent</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">((</span><span class="n">source</span> <span class="o">&amp;</span> <span class="n">InputDevice</span><span class="o">.</span><span class="na">SOURCE_CLASS_TRACKBALL</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">deliverTrackballEvent</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">deliverGenericMotionEvent</span><span class="o">(</span><span class="n">q</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="n">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_VIEW</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<ul>
<li>キューからイベントを抽出して、 DecorView にポインタイベントとして流す</li>
</ul>


<figure class='code'><figcaption><span>ViewRootImpl#deliverPointerEvent()</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kt">void</span> <span class="nf">deliverPointerEvent</span><span class="o">(</span><span class="n">QueuedInputEvent</span> <span class="n">q</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">final</span> <span class="n">MotionEvent</span> <span class="n">event</span> <span class="o">=</span> <span class="o">(</span><span class="n">MotionEvent</span><span class="o">)</span><span class="n">q</span><span class="o">.</span><span class="na">mEvent</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 中略</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// タッチイベントを View ヒエラルキーに流していく</span>
</span><span class='line'>    <span class="c1">// 通常、 mView には Activity のルートビューとなる DecorView が入っているはず</span>
</span><span class='line'>    <span class="kt">boolean</span> <span class="n">handled</span> <span class="o">=</span> <span class="n">mView</span><span class="o">.</span><span class="na">dispatchPointerEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">MEASURE_LATENCY</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">lt</span><span class="o">.</span><span class="na">sample</span><span class="o">(</span><span class="s">&quot;B Dispatched PointerEvents &quot;</span><span class="o">,</span> <span class="n">System</span><span class="o">.</span><span class="na">nanoTime</span><span class="o">()</span> <span class="o">-</span> <span class="n">event</span><span class="o">.</span><span class="na">getEventTimeNano</span><span class="o">());</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// タッチイベントの処理が返ってきたら、イベントキューを完了させる</span>
</span><span class='line'>    <span class="c1">// handled で分岐しているが native method に入ってしまうので、今回は追ってません</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">handled</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">finishInputEvent</span><span class="o">(</span><span class="n">q</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
</span><span class='line'>        <span class="k">return</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// Pointer event was unhandled.</span>
</span><span class='line'>    <span class="n">finishInputEvent</span><span class="o">(</span><span class="n">q</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<ul>
<li>DecorView の親クラス(View)でタッチイベントと判定して dispatch する</li>
</ul>


<figure class='code'><figcaption><span>View#dispatchPointerEvent()</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="nf">dispatchPointerEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">isTouchEvent</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// 今回はタッチイベントなのでこちら</span>
</span><span class='line'>        <span class="k">return</span> <span class="nf">dispatchTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="nf">dispatchGenericMotionEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<ul>
<li>DecorView にて Callback として登録されている Activity に、一旦イベントを流す</li>
</ul>


<figure class='code'><figcaption><span>PhoneWindow.DecorView#dispatchTouchEvent()</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">boolean</span> <span class="n">More</span> <span class="nf">dispatchTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">ev</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="c1">// callback には通常 Activity が登録されている</span>
</span><span class='line'>    <span class="kd">final</span> <span class="n">Callback</span> <span class="n">cb</span> <span class="o">=</span> <span class="n">getCallback</span><span class="o">();</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">cb</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">isDestroyed</span><span class="o">()</span> <span class="o">&amp;&amp;</span> <span class="n">mFeatureId</span> <span class="o">&lt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">cb</span><span class="o">.</span><span class="na">dispatchTouchEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">)</span>
</span><span class='line'>            <span class="o">:</span> <span class="kd">super</span><span class="o">.</span><span class="na">dispatchTouchEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<ul>
<li>Activity にてユーザからの入力があったことを表す <a href="http://developer.android.com/reference/android/app/Activity.html#onUserInteraction%28%29">onUserInteraction()</a> などを呼びながら、再度 DecorView にイベントを dispatch し、子供の View (Activity#addContentView()したViewたち)へとタッチイベントを流していく</li>
</ul>


<figure class='code'><figcaption><span>Activity#dispatchTouchEvent()</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">dispatchTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">ev</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="c1">// キータッチの開始なら onUserInteraction() が呼ばれる</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">ev</span><span class="o">.</span><span class="na">getAction</span><span class="o">()</span> <span class="o">==</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_DOWN</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">onUserInteraction</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="c1">// ここで一旦 DecorView(FrameLayoutを継承) にイベントを戻し、ここから ViewGroup の dispatchTouchEvent() が呼ばれて、タッチイベントの旅が始まる</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">getWindow</span><span class="o">().</span><span class="na">superDispatchTouchEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">))</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="c1">// イベントがキャンセルされずにココまで到達したら、最後に Activity のタッチイベントが呼ばれる</span>
</span><span class='line'>    <span class="k">return</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">ev</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android のアニメーションを自作する]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/11/android-custom-animation/"/>
    <updated>2013-12-11T20:15:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/11/android-custom-animation</id>
    <content type="html"><![CDATA[<p>Android で独自定義のカスタムアニメーションを作りたかったので試してみたところ、 Animation クラスを継承して割と簡単に作れたのでメモ。</p>

<p>ここでは例として、 View を円周に沿って動かすようなアニメーションを作ってみました。<br/>
アニメーションさせたい View に対して中心点を指定して、開始角度と終了角度を与えてアニメーションさせてみます。</p>

<p><img src="http://blog.lciel.jp/images/android-arc-translate-animation.png" alt="android-arc-translate-animation.png" /></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * 円弧上に沿うように移動させるアニメーション</span>
</span><span class='line'><span class="cm"> * @param startDegrees  開始角度</span>
</span><span class='line'><span class="cm"> * @param endDegrees    終了角度</span>
</span><span class='line'><span class="cm"> * @param centerXType   中心点のX座標のタイプ</span>
</span><span class='line'><span class="cm"> * @param centerXValue  中心点のX座標を表す値</span>
</span><span class='line'><span class="cm"> * @param centerYType   中心点のY座標のタイプ</span>
</span><span class='line'><span class="cm"> * @param centerYValue  中心点のY座標を表す値</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="kd">public</span> <span class="nf">ArcTranslateAnimation</span><span class="o">(</span><span class="kt">int</span> <span class="n">startDegrees</span><span class="o">,</span> <span class="kt">int</span> <span class="n">endDegrees</span><span class="o">,</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">centerXType</span><span class="o">,</span> <span class="kt">float</span> <span class="n">centerXValue</span><span class="o">,</span> <span class="kt">int</span> <span class="n">centerYType</span><span class="o">,</span> <span class="kt">float</span> <span class="n">centerYValue</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>




<!-- more -->


<h2>コンストラクタ</h2>

<p>今回はパラメータを受け取るだけ。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="nf">ArcTranslateAnimation</span><span class="o">(</span><span class="kt">int</span> <span class="n">startDegrees</span><span class="o">,</span> <span class="kt">int</span> <span class="n">endDegrees</span><span class="o">,</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">centerXType</span><span class="o">,</span> <span class="kt">float</span> <span class="n">centerXValue</span><span class="o">,</span> <span class="kt">int</span> <span class="n">centerYType</span><span class="o">,</span> <span class="kt">float</span> <span class="n">centerYValue</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mStartRad</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)(</span><span class="n">startDegrees</span> <span class="o">*</span> <span class="n">Math</span><span class="o">.</span><span class="na">PI</span> <span class="o">/</span> <span class="mf">180.0f</span><span class="o">);</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mEndRad</span>   <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)(</span><span class="n">endDegrees</span>   <span class="o">*</span> <span class="n">Math</span><span class="o">.</span><span class="na">PI</span> <span class="o">/</span> <span class="mf">180.0f</span><span class="o">);</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mCenterXType</span>  <span class="o">=</span> <span class="n">centerXType</span><span class="o">;</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mCenterXValue</span> <span class="o">=</span> <span class="n">centerXValue</span><span class="o">;</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mCenterYType</span>  <span class="o">=</span> <span class="n">centerYType</span><span class="o">;</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mCenterYValue</span> <span class="o">=</span> <span class="n">centerYValue</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>initialize()</h2>

<p>まず initialize() で View の座標やサイズなどの情報を取得します。</p>

<p>他のアニメーションに倣い、回転の中心点を指定するときに絶対的(Animation.ABSOLUTE)か相対的(Animation.RELATIVE_TO_SELF)か、親基準で相対的(Animation.RELATIVE_TO_PARENT)かを選べるようにしてみましたが、このあたりは resolveSize() メソッドを使うことで容易に座標に変換できます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">initialize</span><span class="o">(</span><span class="kt">int</span> <span class="n">width</span><span class="o">,</span> <span class="kt">int</span> <span class="n">height</span><span class="o">,</span> <span class="kt">int</span> <span class="n">parentWidth</span><span class="o">,</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">parentHeight</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">super</span><span class="o">.</span><span class="na">initialize</span><span class="o">(</span><span class="n">width</span><span class="o">,</span> <span class="n">height</span><span class="o">,</span> <span class="n">parentWidth</span><span class="o">,</span> <span class="n">parentHeight</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="kt">float</span> <span class="n">fromX</span>   <span class="o">=</span> <span class="n">resolveSize</span><span class="o">(</span><span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">width</span><span class="o">,</span> <span class="n">parentWidth</span><span class="o">);</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">fromY</span>   <span class="o">=</span> <span class="n">resolveSize</span><span class="o">(</span><span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">height</span><span class="o">,</span> <span class="n">parentHeight</span><span class="o">);</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">centerX</span> <span class="o">=</span> <span class="n">resolveSize</span><span class="o">(</span><span class="n">mCenterXType</span><span class="o">,</span> <span class="n">mCenterXValue</span><span class="o">,</span> <span class="n">width</span><span class="o">,</span> <span class="n">parentWidth</span><span class="o">);</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">centerY</span> <span class="o">=</span> <span class="n">resolveSize</span><span class="o">(</span><span class="n">mCenterYType</span><span class="o">,</span> <span class="n">mCenterYValue</span><span class="o">,</span> <span class="n">height</span><span class="o">,</span> <span class="n">parentHeight</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">mDeltaRad</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span><span class="n">Math</span><span class="o">.</span><span class="na">atan2</span><span class="o">(</span><span class="n">fromY</span> <span class="o">-</span> <span class="n">centerY</span><span class="o">,</span> <span class="n">fromX</span> <span class="o">-</span> <span class="n">centerX</span><span class="o">);</span>
</span><span class='line'>    <span class="n">mRadius</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span><span class="n">Math</span><span class="o">.</span><span class="na">sqrt</span><span class="o">(</span><span class="n">Math</span><span class="o">.</span><span class="na">pow</span><span class="o">(</span><span class="n">fromX</span> <span class="o">-</span> <span class="n">centerX</span><span class="o">,</span> <span class="mi">2</span><span class="o">)</span> <span class="o">+</span> <span class="n">Math</span><span class="o">.</span><span class="na">pow</span><span class="o">(</span><span class="n">fromY</span> <span class="o">-</span> <span class="n">centerY</span><span class="o">,</span> <span class="mi">2</span><span class="o">));</span>
</span><span class='line'>    <span class="n">mStartPoint</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Point</span><span class="o">((</span><span class="kt">int</span><span class="o">)(</span><span class="n">fromX</span> <span class="o">-</span> <span class="n">centerX</span><span class="o">),</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">fromY</span> <span class="o">-</span> <span class="n">centerY</span><span class="o">));</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>中心点の座標がとれたので、開始地点と中心点における初期角度、円の半径、開始点などを保存しておきます。</p>

<h2>applyTransformation()</h2>

<p>applyTransformation() がアニメーションのキモで、引数として渡される interpolatedTime パラメータに 0.0f – 1.0f でアニメーションの進行値が入ってくるので、その値に合わせて表示を変更してやります。 ちなみに interpolatedTime は Interpolator が適用された値が設定されているようなので、与えられた値をそのまま進行の割合として信じれば良さそうです。</p>

<p>表示を変更するには、同じく引数として渡される t パラメータに対して操作を行えば OK です。 位置やサイズを変更するなら getMatrix() で参照できる Matrix インスタンスを操作し、アルファ値を変更するなら setAlpha() でアルファ値を設定します。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="n">PointF</span> <span class="nf">getArcPoint</span><span class="o">(</span><span class="kt">float</span> <span class="n">interpolatedTime</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">rad</span> <span class="o">=</span> <span class="n">mStartRad</span> <span class="o">+</span> <span class="o">(</span><span class="n">mEndRad</span> <span class="o">-</span> <span class="n">mStartRad</span><span class="o">)</span> <span class="o">*</span> <span class="n">interpolatedTime</span> <span class="o">+</span> <span class="n">mDeltaRad</span><span class="o">;</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">dx</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)(</span><span class="n">Math</span><span class="o">.</span><span class="na">cos</span><span class="o">(</span><span class="n">rad</span><span class="o">)</span> <span class="o">*</span> <span class="n">mRadius</span><span class="o">);</span>
</span><span class='line'>    <span class="kt">float</span> <span class="n">dy</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)(</span><span class="n">Math</span><span class="o">.</span><span class="na">sin</span><span class="o">(</span><span class="n">rad</span><span class="o">)</span> <span class="o">*</span> <span class="n">mRadius</span><span class="o">);</span>
</span><span class='line'>    <span class="k">return</span> <span class="k">new</span> <span class="nf">PointF</span><span class="o">(</span><span class="n">dx</span> <span class="o">-</span> <span class="n">mStartPoint</span><span class="o">.</span><span class="na">x</span><span class="o">,</span> <span class="n">dy</span> <span class="o">-</span> <span class="n">mStartPoint</span><span class="o">.</span><span class="na">y</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">protected</span> <span class="kt">void</span> <span class="nf">applyTransformation</span><span class="o">(</span><span class="kt">float</span> <span class="n">interpolatedTime</span><span class="o">,</span> <span class="n">Transformation</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">PointF</span> <span class="n">p</span> <span class="o">=</span> <span class="n">getArcPoint</span><span class="o">(</span><span class="n">interpolatedTime</span><span class="o">);</span>
</span><span class='line'>    <span class="n">t</span><span class="o">.</span><span class="na">getMatrix</span><span class="o">().</span><span class="na">postTranslate</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">x</span><span class="o">,</span> <span class="n">p</span><span class="o">.</span><span class="na">y</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>今回は Translate アニメーションなので、 getArcPoint() で座標を決定したら Matrix#postTranslate() で位置を移動してやります。</p>

<h2>カスタムアニメーションを使用する</h2>

<p>これで普通の Animation と同じように使うことができます。</p>

<figure class='code'><figcaption><span>使用例</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">View</span> <span class="n">target</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">targetView</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">Animation</span> <span class="n">anim1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArcTranslateAnimation</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">90</span><span class="o">,</span> <span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="o">-</span><span class="mi">300</span><span class="o">,</span> <span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
</span><span class='line'><span class="n">anim1</span><span class="o">.</span><span class="na">setDuration</span><span class="o">(</span><span class="mi">1000</span><span class="o">);</span>
</span><span class='line'><span class="n">anim1</span><span class="o">.</span><span class="na">setFillEnabled</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
</span><span class='line'><span class="n">anim1</span><span class="o">.</span><span class="na">setFillAfter</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
</span><span class='line'><span class="n">target</span><span class="o">.</span><span class="na">startAnimation</span><span class="o">(</span><span class="n">anim1</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">Animation</span> <span class="n">anim2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArcTranslateAnimation</span><span class="o">(</span><span class="mi">90</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="o">-</span><span class="mi">300</span><span class="o">,</span> <span class="n">Animation</span><span class="o">.</span><span class="na">ABSOLUTE</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
</span><span class='line'><span class="n">anim2</span><span class="o">.</span><span class="na">setStartOffset</span><span class="o">(</span><span class="mi">1000</span><span class="o">);</span>
</span><span class='line'><span class="n">anim2</span><span class="o">.</span><span class="na">setDuration</span><span class="o">(</span><span class="mi">1000</span><span class="o">);</span>
</span><span class='line'><span class="n">anim2</span><span class="o">.</span><span class="na">setFillEnabled</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
</span><span class='line'><span class="n">anim2</span><span class="o">.</span><span class="na">setFillAfter</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
</span><span class='line'><span class="n">target</span><span class="o">.</span><span class="na">startAnimation</span><span class="o">(</span><span class="n">anim2</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>もちろん AnimationSet で使うこともできます。</p>

<h2>ArcTranslateAnimation クラス全容</h2>

<p>最後に今回作成した ArcTranslateAnimation クラスを置いておきます。</p>

<div><script src='https://gist.github.com/9435696.js'></script>
<noscript><pre><code>import android.graphics.Point;
import android.graphics.PointF;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class ArcTranslateAnimation extends Animation {

    private int mCenterXType;
    private int mCenterYType;
    private float mCenterXValue;
    private float mCenterYValue;

    private float mRadius;
    private Point mStartPoint;

    private float mDeltaRad;
    private float mStartRad;
    private float mEndRad;

    /**
     * 円弧上に沿うように移動させるアニメーション
     * @param startDegrees  開始角度
     * @param endDegrees    終了角度
     * @param centerXType   中心点のX座標のタイプ
     * @param centerXValue  中心点のX座標を表す値
     * @param centerYType   中心点のY座標のタイプ
     * @param centerYValue  中心点のY座標を表す値
     */
    public ArcTranslateAnimation(int startDegrees, int endDegrees,
            int centerXType, float centerXValue, int centerYType, float centerYValue) {
        this.mStartRad = (float)(startDegrees * Math.PI / 180.0f);
        this.mEndRad   = (float)(endDegrees   * Math.PI / 180.0f);
        this.mCenterXType  = centerXType;
        this.mCenterXValue = centerXValue;
        this.mCenterYType  = centerYType;
        this.mCenterYValue = centerYValue;
    }

    /**
     * 現在の座標を取得する
     * @param interpolatedTime
     * @return
     */
    private PointF getArcPoint(float interpolatedTime) {
        float rad = mStartRad + (mEndRad - mStartRad) * interpolatedTime + mDeltaRad;
        float dx = (float)(Math.cos(rad) * mRadius);
        float dy = (float)(Math.sin(rad) * mRadius);
        return new PointF(dx - mStartPoint.x, dy - mStartPoint.y);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        PointF p = getArcPoint(interpolatedTime);
        t.getMatrix().postTranslate(p.x, p.y);
    }

    @Override
    public void initialize(int width, int height, int parentWidth,
            int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);

        float fromX   = resolveSize(Animation.ABSOLUTE, 0, width, parentWidth);
        float fromY   = resolveSize(Animation.ABSOLUTE, 0, height, parentHeight);
        float centerX = resolveSize(mCenterXType, mCenterXValue, width, parentWidth);
        float centerY = resolveSize(mCenterYType, mCenterYValue, height, parentHeight);

        mDeltaRad = (float)Math.atan2(fromY - centerY, fromX - centerX);
        mRadius = (float)Math.sqrt(Math.pow(fromX - centerX, 2) + Math.pow(fromY - centerY, 2));
        mStartPoint = new Point((int)(fromX - centerX), (int)(fromY - centerY));
    }
}</code></pre></noscript></div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ファイル名に特定の記号が使用できる場合とできない場合がある]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/06/android-sdcard-vfat/"/>
    <updated>2013-12-06T21:11:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/06/android-sdcard-vfat</id>
    <content type="html"><![CDATA[<p>Android のバージョンは同じなのに、端末によってファイルの移動(renameTo())に失敗してしまうことがあって悩まされたが、オチは移動先のファイル名にクエスチョンマーク(&ldquo;?&rdquo;)が含まれていたことが原因だった。</p>

<p>クエスチョンマークが入ってしまっていたこと自体がバグだったのだけれど、そもそも何で端末によってこのようなことが起きるのかを軽く追ってみた。</p>

<h3>原因はファイルシステム(っぽい)</h3>

<p>成功する端末では内部ストレージに書き込みを行っており、失敗する端末では外部ストレージに書き込みを行っていた。</p>

<p>ファイルシステムを見てみると、内部ストレージは FUSE でマウントされているのに対し、外部ストレージは VFAT でマウントされていた。</p>

<figure class='code'><figcaption><span>mount の状態</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'># 内部ストレージとして認識されているディレクトリ
</span><span class='line'>/dev/fuse /storage/sdcard0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
</span><span class='line'>
</span><span class='line'># 外部ストレージとして認識されているディレクトリ
</span><span class='line'>/dev/block/vold/179:33 /storage/sdcard0/external_sd vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
</span></code></pre></td></tr></table></div></figure>


<p>正式な出典が見つからなかったけれど、 VFAT ではファイル名に以下の文字の使用を禁止しているようなので、恐らくこれが原因っぽい。<br/>
試しにその他の記号を含めたファイル名を作成してみたところ、全て失敗した。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>\ : * ? &lt; &gt; | / ;
</span></code></pre></td></tr></table></div></figure>


<p>参考 : <a href="http://www2s.biglobe.ne.jp/~system/doc/winfile2.htm">ファイル名とフォルダ名で使用できない文字</a></p>

<p>というわけで、環境によって(サンプル数は少ないが、恐らく外部SDカードでは)一部の記号がファイル名に使えなくなることがある、ということが分かった。</p>

<h3>メモ</h3>

<p>Android のファイルシステム周りについては全く調べられていないが、いくつか気になることがあったのでメモ。</p>

<ul>
<li>エミュレータでは FUSE ではなく YAFFS2 でマウントされていた(どこのレイヤーで変わってるのか不明)</li>
<li><a href="http://source.android.com/devices/tech/storage/">ここ</a>を見ると、 Android 4.4 からは外部ストレージも FUSE 経由でマウントするようになるっぽい？が、4.4 のエミュレータが起動せず、実機も外部メモリがマウントできない端末しかなく確認できず (raw storage をラップしているとあるので、今回の件は実体の方でこけそう)</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ListView#setEmptyView() について]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/04/listview-setemptyview/"/>
    <updated>2013-12-04T21:10:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/04/listview-setemptyview</id>
    <content type="html"><![CDATA[<p>ListView の要素が無い場合に表示する View を指定できる setEmptyView() だが、その名前から想像できるのとは少し違う動きをする。</p>

<ul>
<li>違 : 「要素が無い場合に ListView の子供として表示させる View が設定できる」</li>
<li>正 : 「要素が無い場合に ListView の代わりに表示する View が設定できる」</li>
</ul>


<p>実際の動作は setEmptyView() で指定した View と ListView の Visibility を View.GONE と View.VISIBLE で入れ替えるだけとなっている。</p>

<p>そのため、 inflate() しただけでどこにも addView() していない View などを setEmptyView() で指定しても表示されないし、 ListView の子として表示される Header や Footer も表示されないこととなる。</p>

<p>通常は ListView と同階層に兄弟 View として xml に定義しておくのがよさそう。<br/>
EmptyView として設定する View の Visibility は特に指定しなくても ListView 側でやってくれるので問題ないです。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;ListView</span>
</span><span class='line'>    <span class="na">android:id=</span><span class="s">&quot;@+id/listView&quot;</span>
</span><span class='line'>    <span class="err">...</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;View</span>
</span><span class='line'>    <span class="na">android:id=</span><span class="s">&quot;@+id/emptyView&quot;</span>
</span><span class='line'>    <span class="err">...</span> <span class="nt">/&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">ListView</span> <span class="n">listView</span> <span class="o">=</span> <span class="o">(</span><span class="n">ListView</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">listView</span><span class="o">);</span>
</span><span class='line'><span class="n">listView</span><span class="o">.</span><span class="na">setEmptyView</span><span class="o">(</span><span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">emptyView</span><span class="o">));</span>
</span></code></pre></td></tr></table></div></figure>


<p>以下は実装箇所の確認。</p>

<figure class='code'><figcaption><span>android.widget.AdapterView(1.6_r2)</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kt">void</span> <span class="n">More</span> <span class="o">...</span><span class="na">updateEmptyStatus</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">empty</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">isInFilterMode</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">empty</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">empty</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// EmptyView が設定されていた場合は自身を消して、 EmptyView を表示させている</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mEmptyView</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mEmptyView</span><span class="o">.</span><span class="na">setVisibility</span><span class="o">(</span><span class="n">View</span><span class="o">.</span><span class="na">VISIBLE</span><span class="o">);</span>
</span><span class='line'>            <span class="n">setVisibility</span><span class="o">(</span><span class="n">View</span><span class="o">.</span><span class="na">GONE</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>            <span class="c1">// If the caller just removed our empty view, make sure the list view is visible</span>
</span><span class='line'>            <span class="n">setVisibility</span><span class="o">(</span><span class="n">View</span><span class="o">.</span><span class="na">VISIBLE</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="c1">// ...</span>
</span><span class='line'>
</span><span class='line'>    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// ...</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android のタッチイベントを理解する(その1)]]></title>
    <link href="http://blog.lciel.jp/blog/2013/12/03/android-touch-event/"/>
    <updated>2013-12-03T20:31:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/12/03/android-touch-event</id>
    <content type="html"><![CDATA[<p>タッチイベントがうまく流れてこなくて困ったり、自力でイベントをルーティングしたりするときに困ったりと、ちょこちょことタッチイベントについて勉強したのでまとめておきます。<br/>
主にタッチイベントがどう流れてどう止まるかなどについて調べています。</p>

<p>イベントの流れを理解するには以下の資料がかなり参考になりました。</p>

<ul>
<li><a href="http://devsbuild.it/files/PRE_andevcon_mastering-the-android-touch-system.pdf">Mastering the Android Touch System (PDF)</a></li>
</ul>


<p>毎度のことながら、間違いがありましたらご指摘頂ければ幸いです。</p>

<!-- more -->


<h2>タッチイベントを処理する主要なメソッド</h2>

<p>実際の流れを理解する前に、主要なメソッドを三つ紹介しておきます。</p>

<table>
<thead>
<tr>
<th></th>
<th align="left"> <strong>メソッド名</strong> </th>
<th align="left"> <strong>概要</strong> </th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td align="left"> onTouchEvent() (<a href="http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent">View</a>) </td>
<td align="left"> タッチイベントに対して何かを処理するメソッド。setOnTouchListener() で登録した listener はこのタイミングで呼び出される。</td>
</tr>
<tr>
<td></td>
<td align="left"> onInterceptTouchEvent() (<a href="http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent">ViewGroup</a>) </td>
<td align="left"> タッチイベントが子供へと伝搬することを阻止できるメソッド。</td>
</tr>
<tr>
<td></td>
<td align="left"> dispatchTouchEvent() (<a href="http://developer.android.com/reference/android/app/Activity.html#dispatchTouchEvent(android.view.MotionEvent">Activity</a>, <a href="http://developer.android.com/reference/android/view/View.html#dispatchTouchEvent(android.view.MotionEvent">View</a>, <a href="http://developer.android.com/reference/android/view/ViewGroup.html#dispatchTouchEvent(android.view.MotionEvent">ViewGroup</a>) </td>
<td align="left"> タッチイベントを受け取り、子に伝搬させるかどうか、自分が処理するかどうかなどを管理する。onInterceptTouchEvent() や onTouchEvent() を呼ぶ人。</td>
</tr>
</tbody>
</table>


<p>　</p>

<h2>基本的なタッチイベントの流れ</h2>

<p>タッチイベントは Activity を経由して PhoneWindow 直下の DecorView から伝搬が始まり、親の View からその子 View へと dispatchTouchEvent() なるメソッドを通じて伝搬していきます。</p>

<p>dispatchTouchEvent() は 自身が ViewGroup だった場合、まず自身の onInterceptTouchEvent() を呼び出します。
onInterceptTouchEvent() では子にイベントを渡すかどうかなどを判断します(後で詳しく説明します)。</p>

<p>次に、子の dispatchTouchEvent() を呼び出してイベントを渡していきます。
このとき、親が子の dispatchTouchEvent() を呼び出す順番は、一番新しく追加した子から古い子へと逆順に渡していきます。</p>

<p>そして、最後に一般的にタッチイベントを処理するメソッドである onTouchEvent() が dispatchTouchEvent() によって呼ばれます。
この onTouchEvent() は、子から親へと逆順(ユーザから見ると手前に表示されている順)に流れていくようになっています。</p>

<p>文章だけだと分かりづらいので、たとえば以下のような構成の View の場合を考えてみます。</p>

<p><img src="http://blog.lciel.jp/images/android_touch_event_sample_view.png" alt="Sample View" /></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>FrameLayout1(白)
</span><span class='line'>|-- FrameLayout2(赤)
</span><span class='line'>`-- FrameLayout3(緑)
</span><span class='line'>    `- Button
</span></code></pre></td></tr></table></div></figure>


<p>この構成の場合、いずれの View もタッチイベントを処理しない、最もシンプルなイベントの流れは以下のようになります。</p>

<p><img src="http://blog.lciel.jp/images/android_touch_event_flow_01.png" alt="TouchEvent Flow" /></p>

<p>(1) から (13) の順番で処理が流れ、 onInterceptTouchEvent() が呼び出される順番は (I) から (III) となり、肝心の onTouchEvent() が呼び出される順番は (i) から (iv) となります。</p>

<p>画面と照らし合わせてみると、ユーザから見て手前側の View から onTouchEvent() が呼び出されていることを確認できるかと思います。</p>

<h2>タッチイベントを処理した場合の流れ</h2>

<p>タッチイベントは以上の流れで伝搬していきますが、いずれかのメソッドで true が返された場合、そこで連鎖がとまり、以降の処理は実行されなくなります。</p>

<p>例として、以下のように Button で onTouchEvent() を処理して true を返してみます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">TouchTestActivity</span> <span class="kd">implements</span> <span class="n">OnTouchListener</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// ...</span>
</span><span class='line'>        <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">button</span><span class="o">).</span><span class="na">setOnTouchListener</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onTouch</span><span class="o">(</span><span class="n">View</span> <span class="n">v</span><span class="o">,</span> <span class="n">MotionEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">v</span><span class="o">.</span><span class="na">getId</span><span class="o">();</span>
</span><span class='line'>        <span class="k">switch</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">case</span> <span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">button</span><span class="o">:</span>
</span><span class='line'>            <span class="n">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="n">TAG</span><span class="o">,</span> <span class="s">&quot;Touched!&quot;</span><span class="o">);</span>
</span><span class='line'>            <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>この場合、 Button の onTouchEvent() でイベントの伝搬が停止するため、 FrameLayout3 の onTouchEvent() はコールされず、 FrameLayout2 は onDispatchTouchEvent() すら呼ばれません。
つまり、ユーザから見て「触ってイベントが発生した View より後ろにある View」には onTouchEvent() が一切発生しないことになります。</p>

<p><img src="http://blog.lciel.jp/images/android_touch_event_flow_02.png" alt="TouchEvent Flow" /></p>

<p>OnTouchListener を登録したり onTouchEvent() を直接処理したりする以外にも、良くある例だと View#setOnClickListener() で OnClickListener を登録した場合なども、 onTouchEvent() で true が返るようになり、それ以降の View の onTouchEvent() はキャンセルされることになります。</p>

<p>子の OnClickListener などに影響されずにタッチイベントを処理したい場合は、子を呼びだすより前に呼ばれる onInterceptTouchEvent() で必要な処理を行うという方法があります。
例えば <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/widget/ScrollView.java#ScrollView.onInterceptTouchEvent%28android.view.MotionEvent%29">ScrollView</a> は子に影響されずにスクロール可能でなければならないため、 onInterceptTouchEvent() でスクロールの開始フラグを立てたりしています。</p>

<h2>onInterceptTouchEvent() で伝搬を止めた場合</h2>

<p>ViewGroup に実装されている onInterceptTouchEvent() で true を返すと、子供の View にイベントを伝搬しないようになります。</p>

<p>たとえば、以下のように onInterceptTouchEvent() で true を返すようにした CustomFrameLayout で FrameLayout3 を置き換えてみます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">CustomFrameLayout</span> <span class="kd">extends</span> <span class="n">FrameLayout</span> <span class="o">{</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onInterceptTouchEvent</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="c1">// ...</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>この場合、 FrameLayout3 が子供(Button)にイベントを伝搬しなくなるため、以下のようなイベントの発生順序になります。</p>

<p><img src="http://blog.lciel.jp/images/android_touch_event_flow_03.png" alt="TouchEvent Flow" /></p>

<p>また <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/widget/ScrollView.java#ScrollView.onInterceptTouchEvent%28android.view.MotionEvent%29">ScrollView</a> を例にあげると、スクロール中は子供のタッチイベントを発生させないようにする必要があるため、 onInterceptTouchEvent() が活用されている様子を見る事ができます。(イベントのアクションが MotionEvent.ACTION_MOVE かつドラッグ中フラグが立っていたら子へ伝搬させないなど)</p>

<p>また、この onInterceptTouchEvent() を使って親側から子へのイベントの伝搬が止められることがある場合、子供側から止めないようにお願いする事ができます。
イベントの伝搬を親側から止めないようにする場合は、親の <a href="http://developer.android.com/reference/android/view/ViewParent.html#requestDisallowInterceptTouchEvent%28boolean%29">requestDisallowInterceptTouchEvent()</a> を呼びます。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">TouchTestActivity</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// ...</span>
</span><span class='line'>        <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">button</span><span class="o">).</span><span class="na">getParent</span><span class="o">().</span><span class="na">requestDisqllowInterceptTouchEvent</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><img src="http://blog.lciel.jp/images/android_touch_event_flow_04.png" alt="TouchEvent Flow" /></p>

<p>requestDisallowInterceptTouchEvent(true) で onInterceptTouchEvent() を抑制した場合、親の onInterceptTouchEvent() が呼ばれないことになるので、子にイベントを流すようにするだけでなく、副産物的に onInterceptTouchEvent() で行っている処理を無視させることができます。</p>

<p>たとえば、 requestDisallowInterceptTouchEvent() と加えて、子の onTouchEvent() で true を返すなどしてイベントの伝搬を子で止めてしまえば ScrollView のスクロールを無効化できたりします。
このあたりを組み合わせると、入れ子状の ScrollView を実現できたりします。</p>

<h2>次回予告？</h2>

<p>自力でイベントをルーティングする場合の話や、 Action の話なども書こうと思いましたが、思ったより長くなってしまったので、気が向いたらまた次回書きます。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Octopress + Disqus でコメントを表示しようとしたがうまくいかなかった話]]></title>
    <link href="http://blog.lciel.jp/blog/2013/11/30/octopress-unable-load-disqus/"/>
    <updated>2013-11-30T22:16:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/11/30/octopress-unable-load-disqus</id>
    <content type="html"><![CDATA[<p>Octopress ルートディレクトリの _config.xml の disqus_short_name に short_name を書き込むだけで Disqus と連携されてコメントモジュールが表示される。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>disqus_short_name: &lt;short_name&gt;</span></code></pre></td></tr></table></div></figure>


<p>ところが以下のエラーが表示されてしまい、コメントモジュールがロードされない。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.</span></code></pre></td></tr></table></div></figure>


<p>オチは Disqus の short_name を理解していなかったのが原因で、ずっと Disqus ID を disqus_short_name に書き込んでいたのが問題だった。 # Disqus 使ったこと無かった上に説明を読んでなかった</p>

<p>Disqus では、コメントを投稿する単位としてまず Site を登録する必要があり、この Site の識別子として使われるのが short_name だった。
Disqus にログインした状態で<a href="http://disqus.com/register">ここ</a>にアクセスして Site を登録したところ、無事に short_name が生成された。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[StackTrace を文字列として取得する]]></title>
    <link href="http://blog.lciel.jp/blog/2013/11/29/get-stacktrace-strings/"/>
    <updated>2013-11-29T20:45:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/11/29/get-stacktrace-strings</id>
    <content type="html"><![CDATA[<p>Java において StackTrace を取得する。<br/>
どこかに仕込んでおくとデバッグ時に何かと便利。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">static</span> <span class="n">String</span> <span class="nf">getStackTrace</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">StackTraceElement</span><span class="o">[]</span> <span class="n">stacks</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Throwable</span><span class="o">().</span><span class="na">getStackTrace</span><span class="o">();</span>
</span><span class='line'>    <span class="n">StringBuilder</span> <span class="n">sb</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="o">();</span>
</span><span class='line'>    <span class="k">for</span><span class="o">(</span><span class="n">StackTraceElement</span> <span class="n">e</span> <span class="o">:</span> <span class="n">stacks</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span><span class="o">(</span><span class="n">e</span> <span class="o">==</span> <span class="n">stacks</span><span class="o">[</span><span class="mi">0</span><span class="o">])</span> <span class="k">continue</span><span class="o">;</span>
</span><span class='line'>        <span class="n">sb</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">&quot;\tat %s(%s:%s)&quot;</span><span class="o">,</span> <span class="n">e</span><span class="o">.</span><span class="na">getMethodName</span><span class="o">(),</span> <span class="n">e</span><span class="o">.</span><span class="na">getFileName</span><span class="o">(),</span> <span class="n">e</span><span class="o">.</span><span class="na">getLineNumber</span><span class="o">()));</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">sb</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ViewGroup では onDraw() の代わりに dispatchDraw() が呼ばれる]]></title>
    <link href="http://blog.lciel.jp/blog/2013/11/27/viewgroup-dispatchdraw/"/>
    <updated>2013-11-27T20:18:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/11/27/viewgroup-dispatchdraw</id>
    <content type="html"><![CDATA[<p>FrameLayout で onDraw() のタイミングで処理をしたいが、どうも onDraw() が呼ばれないように見える。</p>

<p>確認したところ、 ViewGroup を継承したクラスは onDraw() の代わり dispatchDraw() が呼ばれるようだった。<br/>
(その名の通り子の View に対して draw() をコールしたりしなかったりするメソッド)</p>

<p>ViewGroup を継承したクラスに対して onDraw() のタイミングで実行したい処理は、 dispatchDraw() に書けば問題なさそう。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">protected</span> <span class="kt">void</span> <span class="nf">dispatchDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="cm">/*</span>
</span><span class='line'><span class="cm">        canvas に対して処理をしたりなんだり...</span>
</span><span class='line'><span class="cm">    */</span>
</span><span class='line'>    <span class="kd">super</span><span class="o">.</span><span class="na">dispatchDraw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Octopress の preview は generate を兼ねる]]></title>
    <link href="http://blog.lciel.jp/blog/2013/11/26/octopress-preview-include-generate/"/>
    <updated>2013-11-26T21:10:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/11/26/octopress-preview-include-generate</id>
    <content type="html"><![CDATA[<p>今まで気がつかなかったけれど、わざわざ generate してから preview しなくても、 preview 中に source ファイルを書き換えれば勝手にそれを検知して regenerate してくれるっぽい。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='text'><span class='line'>$ rake preview
</span><span class='line'>...
</span><span class='line'>&gt;&gt;&gt; compass is watching for changes. press ctrl-c to stop.
</span><span class='line'>&lt;ここでファイルを編集&gt;
</span><span class='line'>[2013-11-25 22:35:05] regeneration: 1 files changed
</span></code></pre></td></tr></table></div></figure>


<p>これは便利！
ちなみに新規ファイルを保存してもきちんと捕足して regenerate してくれるみたい。<br/>
投稿のハードルを限りなく低くしたいと思っている身からは、preview を立てっぱなしに出来るのは捗りそう。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android 4.3 で ImageView#getImageMatrix() の挙動が変わっている]]></title>
    <link href="http://blog.lciel.jp/blog/2013/11/25/imageview-getimagematrix/"/>
    <updated>2013-11-25T11:19:00+09:00</updated>
    <id>http://blog.lciel.jp/blog/2013/11/25/imageview-getimagematrix</id>
    <content type="html"><![CDATA[<p>今まで ImageView#getImageMatrix() で取得した Matrix のインスタンスに対して、直接 post*() のメソッドを呼んだりして操作すれば表示に反映されていたが、どうやら 4.3 で挙動が変わったご様子。</p>

<p>結論から言うと、横着せずにちゃんと毎回 setImageMatrix() をしてやるか、はじめに setImageMatrix() してから getImageMatrix() を使うようにすれば想定通りに動作する。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">ImageView</span> <span class="n">imageView</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">imageView</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="kt">float</span> <span class="n">ratio</span> <span class="o">=</span> <span class="mf">2.0f</span><span class="o">;</span>
</span><span class='line'><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="n">imageView</span><span class="o">.</span><span class="na">getImageMatrix</span><span class="o">();</span>
</span><span class='line'><span class="n">matrix</span><span class="o">.</span><span class="na">postScale</span><span class="o">(</span><span class="n">ratio</span><span class="o">,</span> <span class="n">ratio</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">matrix</span><span class="o">.</span><span class="na">setImageMatrix</span><span class="o">(</span><span class="n">matrix</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">ImageView</span> <span class="n">imageView</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">imageView</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">Matrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Matrix</span><span class="o">();</span>
</span><span class='line'><span class="n">imageView</span><span class="o">.</span><span class="na">setImageMatrix</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'><span class="kt">float</span> <span class="n">ratio</span> <span class="o">=</span> <span class="mf">2.0f</span><span class="o">;</span>
</span><span class='line'><span class="n">matrix</span> <span class="o">=</span> <span class="n">imageView</span><span class="o">.</span><span class="na">getImageMatrix</span><span class="o">();</span>
</span><span class='line'><span class="n">matrix</span><span class="o">.</span><span class="na">postScale</span><span class="o">(</span><span class="n">ratio</span><span class="o">,</span> <span class="n">ratio</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<h3>どう変わってるのか確認</h3>

<p>4.2 以前では mMatrix (initImageView()で初期化されてる)がそのまま返っているのに対して、 4.3 以降では mDrawMatrix が返るようになっている。
(mDrawMatrix は configureBounds() でセットされている)</p>

<p>mDrawMatrix がセットされていない状態だと、その場で Matrix のインスタンスが作られているため、このインスタンスに対して直接操作を行っても反映されないというわけでした。</p>

<figure class='code'><figcaption><span>4.2_r1 android.widget.ImageView#getImageMatrix()</span><a href='http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2_r1/android/widget/ImageView.java#ImageView.getImageMatrix%28%29'>link</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="n">Matrix</span> <span class="nf">getImageMatrix</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">mMatrix</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<figure class='code'><figcaption><span>4.3_r1 android.widget.ImageView#getImageMatrix()</span><a href='http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r1/android/widget/ImageView.java#ImageView.getImageMatrix%28%29'>link</a></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="n">Matrix</span> <span class="nf">getImageMatrix</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">mDrawMatrix</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="k">new</span> <span class="nf">Matrix</span><span class="o">(</span><span class="n">Matrix</span><span class="o">.</span><span class="na">IDENTITY_MATRIX</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">mDrawMatrix</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Android はマイナーバージョンアップでも、結構こういう細かい挙動変更が入ってくるので、以前動いていたものが突然動かなくなることが良くあるのだけれど、Android のコードを直接見に行けば答えが書いてあるので安心感がありますね。</p>
]]></content>
  </entry>
  
</feed>
