2011/12/29

Android端末のフィーチャー定義を取得する

端末のフィーチャー定義を取得する方法です。

PackageManagerクラスのgetSystemAvailableFeaturesあるいはhasSystemFeature
を利用することで調べることができます。

サンプルソースは下記。

FeatureInfo[] infos = getPackageManager().getSystemAvailableFeatures();
for (FeatureInfo info : infos) {
    android.util.Log.e("yuki" , "yuki features = "  + info);
}

フィーチャー名は PackageManager.FEATURE_* として定数定義されています。

参考:Android Developerサイト

以上です。
2011/12/28

Android3.2以降、画面回転で意図せずActivityが再起動してしまう

orientationのconfigChangedを受け取っているのに画面回転させるとActivity
が再起動されてしまう問題に悩まされたので覚書。

HoneyComb MR2(Android3.2)以降、画面回転時にSCREEN_SIZEのconfigChangeも
走るようになりました。

参考:Android Developerサイト

これにより、AndroidManifestで
 android:configChanges=orientation
としただけでは不十分となりました。

画面回転時の再起動を防ぎたい場合は
 android:configChanges=orientation|screenSize
とする必要があります。(※端末形状によってはkeyboardHiddenも必要)

実際にソースコードを組んで確認してみます。
@Override
protected void onDestroy() {
    super.onDestroy();
    int change = getChangingConfigurations();
    android.util.Log.e("yuki" , "yuki c=" + String.format("0x%08x", change));
    // CONFIG_SCREEN_SIZE 0x000004
    // CONFIG_ORIENTATION 0x0000008
}
結果は 
 yuki c=0x00000480
となります。(CONFIG_SCREEN_SIZE|CONFIG_ORIENTATION)

以上です。

2011/12/25

Android:GPSの測位が上手くいかない場合の対処法

GalaxyS や GalaxyS2でGPSの測位が上手くいかない、GPSの測位がおかしい場合の対処方法。

WiFi通信中である場合にGPSの測位がうまくいかない場合が多いです。
3Gデータ通信中だとそうでもないようです。

3Gデータ通信を常にOFFにしている(WiFiしか使用しない)ユーザにとってGPSが使えないのは非常
に不便です。
改善方法は下記です。

1. 一度データ通信(3G等)をON,WiFi通信をOFFにした状態でGPS測位させる。
2. 測位完了後にデータ通信をOFFにして、WiFi通信ONに戻す。



どうもGalaxy特有の問題だそうです。(Nexusでも発生するかは不明)
以上です。
2011/12/23

解像度別のAndroidランチャーアイコンサイズ

ランチャーアイコンを作成する際のサイズについて。

解像度によって、ランチャーアイコンのサイズは異なります。
ldpi (120 dpi) 36 x 36 px
mdpi (160 dpi) 48 x 48 px
hdpi (240 dpi) 72 x 72 px
xhdpi(320 dpi) 96 x 96 px


解像度によりサイズが変わる仕組みはこちら。


以上です。

2011/12/20

Android:プロセスが使用しているメモリ使用量のランキングを調べる方法


各プロセスが使用しているメモリ使用量のランキング上位を表示する方法です。
procrankコマンドで調べることができます。

# procrank

  PID      Vss      Rss      Pss      Uss  cmdline
  128   49064K   49064K   18013K   13896K  com.android.systemui
   74   47636K   47636K   17095K   13852K  system_server
  170   47644K   47644K   14781K    9856K  com.android.launcher
  224   45556K   45556K   14635K   10960K  android.process.acore
  157   39952K   39952K   10902K    8664K  com.android.phone
   35   39328K   39328K    8117K    4800K  zygote
  375   37096K   37096K    8011K    5620K  com.android.email

以上です。

Android:UIDを調べる方法


プロセスのUIDを調べる方法。
adb shellモードに入ってpsコマンドを発行。

# ps

下記のような結果が得られる。

USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
system    198   35    129244 33328 ffffffff 40011384 S com.android.settings
app_9     224   35    145148 45552 ffffffff 40011384 S android.process.acore
app_0     244   35    128604 33296 ffffffff 40011384 S com.android.calendar
app_15    277   35    125664 32712 ffffffff 40011384 S com.android.deskclock

