2011/12/20

AndroidでPhoneとTabletを見分ける方法

Android4.0が出て、4.0.3が出て、対応端末もリリースされ、その端末がPhoneなのかTabletなのかを見分けるって結構重要ですよね。Androidのソースコードを元にPhoneとTabletを見分ける方法の紹介です。


・~Android 3.1
Build.SDK_INT見る。ハニカム以上ならタブレット


・Android 3.1~
この様にリソースにBooleanを定義しておいて、 こんな感じ。PhoneでもWXGAの端末が出てきたりして画面ピクセル数による見分けも出来なくなった今日この頃、PhoneとTabletの最大の違いはPhoneはhdpi(1:1.5)~xhdpi(1:2)なのに対してTabletは総じてmdpi(1:1)で画面に表示出来る内容が多いこと。同じ720pxでもPhoneは360dpなのに対してTabletは720dpとして利用できます。


結論:

2011/12/17

他パッケージ(APK)のclassファイルを読み込む

ちょっと興味があって調べてみた。


結論としては
  • 他のパッケージのクラスファイルは読み込める
  • セキュリティー的に問題あるんじゃね?

某ブログには
  • SharedUserIdを共有して
  • 共有Contextを作成すればできる
なんて書いてあるけどこれは嘘。以下、その方法

まずAndroidの標準的なリソース共有方法であるContextの共有から調べてみた。 これでClassを作成しようとすると怒られます。
。。。ん?
この部分が怪しい。
と言うわけでdalvik.system.PathClassLoaderをちょっと見てみると、 mDexとかmZipとか、何となくAPKパッケージを探していそう。コンストラクタを見てみると ビンゴですね。「:」で第一引数を区切ってそこからdexファイルを取得しようとしています。
PathClassLoaderを生成するときの第一引数はクラス名ではなくAPKファイル名を指定しなければいけないようです。


つまりこういうこと

実際にやってみて驚いたのが、これを実行するのにSharedUserIdが同一である必要は無いし、電子署名が一致してる必要も無いこと。これで既存アプリの中身に直接アクセス出来ちゃいます。
試してはいませんが、リソースにもこれで直接アクセス出来てしまうのかもしれませんね。

ちなみにAndroid4.0でこのPathClassLoaderの継承元がjava.lang.ClassLoaderからdalvik.system.BaseDexClassLoaderに変わっているため、同じ方法でアクセス出来ないかもしれません。要注意。これから調べる。
どうやらAndroid4.0でもいけるっぽい? ソースコードぱっと見アウトに思えたけど、API14エミュで動いた。

最後に、例に挙げているjp.co.noxi.weathernow.Commonは実際のアプリには存在しないクラスです

2011/12/16

TextViewに適切なサイズを指定する

JavaからTextViewを生成するとき。。。テキストサイズ、なんかおかしくね?、って思ったことありませんか?
特にXMLリソースでDimensionを設定しこれをJavaで取得してTextViewに適応するとき「フォントサイズでかくね?」って思うことありませんか?


TextView#setTextSize(float)がやっていることって実は 内部でSPをちゃんとかけてます。まぁ、ちゃんとJavaDoc読めば

This size is adjusted based on the current density and user font size preference.

って書いてあるんですけどね。。。
ちなみにsetTextSize(int, float)で利用されているTypedValue#applyDimensionは
らしいので、純粋にXMLで設定したDimensionをJavaから設定するには こんな感じで指定すればいいらしい。

ただしsetTextSize(int, float)が利用できない場合は きれいじゃ無いけどしょうが無いよねっ!


ちなみにdpとspの違いは、dpは画面解像度に対してのみで決定されるのに対し、spは更にユーザーが設定に応じて倍率が変更されるらしいです。
IS05にはその倍率設定画面が見当たらないけど。。。

2011/12/06

PreferenceActivityのHeader画面でカテゴリーも表示する

API11(Android3.0)から実装されたPreferenceActivity$Header
HeaderとPreferenceFragmentを利用した設定画面の作成方法はこちらの記事で紹介した感じで簡単に作れます。

ところで。。。このHeader画面にカテゴリー表示ってどうやんの?っていう疑問。Android標準の設定画面はカテゴリー作ってんじゃんブーブー、的な。
Androidのソースコードを読んだ感じでは、標準で用意されているHeader用のListAdapterを上書きする必要があるようです。Android2.xとのCompatも含めて、以下、その方法。
ほとんどAndroidのソースコードコピペっただけですが・ω・


Header部分を構成するPreferenceなXML。
Android3.0~のXMLではカテゴリーで表示したいheaderタグにfragmentまたはintentを属性設定しないこと。

次にAndroid2.x用ヘッダー画面。
PreferenceFragmentとの共用クラス作った時とここまでは同じ。

ここからAPI11以上用のファイル達
Androidの内部リソースにアクセス出来ないため、ヘッダーで利用されているレイアウトXMLを自前で用意する必要があります。

PreferenceHeaderを表示するActivity

2011/12/05

メモ的 DialogPreference

android.preference.DialogPreferenceを利用してちょっと遊んでみた。


WeatherNow 1.6だか2.0だかではAppWidget背景の透過率を従来の10%単位から1%単位での設定に変更します。設定画面でPreferenceクリックしたらダイアログ出して、ダイアログの中でシーク+ボタン+直接入力で透過率設定出来たら便利だよね?!ってことで作ってみた。

DialogPreferenceを継承する上で重要なDialogの表示部分ですが、Androidのソースコード(4.0.1)ではこんな感じになってます。


ダイアログの表示部分自体を変えたければこのshowDialogを、ダイアログで表示する中身を変えたければonPrepareDialogBuilderを、ダイアログが閉じられたときの挙動を変えたければonClickやonDialogClosedをオーバーライドすればいいっぽいです。


そんなわけで、作ってみた。最終的なViewのアウトプットはこんな感じ。