タグ:android ( 37 ) タグの人気記事

カメラのカラーエフェクトのバグ

Androidでカメラアプリを作っているわけだが、カラーエフェクトのバグが回避できなくて困っている。
(もしかしたら、ホワイトバランス等、他でもそうなのかも)

カラーエフェクトの設定は、
CameraParameters.setColorEffect(String);
この関数で行う。

Stringの部分に、"negative"を指定すれば、白黒反転、"sepia"でセピアカラーといった具合だ。
そして、"none" でエフェクト無しに戻せる。

…はずなのだが。

ドコモ端末F-10D:問題なし。

S5110b:エフェクトの切り替えはできるが、noneを指定すると無視される&プレビューが停止。
カメラを一度破棄することで、元に戻せる

KEIANタブレット:同じく、エフェクトの切り替えできるが、noneを無視。二度と復帰不可能

どれくらい不可能かといえば、カラーエフェクトを適用して、アプリ終了。内蔵されているカメラアプリを起動すると、さっき設定したエフェクトが残ったまま、というくらい、深く刻み込まれている。
再起動すれば元に戻るのだが…。


----
追記:

解決策見つけました。
http://miries.exblog.jp/24072856/
[PR]
by miries | 2015-01-29 15:38 | Android

続・Activity切り替え

カメラアプリには必須っぽいActivity切り替え。
そこにも、まだまだ罠が潜んでいた。

今自作しているアプリは、独自フレームワークを使っている。
Activityを継承したフレームワーククラスを作り、なるべく共通な要素をそこで処理し、
ゲーム毎に行うべき処理を、ゲームのメインクラスとして定義し、
フレームワークでインスタンスを生成している。

がActivityを継承したフレームワークは、そもそもActivity切り替えなぞ考えてない設計だった。
Activityを切り替えるたびに、この初期化部分が呼び出される。

レイアウトを作り変えるのが、切り替えの目的だから、毎回初期化部分が呼び出されないと困るわけだが、
その他の初期化部分は、なるべく一度しか処理されないようにしなければならない。

まあ、タッチライブラリの初期化、など、各種ユーティリティの初期化しか行ってないので、基本問題は無い。
と思いきや、ゲームクラスの初期化に問題があった。

シングルトン形式で、インスタンスを1つしか生成しないようにしているため、2回目以降の初期化(生成処理)は通過しない。
この初期化の中で、

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

これで、画面を横方向に固定している。
どちらの画面方向を使うかは、ゲームによって異なるので、フレームワークには入れなかった。

しかし、この処理は、毎回必要らしい。


初回起動・フレームワーク初期化、ゲームクラス初期化
 ↓
別のActivity切り替え
 ↓
元のActivityに戻る
 ↓
フレームワーク初期化・ゲームクラスはインスタンスがあるため、初期化スルー

とすると、画面設定が、任意方向可に戻るのだ。
面倒だのう。

あと、もう1つ。
これは、アプリ制作では、周知の事実だけど、Activity切り替え(View切り替え)を使うと、顕在化する。

AndroidOSにある、1つ戻るボタン(機能)。
これは、ホーム画面に戻る、ではなく、1つ前のVIEWに戻る、という機能なんだな。

ゲームで1つのVIEWしか使って無いと、ゲーム中に1つ戻ることで、ホーム画面に戻る。
が、Activity切り替えを導入し、一度切り替えると…。

1つ戻るボタンでは、永久に、アプリは終わらなくなる…。
[PR]
by miries | 2015-01-25 10:16 | Android

カメラとActivity切り替え

まだまだカメラアプリと格闘中。

中華タブレットから、F-10Dに戻ってアプリを起動すると…。
エラーの嵐!

なん…だと…。

ログ出力を見てみると、アプリ起動直後に、onDestroyが呼ばれ、その後、自動で再起動している。
そんなバカな。

以前は問題なく動いたはずだ。
何もなく Destroyが呼ばれるはずが無い。
改変の途中で、何かしらいけないことをやっているということか?

しかし、差分は大きい。探し出すのは不可能にちかい…。

いやまて。
通常、Destroyが呼ばれる=アプリ終了だ。
大抵、ぬるぽだったりするはずだ。

それが、そのままActivityが再起動するだと?
どこかでその現象みたことがあるぞ!

そう、画面の回転だ。
Androidは、画面が回転するだけで、Activityの破棄・生成が起きる。
しかし、それを回避するマニフェストは書いてある。