今回はacoreのUIDを調べてみます。
psコマンドの結果からacoreのUSERが"app_9"であることがわかります。
続いてsuコマンドでユーザ切替。

# su app_9

続いてidコマンドを発行することでUIDがわかります。

$ id

実行結果は下記。acoreのUIDは10009のようです。

uid=10009(app_9) gid=10009(app_9)

以上です。
2011/12/16

onPause中にアプリが突然killされるケース

ActivityのonPause処理中に突然プロセスkillされることがあります。
つまりonPauseが完走しないケースが"あり得る"ということです。

プロセスをkillするのはLowMemoryKiller。
LowMemorykillerはフォアグラウンドプロセスをkillすることもありますが、ごく稀です。
killされる可能性が高くなるのはアプリがバックグラウンドにまわったpause状態の時。
Activityはforeground状態よりもpause状態の方がkillされる可能性がぐんと上がります。
通常、Activityがpause状態に遷移するのはonSavedInstance~onPauseが終わった後です。
しかし例外があります。

onSavedInstance開始~onPause終了に500msec以上かかった場合、ActivityManagerはActivity
のonPause完了を待たずにpause状態へと無理やり遷移させます。
その際下記のようなログがmainログに吐かれます。

W/ActivityManager(86): Activity pause timeout for ActivityRecord{ ... }

そのため、onPauseメソッドはActivityのpause状態で実行されることがあり、
onPauseの途中でプロセスがkillされてしまうとonPauseが完走しません。

とはいえ、バックグラウンドで10以上のアプリを起動していたりする場合に起こり得るケースで
あるため、これも稀なケースと言えます。


Androidでスクリーンセーバを試す



Androidの小ネタです。

intentにはDREAMというカテゴリがあります。
これはパソコンでいうところのスクリーンセーバに属するカテゴリです。

エミュレータでも、adbシェルで下記を実行することでスクリーンセーバ「Rocket Launcher」が起動します。

# am start -a android.intent.action.MAIN -c android.intent.category.DREAM

下記のようなスクリーンセーバアプリが起動します。


以上です。

2011/12/15

ハードウェアアクセラレーションのメリットとデメリット

Android3.0より、ハードウェアアクセラレーション機能のON/OFFが指定できるようになりました。
この機能がONの場合は、Canvas、SurfaceViewやOpenGLなどの描画をGPUで実行するようになります。
ハードウェアアクセラレーション機能を使用することで描画パフォーマンスの向上が期待できます。
逆にTextViewやDrawableに対しては効果が期待できません。

下記はApplicationタグへの指定例です。
※この機能はapplicationまたはactivityタグに指定できます。

<application
    android:hardwareAccelerated="true" >

しかし、デメリットもあります。
ハードウェアアクセラレーション機能はメモリをより多く消費します。
これは、CanvasやSurfaceViewを使用している場合に限らず、TextViewやDrawableしか使用していないような
シンプルなアプリでも、機能ONであればメモリ消費量が増えてしまいます。

ハードウェアアクセラレーション機能はデフォルトでONです。
そのため、メリットとデメリット、自アプリの特徴を把握した上でハードウェアアクセラレーション機能を使用するか
しないかを考え、使用しない場合は明示的に機能OFFとする必要があります。

以上です。
2011/12/12

Androidでパケットログを取得する方法

アンドロイドの通信ログ(パケットログ)を取得する方法です。

下記のコマンドを発行するとログキャプチャ待機状態になります。

adb shell tcpdump -s 0 -v -w /data/tcp.pcap

待機状態でブラウザ等から通信を行うとパケットログが取得できます。
パケットログ取得を終了するにはCtrl+C。

取得したパケットログは上記コマンドの場合は /data/tcp.pcap に保存されます。
これをpullしてワイヤーシャークなどで実行すればパケットログ解析が可能です。



以上です。

2011/12/11

ファイルシステムの情報、空き容量を取得する方法

コード上でファイルシステムの情報や空き容量を取得するにはStatFSが使用
できます。

