2013年12月18日

[Android] dumpsysコマンド

dumpsysコマンドについて調べようと思い、検索したら以下のページが引っかかりました。
公式サイトのようです。
Dumpsys | Android Developers

ちゃんと読んでないのですが、Usageのところのコマンドが気になりました。
$ adb shell su -- dumpsys window

dumpsysの後にwindowと書かれています。
そして、その後にはWINDOW_MANAGERとも書かれています。
これはContext#getSystemService()で取得できる「○○マネージャー」に相当する文字列を指定できるのではないかと考えました。

Context | Android Developers

dumpsysの後に、↑ここで書かれている文字列を指定してみました。
shell@android:/ $ dumpsys window # → OK
shell@android:/ $ dumpsys layout_inflater # → NG
shell@android:/ $ dumpsys activity # → OK
shell@android:/ $ dumpsys power # → OK
shell@android:/ $ dumpsys alarm # → OK
shell@android:/ $ dumpsys notification # → OK
shell@android:/ $ dumpsys keyguard # → NG
shell@android:/ $ dumpsys location # → OK
shell@android:/ $ dumpsys search # → OK
shell@android:/ $ dumpsys vibrator # → OK?
shell@android:/ $ dumpsys connection # → NG
shell@android:/ $ dumpsys wifi # → OK
shell@android:/ $ dumpsys input_method # → OK
shell@android:/ $ dumpsys uimode # → OK
shell@android:/ $ dumpsys download # → NG

結果が返ってきたものは「OK」、エラーになったものは「NG」としました。
幾つかはエラーになってしまいましたが、だいたいのものはこれで情報が取得できるようです。
出力される情報の意味もわかっていませんが、dumpsysはこうやって使うんですね。
英語をちゃんと読めばこういうことも書いてあるんでしょうか…。
こういったコマンドも開発には役立ちそうなので、使い方を覚えてみるのも良さそうですね。


タグ:android ADB dumpsys
posted by t2low at 01:26| Android

2013年12月16日

[Android] Android4.2.2での9patch画像表示不具合?

9path画像をTextViewの背景画像として使用していたのですが、Android4.2.2の端末で正しく表示されない現象が発生しました。
以下のような画像を表示した際に、中心部分の赤丸が右下に寄ってしまうのです。

flag.9.png

ヤバそうな気配を感じましたが、幸い回避方法を公開してくれている方がいました。


Android - 9patchでStretchable Areaを横2箇所設置時に同幅にスケールしない問題の解決方法 - Qiita [キータ]


この記事のとおりに画像の幅を奇数にしたところ正しく表示されるようになりました。

HTL22(4.2.2)(上が偶数サイズの画像、下が奇数サイズの画像)
htl22_ss.png

ISW12HT(4.0.3)(上が偶数サイズの画像、下が奇数サイズの画像)
isw12ht_ss.png

画像はありませんがNexus7(2012)(4.4.2)では、偶数サイズでも正常に表示されました。
Android4.2.2の不具合なのでしょうか。


あと、この件とは関係ないのですが、上記画像に「J」という文字が表示されていますが、どれも「Content Area」に表示されていません。
「Content Area」は「Stretchable Area」と重ならないといけないのでしたっけ。
テキトーな知識で進めるからこうなるのでしょうね…。


タグ:android 9patch
posted by t2low at 23:00| Android

2013年12月13日

[Android] Fragmentの中でFragmentを使う

Fragmentは機能をまとめておけて便利ですね。
少し前に、Fragmentの中でもFragmentを利用できることを知りました。
getChildFragmentManager()でFragmentManagerを取得すれば良いようです。
以下はサンプルです。

MainActivity.java
public class MainActivity extends FragmentActivity {

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

Fragment fragment = NestFragment.newInstance(0);
getSupportFragmentManager().beginTransaction().add(R.id.content, fragment).commit();
}

public static class NestFragment extends Fragment {
private static final String ARG_ID = "id";

public static NestFragment newInstance(int id) {
Bundle args = new Bundle();
args.putInt(ARG_ID, id);

NestFragment fragment = new NestFragment();
fragment.setArguments(args);
return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main, null);

int id = getArguments().getInt(ARG_ID);
if (id < 5) {
Fragment fragment = NestFragment.newInstance(id + 1);
getChildFragmentManager().beginTransaction().add(R.id.content, fragment).commit();
}
((TextView) view.findViewById(R.id.text)).setText(Integer.toString(id));

int colorId = ((id & 1) == 1) ? android.R.color.black : android.R.color.white;
view.setBackgroundColor(getResources().getColor(colorId));

return view;
}
}
}


layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TEXT"
android:textColor="#888" />

<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp" >
</FrameLayout>

</LinearLayout>

表示するとこんな感じになります。(こんな使い方はしませんが)

device-2013-12-13-200829.png

posted by t2low at 23:00| Android

2013年12月12日

[Android] onLoadFinished()でDialogFragmentを表示する

データを読み込んで、ある条件に一致したらダイアログを表示しようと考え、以下のようなコードを書きました。
CursorLoaderを使ってデータを読み込んでいます。
条件を満たしていたら、onLoadFinished()でダイアログを表示します。
public class MainActivity extends FragmentActivity {

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

getSupportLoaderManager().initLoader(0, null, new LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getApplication(), HOGE_URI, null, null, null, null);
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// .. 何らかの処理 ..

DialogFragment fragment = new MyDialogFragment();
fragment.show(getSupportFragmentManager(), "dialog");
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
});
}
}

しかし、このコードを実行すると以下の例外が発生し、アプリがクラッシュしてしまいました。

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished

どうやら、onLoadFinished()内でダイアログを表示してはいけないようです。
UIスレッド以外でUIの操作をしてはいけないという制限によるものなのかと、ダイアログ表示部分を以下のように書き換えてみました。
runOnUiThread(new Runnable() {
@Override
public void run() {
DialogFragment fragment = new MyDialogFragment();
fragment.show(getSupportFragmentManager(), "dialog");
}
});

これもダメでした。同じ例外が発生してクラッシュしてしまいます。
インターネット上で検索してみると、Handlerを使えばうまくいくらしいことがわかりました。
以下のようにします。
handler.post(new Runnable() {
@Override
public void run() {
DialogFragment fragment = new MyDialogFragment();
fragment.show(getSupportFragmentManager(), "dialog");
}
});

これなら動きました。

イマイチよくわかりません。
時間があれば、もう少し調べてみたいところですが、今はちょっと忙しいのでここまで。

posted by t2low at 22:00| Android

2013年12月11日

[Android] キーがintのMapについて

以下のようなコードを書くと…
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(0, "ZERO");
map.put(1, "ONE");
map.put(2, "TWO");

Lintさんに怒られます。
「Use new SparseArray<String>(...) instead for better performance」
SparseArrayを使え、ということですね。↓こんな感じ。
SparseArray<String> map = new SparseArray<String>();
map.put(0, "ZERO");
map.put(1, "ONE");
map.put(2, "TWO");


また、調子に乗って、以下のように値がIntegerのSparseArrayを書くと…
SparseArray<Integer> map = new SparseArray<Integer>();
map.put(0, 10);
map.put(1, 100);
map.put(2, 1000);

やっぱりLintさんに怒られます。
「Use new SparseIntArray(...) instead for better performance」
SparseIntArrayを使えということですね。
SparseIntArray map = new SparseIntArray();
map.put(0, 10);
map.put(1, 100);
map.put(2, 1000);

少しでもアプリを良くしようとがんばってるLintさんステキです。

posted by t2low at 22:00| Android

2013年12月09日

[Android] Bitmapを回転する

アプリ内で画像(Bitmap)を回転しなければいけなくなりました。
カメラを使ったアプリを作ったときに一度実装したのですが、覚えていなかったので結局また調べて実装することに…。

Bitmap#createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) | Android Developers

使うのは↑このメソッドですね。
最後の引数のfilterは、変形する時にメソッド内部でPaint#setFilterBitmap()に渡す値のようです。
通常はtrueにしておくのが良いでしょう。
Bitmap orgBmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);

Matrix matrix = new Matrix();
matrix.postRotate(90);

Bitmap rotatedBmp = Bitmap.createBitmap(orgBmp, 0, 0, orgBmp.getWidth(), orgBmp.getHeight(), matrix, true);

こんな感じ。
回転しかしないならmatrix#setRotate()でも良いですね。
以上です。

posted by t2low at 22:00| Android

2013年12月05日

[Android] Android4.4搭載端末で操作動画を撮影する

Android4.4搭載端末であれば画面の録画ができると聞いて試してみました。