android:configChanges="orientation|keyboardHidden"

そう、これだ。
しかし、これと似たようなところに、原因があるはずだ!

…と目星をつけて、ぐぐると…見つけやしたぜ!

android:configChanges="orientation|screenSize|keyboardHidden"

なんと、APIレベル13以上から、orientation以外に、screenSizeもつける必要があるらしい。
そういえば、先日、API8⇒API16に上げたわ。

お 前 が 原 因 か!

つか、似たような原因じゃなくて、もろ回転じゃねーか!

ということで1つ解決したが、まだまだ残ってる。
IntentによるActivity切り替え後のカメラプレビューが表示されなかったり、
プレビューを開始すると落ちたりするのだ。

先は長い。
[PR]
by miries | 2015-01-23 23:33 | Android

カメラのプレビューとsurfaceViewのサイズ

カメラのプレビューサイズと、SurfaceViewのサイズについては、カメラアプリを作るときに必須なので、すでに多くのサイトで解説がなされているので、さらっとおさらい。

●カメラのプレビューサイズは、任意に決定できない。
サポートされているサイズセットの中から選ぶ

●プレビューサイズは、端末の画面サイズと同じとは限らない
(というか、一致しない方がデフォ)

●プレビューサイズを設定しても、最終的には、SurfaceViewのサイズになる。
(viewのサイズに、ViewGroup.LayoutParams.WRAP_CONTENTを指定した場合)

なので、16:9のアスペクト比を持つ画面いっぱいのViewに、4:3のプレビューを表示すると、横に伸びた映像になる。
この辺りを、どう解決するかで、みんながググる事になる。

一般的な解決方法は、SurfaceViewを作って、レイアウトにaddView() する際に、
プレビューの比率に合わせてサイズを指定することである。

しかしこのSurfaceViewのサイズ、一旦決めたら、変更するのがなかなか難しい。
もし、画面サイズが変わる端末があったら、プレビューが見切れたりしてしまう。

そんな、恐ろしい端末が、s5110bである!

b0163324_12252714.png
b0163324_12253662.png


画面下のアクションバーを(アプリ起動中でも)いつでも出し入れできるのだ。
アクションバーが消えているときは、画面一番下を横にスワイプすることで出てくる。

ちなみに画面サイズは、[800x480] [800x432]で、アクションバーの高さは48ピクセル、
割合にして、10%も変化してしまう。

アクションバーを出した状態で、カメラアプリを起動し、アクションバーを消すと、変な空白が生まれるわけだ。

この微妙な見た目に対応するためには、どうにかしてSurfaceViewのサイズを変更する必要がある。

画面サイズが変更されるので、onSizeChanged()が呼ばれるが、
名前の通り、サイズが変更"された"ときに呼ばれるメソッドだ。
ここで何をやっても何も起こらない。

そこで、見つけたのが、onMeasure() だ。

これは、画面サイズ変更時(だけではないが)に呼ばれ、
各Viewのサイズを算出して設定するメソッドだ。
ここで取得できるサイズは、変更後の新サイズで、試しに100x100を設定したら、きちんと反映された。

まあ、自力で算出しろってことだ。

そんなこんなで、実際のコード。
カメラプレビューは、アスペクト比4:3から変更するつもりがないので、固定で書き込んでいる。

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int widthMode= MeasureSpec.getMode(widthMeasureSpec);
int heightMode= MeasureSpec.getMode(heightMeasureSpec);

int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);

int dw = w;
int dh = h;

switch(widthMode) {
case MeasureSpec.EXACTLY:// 確定
break;
case MeasureSpec.UNSPECIFIED:// 自由
dw = h *4 /3;
break;
case MeasureSpec.AT_MOST:// 以下
dw = h *4 /3;
if ( dw > w ) {
dw = w;
}
break;
}
switch(heightMode) {
case MeasureSpec.EXACTLY:// 確定
break;
case MeasureSpec.UNSPECIFIED:// 自由
break;
case MeasureSpec.AT_MOST:// 以下
dh = dw *3 /4;
if ( dh > h )
dh = h;
break;
}

//サイズ反映
setMeasuredDimension(dw, dh);

}


[PR]
by miries | 2015-01-22 13:00 | Android

SurfaceViewの重ね順

久しぶりにカメラアプリを作ろうと、数年前のプロジェクトを見直す。