android.os.StatFsには下記のメソッドが用意されています。
・public StatFs (String path)
 ⇒コンストラクタ。指定したパスのファイルシステムがStartFsの対象とな
  ります。

・public int getAvailableBlocks ()
 ⇒指定したファイルシステムでアプリケーションが利用できる領域のブロ
  ックサイズを返します。

・public int getFreeBlocks ()
 ⇒指定したファイルシステムで利用できる領域のブロックサイズを返します。
  返されるブロックにはアプリケーションから利用できない領域を含みます。

・public int getBlockCount ()
 ⇒ファイルシステムの総ブロック数を返します。

・public int getBlockSize ()
 ⇒ファイルシステムのブロックサイズを返します。単位はByte。

一般アプリでファイルシステムの空き容量を調べる場合はgetAvailableBlocks
を使用します。getFreeBlocksは常用外です。

それぞれの容量を調べる場合はブロック数とブロックサイズの積を求めます。

StatFs sf = new StatFs("/mnt/sdcard/");
int kb = sf.getAvailableBlocks() * sf.getBlockSize() / 1024;
android.util.Log.e("yuki", "yuki KB=" + kb);

参考:http://developer.android.com/reference/android/os/StatFs.html#getAvailableBlocks()

以上です。

HoloテーマとDeviceDefaultテーマについて

アクティビティに指定するテーマについて。

android4.0以前はTheme.Blackが用意されていました。
Theme.Blackはデフォルトテーマとして設定され、アプリの見た目のベースとなります。
しかし、テーマは各メーカーや端末によってカスタマイズされています。
そのため、端末によっては見た目に差が出てしまうことがあります。

android4.0以降はホログラフィックテーマ用にTheme.Holoが用意されています。
このテーマはカスタマイズしてはいけないルールとなっており、端末によって見た目が
変わらないことが保証されています。

android4.0以降、メーカーや端末特有のテーマはDeviceDefaultに置き換えられています。
DeviceDefaultはGoogleから端末開発者向けに用意されたテーマです。

ホロテーマを適用したい(端末間での見た目を統一したい)場合はTheme.Holoを、
端末固有のテーマを適用したい場合はTheme.DeviceDefaultを適用します。

適用のサンプルは下記。

<style name="TestTheme"
        parent="@android:style/Theme.Holo">

以上です。
2011/12/07

アプリ起動の高速化:windowDisablePreview

スタイルの属性にwindowDisablePreviewというものがあります。

アプリを起動する際、アプリに黒系統のテーマ(Theme.Black, Theme.Holo)が適用されている場合は一瞬画面
が黒くなってからアプリが起動されます。
アプリに白系統のテーマ(Theme.Light, Theme.Holo.Light)が適用されている場合は一瞬画面が白くなってから
アプリが起動されます。

この現象は、アプリの起動パフォーマンスに問題を抱えていないアプリの場合確認が困難なぐらい一瞬です。
しかし、アプリの起動パフォーマンスに問題を抱えているアプリの場合は、ユーザがそれを認識(秒単位で)できる
ほどになります。

この画面が黒(あるいは白)くなる現象は、ユーザへのアプリ起動開始を通知する役目を担っています。
つまり、アプリの起動が非常に遅い(ランチャーアイコンをタップしても中々起動してこない)場合にユーザ
へのレスポンスタイムを縮める効果があります。

しかし、ユーザの操作なしにバックグラウンドから起動されるようなケースで、この効果を邪魔に感じる場合は
効果をOFFにすることが可能です。

下記のようにwindowDisablePreviewにtrueを設定したスタイルをactivityや
applicationに適用します。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="TestTheme"
            parent="@android:style/Theme.DeviceDefault">
        <item name="android:windowDisablePreview">true</item>
    </style>
</resources>

上記はメリットとデメリットを把握した上で使うのが重要です。
一見するとアプリのパフォーマンスが向上したように感じられますが、前述した通りレスポンスタイムは遅くなります。
windowDisablePreviewをtrueとすれば、ユーザはアプリが起動中であると認識できるタイミングは遅くなりますが、
アプリ起動中の黒(白)画面が表示されなくなるためユーザに起動中であることを気取られず高速起動したように見えます。

