2017年1月11日水曜日

MOVERIO カメラアプリを真面目に考えてみる / その2

MOVERIOは、自分で色々作らないと話にならない…。
ということで、まずは、カメラアプリから、作ろうということにしたんだが。

音量が小さい問題とか、Androidでタッチが認識されない問題とか。

検証アプリ作ったりで、時間取られまくったけど、ようやく本来のカメラアプリが開発できる…?

かと思いきや、MOVERIOは、やはりコントロールBOXの入力がトリッキーらしい。
こちらの記事でも書きましたが、まずは、タッチパッドで長押しすることから始まる。

実際、ギャラリーなど、Androidで共通で使われるアプリを操作してみると、正しく操作できているように思える。

例えば、タッチパッドを長押しして、カーソルが○⇒●に替わった瞬間に、左にはじくと、左フリックになる。
(ホーム画面が右にスクロールする)

だが同じことを自作アプリでやっても、Activityの onTouchEvent() にブレークが来ない!
カーソルが○のまま移動する、HOVERに関しては、がんがんブレークに引っかかってくるのだが、onTouchEvent() には、全く来ない。

と思いきや、たまに来る。

コントロールBOXは特殊な操作なので、HOVERの内部で、タッチイベントを発行しているのではないかと推測できるが、これまた検証だよ…。

ついでに、サイドの物理ボタンも検証するか。
技術資料によると…。

お、トラックパッドで取得できるイベント一覧もあるぞ。

onTouchEvent 発生することになってるな。いや発生はするけど、タイミングおかしいんだけど。

まあ、それは検証に回して、キーに関しては、

Volume Up
Volume Down
Back Key
Up
Down
Left
Right
Enter Key

通知されるのは、これくらいか。
Back Keyは使いにくいので、それ以外だな。


2017年1月10日火曜日

Androidでタッチイベントが取得できないだと!/ 解決編

Androidで初回のタッチが取得できない件が解決した。

どうやら、ナビゲーションバーの非表示が絡んでいたらしい。
ナビゲーションバーの非表示については、Activityの onCreate() で以下をするのが一般的のようだ。
View view = window.getDecorView();
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | c);

これを、GLSurfaceView を作成して、setContentView をやったあとに呼ぶのか、やる前に呼ぶのか、説明しているブログでも統一されていない。

今回のアプリの実機テストは、F-10Dと、nuuX4で行っているのだが、どちらの機種も、ナビゲーションバーは物理的に表示されていて、OFFにできない。

※上記プログラムの青色部分は、APIレベル的にF-10Dでは対応してないので注意

だが、ナビゲーションバーの表示を切り替えられる、MOVERIO BT-300で試したところ、原因が分かった。

この命令は、あくまで、ナビゲーションバーを“隠す”ものなのだ。
で、隠れた状態で、タッチすると、ナビゲーションバーが表示される。

このナビゲーションバーの表示に、1タッチ取られているから、初回のタッチは検出できず、ナビゲーションバーは一度表示されると、二度と隠れないので、そのままアプリのActivityにタッチイベントが通知される、という動作のようだ。

むむ…。

元々、ナビゲーションバーの非表示を追加したのは、MOVERIO対策。
ディスプレイに有機ELを使用しているため、長時間同じものを表示すると焼きつく、と説明があるからだ。
ナビゲーションバーなんて、同じものしか表示しないジャン!

だが、実機テストは、今まで通り、F-10Dで行っていたので、初回タッチ問題が発生してしまったわけだ。

実機テストをnuuX4に変更し、ターゲットをレベル19(Android4.4)に設定して、

View.SYSTEM_UI_FLAG_IMMERSIVE
を追加したところ、ナビゲーションバーも表示されなくなり、かつ、1タッチ目から取得できるようになった。

めでたしめでたし。

MOVERIOの技術資料を見ると、この点に触れていて、BT-300より前の機種では、専用のAPIでフルスクリーンにしていたが、BT-300では、Android標準の、上記方法でフルスクリーン化ができるようになったそうな。

もう、実機テストにすら、使えなくなってきたのか >F-10D

しまった、実機テスト用に、年末年始の安いタブレットを買っておけば良かった…!


2017年1月8日日曜日

Androidでタッチイベントが取得できないだと!/ その3

tetatailでも解決できないので、地道に自分で解析中。
まだ解決はできていません。