写真にフレームイラストを合成しようとすると、どうしても、Viewを重ねる必要が出てくる。
下にカメラのプレビュー映像を流し、その上に(プリクラ的な)フレームを重ねるわけだ。

で、この辺も過去にしっかり作っていたんだけど。
ググっていると、気になる一文を見つけた。

ホームキーを押すなどして、一旦アプリを停止してから、レジュームすると、
SurfaceViewの順番が入れ替わるらしいのだ。

過去には、そこまで細かくテストしてなかった気がするので、早速テストしてみると、
確かに、フレームイラストの上に、プレビューが来てしまうではないか。

これを回避するには、SurfaceViewに対して、onResume時に、bringtoFront() をすればいいらしい。
ということで追加。

…。
直らんやんけ!

カメラの初期化に時間を食ってるからか?
色々実験してみるが、全く直る気配なし。

再び、グーグル先生に詳しく聞いてみる。

なんと!
SurfaceViewのソート順は、内部で勝手に決められていて、任意に設定することは出来ないとな!

任意ではないが、ある程度の設定はできる。

setZOrderOnTop(true);

これで、最前面のプライオリティになるようだ。
が、コレだけではダメ。
onResume時に、bringToFront()がやっぱり必要なのだ。

つまり、この2つは必須セット。
おのれ、bringToFront()だけとか、中途半端な情報に騙されたわ!
[PR]
by miries | 2015-01-20 01:59 | Android

タブレットのエアタップ

タブレット(画面をタッチして操作する機器)で、何もしてないのに、勝手にタッチされる現象をエアタップというらしい。

先日まで正常に動作していた、ウチのVita型Androidタブレット、s5110b にもエアタップ現象が発生。

現象の隙をついて、開発者オプションの「タップ位置を表示」オプションをONにしてみると…。
画面最下部(s5110bでは、ステータスバーが表示されているところ)に、ものすごい勢いで●マークが出現。

今自作しているアプリは、5点同時タップで、ソフトウェアリセットがかかるようにしてあるのだが、
これが発動するくらい、すごい勢いでタップされている。

もうこうなると開発はおろか、普通に使うのも無理。
なんとかならないものか…と、再起動はもちろん、画面を吹いたり、分解して掃除してみたりしたのだが影響なし。
最悪なことに、画面最上部にもいくつか出るようになってきた。

そんななか、ドコモの特定の機種で、この現象が発生した場合、
バッテリーが完全になくなるまで使い切ったあと、再起動すると、キャリブレーションが行われる、という噂を発見。
早速、バッテリーが無くなるまで放置し、さらに丸一日放置。

起動してみると…。
おお!発生しなくなってる!

ごくたまに発生するようだが、元々このくらいの頻度で暴走していたので、よしとしよう。


----
追記

とりあえず、一日開発して、エアタップは発生しなかった。
バッテリー使いきり再起動は、方法の1つとして有効なようだ。
[PR]
by miries | 2015-01-16 11:59 | Android

AndroidStudioのlogcat

アプリの開発には、デバッグが必須なわけだが、Androidでは、logcatを使用している。

自分で printf した内容が表示されるログエリアなんだが、
確か、昨日まではちゃんと機能していたんだよ。

それが、今日になって、なーんにも表示されなくなった。

表示するログは大量なので、(実機につないでいると、関係ないアプリのログも全部出る)
フィルタリングする機能があるのだが、良く見たら、勝手にフィルタが設定されている。

アプリのパッケージ名でフィルタリングするように設定されているが、
試しに、no filter にすると、全部問題なく表示された。

で、しばらくして気づいたら、やっぱり何もでなくなっている。

どうやら、アプリを実機で動作テストした瞬間に、
・なければ、自動的にアプリ名のフィルタを生成
・アプリ名のフィルタに自動切り替え
を行うらしい
まったく余計なことを。
そもそも、パッケージ名できちんとフィルタリングできていれば問題ないのだが。

ぐぐってみと、やっぱり、パッケージ名でフィルタリングできねーじゃねーか!と問題になっていた。
http://stackoverflow.com/questions/7537419/how-to-filter-android-logcat-by-application

現状、解決してないようなので、自動的に作られたフィルタの中身を手動で空にしてやると、
全ログが表示されるようになった。