ランチャーアイコンから起動されるActivityには不向きと言えるでしょう。

以上です。
2011/12/06

SDカードのマウント、リマウント時にメディアストレージパスを意識する

SDカードのマウント、リマウント時に発行されるACTION_MEDIA_*系のブロードキャストインテントについて。
onReceiveで受け取る引数intentのdataにはマウントorリマウントされたストレージのパスが格納されています。
通知されるパスは下記のようなコードで確認できます。
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Uri data = intent.getData();
        String path = null;
       
        if (data != null) {
            path = data.getPath();
        }
        android.util.Log.e("test", "path=" + path);

        if ("/mnt/sdcard/xxx".equals(path)
                && Intent.ACTION_MEDIA_EJECT.equals(intent.getAction())) {
            // ...
        }
    }
};

@Override
protected void onResume() {
    super.onResume();
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_MEDIA_EJECT);
    filter.addDataScheme("file");
    registerReceiver(mReceiver, filter);
}
Galaxy Nexusなど、端末の内部ストレージとしてSDがマウントされているものが発売される傾向にあります。
クラウドの流行も後押しし、今後はmicroSDが搭載されない端末や内蔵ストレージ搭載の端末が増えてくるもの
と思われます。

内部ストレージ以外の他メディアがマウントされた場合もACTION_MEDIA_*系の通知がくるため、
異なるメディアストレージのパスに対して処理されるのが困るようなケースでは
Environment.getExternalStorageDirectory()等を利用してパスのチェックを行うのが良いでしょう。

2011/12/05

android4.0をダウンロードする方法(エラー対処編)

以前に書いたandroid4.0をダウンロードする方法について、
いざダウンロードを開始しても途中でダウンロードが停止してしまう現象が頻発しました。
そういう場合はsyncのジョブ数を1で実行すると解決するかもしれません。

具体的なコマンドは下記です。

1. repoコマンドのインストール
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo

2. repoコマンドのパーミッション変更
$ chmod a+x ~/bin/repo

3. repoコマンドの初期化
$ mkdir ~/android_src/
$ cd ~/android_src/
$ ~/bin/repo init -u https://android.googlesource.com/platform/manifest

4. ソースコードをダウンロード
$ ~/bin/repo sync -j1

おおよそ半日ほどでダウンロードは完了します。

以上です。
2011/12/03

onRetainNonConfigurationInstance考察

【一般的なライフサイクル(上から順に...)】
onCreate
onStart
onRestoreInstanceState
onResume
onSaveInstanceState
onPause
onStop
onRetainNonConfigurationInstance
onDestroy

【アクティビティの状態】
起動:onCreate~onResume
背面へ移動:onSaveInstanceState~onPause
停止:onStop
破棄:onDestroy

onSaveInstanceStateとonRetainNonConfigurationInstanceについて、
onRetainNonConfigurationInstanceは特別な理由がない限り画面回転用に使用します。
Activity再起動時に必要なデータはonSaveInstanceStateでBundleに格納します。

理由としてはそれぞれのAPIが呼ばれるタイミングにあります。
アプリ使用中に音声着信が割り込んだ場合を考えましょう。
音声着信割り込みで自身のActivityが背面へ移動する際にonSaveInstanceStateは呼ばれます。
つまりは、アプリの状態を保存するタイミングがあるということです。

次にonRetainNonConfigurationInstanceを考えてみましょう。
音声着信割り込みで自身のActivityが背面へ移動する際にはまだonRetainNonConfigurationInstanceは
呼ばれません。
つまり、このタイミングではアプリの状態を保存することができないということです。

注意しないといけないのは、Activityがシステムよりkillされること。
Activityが背面に回るとRUNNINGからPAUSE状態に遷移し、killされる可能性が上がります。
killされた場合はライフサイクル遷移しないためonRetainNonConfigurationInstanceは呼ばれません。

onRetainNonConfigurationInstanceについては下記のサイトが参考になります。
http://www.techdoctranslator.com/resources/articles/articles-index/faster-screen-orientation-change