Android Debug Bridge | Android Developers

「adb shell」後に「screenrecord [ファイル名]」と実行すれば良いようです。
止めるには「Ctrl-C」ですね。
$ adb shell
shell@grouper:/ $ cd storage/sdcard0/tmp/
shell@grouper:/storage/sdcard0/tmp $ screenrecord test.mp4
^C
shell@grouper:/storage/sdcard0/tmp $ exit
$ adb pull /storage/sdcard0/tmp/test.mp4 ~/Documents/

保存したファイルは「adb pull」で取得出来ます。
Playストアに載せる動画を撮るのが簡単になりましたね。すごい。

タグ:android ADB
posted by t2low at 22:00| Android

2013年12月04日

[Cocos2d-x][Android] animations.plistの配置場所が原因でエラー

Cocos2d-xを始めてから間もないというのに、iOSでは動いて、Androidでは動かないという状況が発生してしまい、調査に疲れました。
結論から言うと、原因はanimations.plistの配置場所でした。

僕は普段はAndroidアプリを開発しているので、開発環境としてはEclipseに慣れています。
しかし、Cocos2d-xで作られたアプリをAndroid実機で動作させるのは少しめんどくさいです。
シェルスクリプトを動かした後で、Eclipseでのビルドを行わなければなりません。
(もっと効率よくビルドする方法もあると思いますが、まだ初心者なので調べておりません)
そのため、コードを書くのはEclipse上で行い、動作の確認はXcodeからiOSシミュレータを起動して行うようになりました。
そんなこんなでしばらくiOSシミュレータでしか動作を確認していなかったのです。

久しぶりにAndroid実機で動作を確認してみたところ、アプリがクラッシュするではありませんか。
おかしいと思いiOSシミュレータで動作を確認すると、こちらは正常に動きます。
まだデバッグ方法もわからない状態なので、CCLog("...")を各所に埋め込んで異常が発生している箇所を特定しました。
結果、animations.plistが読み込めていないことがわかりました。

animations.plistは「Resources/animations/animations.plist」として配置していました。
コード上では以下のように読み込んでいました。
	CCAnimationCache *cache = CCAnimationCache::sharedAnimationCache();
cache->addAnimationsWithFile("animations.plist");

iOSで動かすときはXcodeで明示的に参照を行っていたので、これでも正常に動いたようです。
Androidで動かすときは明示的にどうこうしないので、ファイルの場所がわからず実行時にクラッシュしていたようです。
配置場所を「Resources/animations.plist」とすることで、どちらの環境でも正常に動きました。

階層を設けてもAndroid/iOSともに同じコードで動かす方法もあるような気がしますが、そこは未調査でございます。

posted by t2low at 22:00| Cocos2d-x

2013年12月03日

[Cocos2d-x][Android] エラー発生

create_project.pyで作成されたプロジェクトがどのような構成になっているのか確認しようと、ソースファイルを見ていたら…。
「jni/hellocpp/main.cpp」をEclipseで開いたところ、盛大にエラーが発生していました。
どうやらいろいろと定義が見つからない状態の様子。直しましょう。

■Eclipseの環境設定(Cocos2d-xへの参照)

Cocos2d-x開発入門(p29〜)に「Eclipseの設定」という項目がありました。
この項目でCocos2d-xへの参照を設定していました。
Eclipseの「環境設定...」を開き「General→Workspace→LinkedRecources」の「New...」ボタンを押します。
Name:に「COCOS2DX」と入力し、Location:にはCocos2d-xを展開した場所を絶対パスで指定します。
この設定の後、プロジェクトをリフレッシュしたところ、エラーがかなり減りました。
しかし、まだ残っています。

■Eclipseの環境設定(NDKへの参照)

再びEclipseの環境設定を開きます。
今度は「C/C++→Build→Environment」の「Add...」ボタンを押します。
Name:に「NDK_ROOT」、Value:にNDKを展開した場所を指定します。
こちらは相対パスを指定しても怒られません。良いのでしょうか。わからないので、とりあえず絶対パスで指定しました。
続いて「C/C++→Code Analysis」の「Syntax and Semantic Errors」のチェックを外します。
「Apply」ボタンを押したところ、main.cppのエラーがすべて消えました。
発生すべきエラーをもみ消してしまったような印象があるのですが、これで良いのでしょうか?
(このチェックを外すところはプロジェクト毎のプロパティで設定した方が良いかも?)