最近のプロジェクトは、速度重視のため、SurfaceView ⇒ GLSurfaceView に作り変えたもの。

基本システム以外、入力なども全て一旦削除(コメントアウト)して、
GLでのシステムができたので、徐々に機能を追加している途中で、
初回タッチが入力できていない、ということが発覚した。

なので、昔のプロジェクトを実行してみたところ、問題なく全てのタッチが取得できている。
ということは、

・GLSurfaceViewのタッチ入力
・その他の改良部分

のいずれかであることは間違い、ということだ。

次の検証。

GLSurfaceView をそのまま使用していた部分を、MyGLSurfaceView に変更し、
APIをラップして動作を確認してみる。

まず、onTouchEvent() だが、Activityと同様に、2回目しかコールされていない。

起動時に、onWindowFocusChanged(boolean) が、 true でコールされていることを確認。
これで、フォーカス移動に1タッチ取られている、という可能性も低くなった。

ちなみに、onWindowFocusChange() 内で、ブレークしているときに、画面を2回タップして再実行すると、やはり、1回分のタップが認識される。

ブレーク中もきちんとタッチした回数を覚えていて、その回数 -1 回、onToucheEvent() がコールされている。

以上のことから、タイミングなど不確定要素が絡んでいる可能性は低く、確実に、初回の1タップ処理が、何か別の処理に搾取されていると推測できる。

一体、何なんだ…。



2017年1月7日土曜日

teratail / Androidでタッチイベントが取得できないだと!

Androidで、初回のタッチイベントが取得できないという、
もうどうしようもないバグが出たので、
前から気になっている質問サイトに、投稿することにした。

https://teratail.com/

広告として出てくるので、見たことある人も多いと思う。
売り文句としては、

 「15分悩んで分からなければteratail」
 「最短○○分で回答が来た!」

とか、言ってるんで、だったら聞いてみよう、と。

実際の質問が、これ。
https://teratail.com/questions/61089


いやー、回答きませんな!

Google絡みの問題が発生したときにも、サポートセンターが無いので、
プロダクトフォーラムというのに質問したんだが、
これまた返事がこない。

https://productforums.google.com/forum/#!topic/google-plus-ja/W1J048JtmDY

Googleの方も、エキスパートって人が返答してくれてるが、
スレ違いだがら、スレ移動しといたわ、ってだけ。

エキスパートなら、答えてよ。
こっちは、マニュアルどおりの操作しかしていないんだから、
この程度の質問に答えられなくて、エキスパートってなんだよ…。

結局、こういうサイトって、素人がちょっと困っているってのに役立つだけで、
エンジニアが本気で困っている質問に、答えられる人は居ない

ってことの証明にしかならんわ。





2017年1月6日金曜日

Androidでタッチイベントが取得できないだと!

ごく一般的なつくり方で、いくか自分用のアプリも作ってきたのだが、
ここにきて、タッチという、超基礎の部分で不具合が発生した。

Activityの onTouchEvent() が反応しないのだ。

最初のタッチのみ反応して、2回目以降反応しない

これは良くある問題で、検索すればいくらでも対処方法はでてくる。
onTouchEvent() の最後で、

 return true

と、trueを返すようにするだけだ。

だが今発生している問題は、

初回のタップのみ反応せず、2回目以降は反応する』だ。

意味が分からない。

onTouchEvent() の内部に、ブレークポイントを仕掛けておくと、
最初のタッチでは無反応なのに、2回目以降は、しっかりブレークしてくる。

たしか、去年アプリを作った時は、こんな問題は発生していなかったはず。
こんな大きな問題を見落とすはずがない。

とすると、最近大改造して、surfaceView ⇒ GLSurfaceView にしたのが一番怪しい

MotionEvent ev = MotionEvent.obtain(10, 20, MotionEvent.ACTION_DOWN, x, y, 0);
this.onTouchEvent(ev);

↑これを使うと、疑似的にプログラムから、タッチイベントを呼べるらしい。
onCreate() の最後に付け加えると、確かに onTouchEvent が呼ばれている。

が、その後、タッチすると無反応で、2回目から反応する。

どういうことなのだろうか?

一番考えられるのは、初回、別のどこかにフォーカスが当たっていて、
初回タップで GLSurfaceViewにフォーカスが移り、反応するようになった、だろう。

念のため、起動時に、

view.bringToFront();

で、一番手前に持ってきているはずなのだが…。