あとは適当に、タグのフィルタを追加してやれば、見やすくなるだろう、、、。
[PR]
by miries | 2015-01-15 15:20 | Android

Android端末とリフレッシュレート

ちょいと気になったので、色々実験してみた。

リフレッシュレートを取得するコードは、ぐぐれば沢山あるので省略。

手持ちの端末で表示した結果、

60.0

という値が表示された。
(なぜ取得関数は、float型で返すのだろうか…)
今作成しているアプリは、GLを使わず、Canvasを使用して描画している。
2Dのゲームなので、これで十分だ。

1フレーム分の処理にかかった時間から、スリープ時間を算出してsleepしているわけだが、
この sleep処理をコメントアウトしても、60fps以上が出ない。

特にFPSを制御する命令など入れた覚えはないのだが…。
で、調べたら、描画するためのCanvasを取得する関数、

canvas = holder.lockCanvas();

これが原因らしい。
どうやら、内部で、リフレッシュレートに合わせた操作をしているらしく、
リフレッシュレートよりも早い間隔でアクセスすると、処理時間の算出がうまくいかないようだ。

ためしにコメントアウトすると、

FPS = 279789

なんか、とんでもない値が(笑
--------
追記。
手持ちのKEIANタブデットで、FPSを取得したら、

71.591

という中途半端な数値が表示された…。
[PR]
by miries | 2015-01-07 18:30 | Android

ウインドウ描画

最近は、CSSとかにも実装されている、1枚の絵から、ウインドウを描画する機能。
昔ながらの方法だと、画像を9分割して…という方法なのだが。

Androidでも、drawBitmapMeshを使えば、楽にできるのね。

24x24ピクセルのウインドウパーツ(8x8の9ブロック)があれば、
以下で描画可能。
canvasとimageは適宜に。
----
public static void drawWindow(int x, int y, int w, int h) {

float[] verts = new float[16*2];

int block = 8;

verts[ 0] = x;verts[ 1] = y;
verts[ 2] = x + block;verts[ 3] = y;
verts[ 4] = x + w -block;verts[ 5] = y;
verts[ 6] = x + w;verts[ 7] = y;

verts[ 8] = x;verts[ 9] = y +block;
verts[10] = x + block;verts[11] = y +block;
verts[12] = x + w -block;verts[13] = y +block;
verts[14] = x + w;verts[15] = y +block;

verts[16] = x;verts[17] = y +h -block;
verts[18] = x + block;verts[19] = y +h -block;
verts[20] = x + w -block;verts[21] = y +h -block;
verts[22] = x + w;verts[23] = y +h -block;

verts[24] = x;verts[25] = y +h;
verts[26] = x + block;verts[27] = y +h;
verts[28] = x + w -block;verts[29] = y +h;
verts[30] = x + w;verts[31] = y +h;

canvas.drawBitmapMesh(image, 3, 3, verts, 0, null, 0, null);

}
----
[PR]
by miries | 2012-12-18 12:06 | Android

レスポンシブルWebデザイン

最近、Webページのデザインで、レスポンシブルが流行っているということで、
早速自分でもテストすることにした。

色々なところに、ショーケースがあるので、それを眺めていたら、
想像以上にブラウザサイズに合わされていて驚愕。

こんなのどうやってデザインするんだよ…と思っていたら、
MediaQuery というのを使えば、一発でできるんだね。

MediaQueryの役割は、ブラウザサイズ(デバイスサイズでも可)によって、
使用するスタイルシートを分岐できる、というもの。

この分岐が、JavaScriptを使わなくても、
リアルタイムに変更されるのが素晴らしい。

ブラウザサイズに合わせて、ロゴなどの画像のサイズを変化させているページもある。
それらがどうやっているかは正確には見ていないが、
自分のテストでは、background-image の切り替えで簡単にできた。

仮に、ブラウザサイズを6段階判別するようにして、
それぞれに画像を割り当ててみた。

アクセスログを見ると、まず、ブラウザサイズにより分岐した、
最初の画像が読み込まれるのみ。

ブラウザサイズを変更すると、それに合わせた画像が読み込まれ、
元のサイズに戻しても読み込みは発生しない。

これは良いね。
スマフォとか回線が遅い端末にもぴったりだ。

JavaScriptやPHPなんかを使わなくても、インタラクティブなページが
こんなに簡単に作れるようになっていたとは。
[PR]
by miries | 2012-12-11 19:18 | デジタル系