■他
この設定が抜けていたせいなのかどうかはわかりませんが、これまでClassesやcocos2dxのフォルダが開けませんでした。
一度プロジェクトをEclipseから削除し、再度インポートしなおしたところ、Classesフォルダ内のファイルも開けるようになりました。
良かった良かった。

とりあえず、エラーは消えたので作業を続けます。



posted by t2low at 21:00| Cocos2d-x

2013年12月02日

[Cocos2d-x][Android] 開発環境を構築する

Cocos2d-xを使った仕事をすることになりました。
ということで、まずは開発環境の構築から。

■Cocos2d-xのインストール
以下のサイトからcocos2d-xをダウンロードしてきます。

Cocos2d-x | Cross Platform Open Source 2D Game Engine

僕はこの記事を書いている時点の安定版v2.2.1をダウンロードしました。
ダウンロードしたzipファイルは展開して、「~/cocos2d-x/cocos2d-x-2.2.1」として配置しました。
入門書によるとCocos2d-xは頻繁に新バージョンがリリースされるらしいので、後々切り替えられるようバージョンがわかるようにしておいた方が良いようです。

あと、~/.bash_profileに以下を追加しておきます。
# cocos2d-x 設定
export COCOS2DX_ROOT=~/cocos2d-x/cocos2d-x-2.2.1

■Android NDKのインストール
以下のサイトからAndroid NDKをダウンロードしてきます。Revision 9bをダウンロードしました。

Android NDK | Android Developers

ダウンロード完了後、「~/android-ndk/android-ndk-r9b」に展開しました。
~/.bash_profileに以下を追記します。
# Android NDK 設定
export NDK_ROOT=~/android-ndk/android-ndk-r9b


■プロジェクトの作成
各OS向けに作成する方法もあるようですが、とりあえずはクロスプラットフォーム向けのプロジェクトを作成してみます。
$ cd $COCOS2DX_ROOT/tools/project-creator
$ python create_project.py
Usage: create_project.py -project PROJECT_NAME -package PACKAGE_NAME -language PROGRAMING_LANGUAGE
Options:
-project PROJECT_NAME Project name, for example: MyGame
-package PACKAGE_NAME Package name, for example: com.MyCompany.MyAwesomeGame
-language PROGRAMING_LANGUAGE Major programing lanauge you want to used, should be [cpp | lua | javascript]

Sample 1: ./create_project.py -project MyGame -package com.MyCompany.AwesomeGame
Sample 2: ./create_project.py -project MyGame -package com.MyCompany.AwesomeGame -language javascript

create_project.pyというスクリプトでクロスプラットフォームなプロジェクトを作成できるようです。
引数なしで実行すると使い方が表示されます。
各引数にパラメータを与えて実行します。
$ python create_project.py -project MyCocos2dx -package com.example.mycocos2dx -language cpp 
proj.ios : Done!
proj.android : Done!
proj.win32 : Done!
proj.winrt : Done!
proj.wp8 : Done!
proj.mac : Done!
proj.blackberry : Done!
proj.linux : Done!
proj.marmalade : Done!
New project has been created in this path: $COCOS2DX_ROOT/projects/MyCocos2dx
Have Fun!

■プロジェクトをEclipseにインポートする
まずはCocos2d-xのライブラリプロジェクトをインポートします。
Eclipseを起動し、[File]-[Import...]から[Existing Android Code Into Workspace]を選択して、以下のAndroid用プロジェクトを選択します。

$COCOS2DX_ROOT/cocos2dx/platform/android/java

このとき「Copy projects into workspace」のチェックが付いているとうまくいかないようです。
続いて、同様に作成したプロジェクト(Android用のもの)をインポートします。

$COCOS2DX_ROOT/projects/MyCocos2dx/proj.android

■ビルド・実行
C++コードのビルドはコマンドラインから行うそうです。
プロジェクト(Android用)のディレクトリに移動して、ビルド用スクリプトを実行します。

$ cd $COCOS2DX_ROOT/projects/MyCocos2dx/proj.android
$ ./build_native.sh

コンパイルが完了したら、Eclipseから実行します。

device-2013-12-02-171310.png

うごきました。

今回の環境構築は以下の2冊の書籍を参考にさせてもらいました。





posted by t2low at 21:00| Cocos2d-x