2011年2月26日土曜日

Android Dialog のタイトル部分をなくす

Dialog クラスのインスタンスを生成して、ダイアログを作った場合


ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.bg);

Dialog dialog = new Dialog(this);
dialog.setContentView(imageView);
dialog.show();


setTitle() でタイトルを設定しなくてもタイトル部分が表示されてしまいます。



ちなみに、ProgressDialog の場合は、setTitle() を呼ばなければタイトル部分は表示されません。

Dialog でタイトル部分を消すには、requestWindowFeature() で Window.FEATURE_NO_TITLE を指定します。


ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.bg);

Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(imageView);
dialog.show();


requestWindowFeature() は setContentView() より前に呼ぶ必要があります。

Android style で windowBackground を設定するときの注意点

これはOK


<item name="android:windowBackground">@drawable/bg_blue</item>


だけど、これはダメ


<item name="android:windowBackground">@color/blue</item>


values/colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="blue">#0000ff</color>
<drawable name="bg_blue">#0000ff</drawable>
</resources>


逆に、android:colorBackground の場合は

これがダメで、


<item name="android:colorBackground">@drawable/bg_blue</item>


こっちが OK


<item name="android:colorBackground">@color/blue</item>



 

2011年2月25日金曜日

Android 別々のアプリで SharedPreferences を共有

SharedPreferences を作成するときには、ファイル作成のモードとして以下の4つが選択できます。

MODE_PRIVATE (0x00)
 ファイル作成モード
 デフォルトのモード
 getSharedPreferences を呼んだ(= ファイルを作成した) アプリケーションからのみアクセスできる(ただし、同じ user ID を共有しているアプリケーションもアクセスできる)

MODE_WORLD_READABLE (0x01)
 ファイル作成モード
 他の全てのアプリケーションが読み込みアクセス権限をもつ

MODE_WORLD_WRITEABLE (0x02)
 ファイル作成モード
 他の全てのアプリケーションが書き込みアクセス権限をもつ

MODE_MULTI_PROCESS (0x04)
 SharedPreference の読み込みフラグ
 たとえプロセス内ですでに shared preferences インスタンスがロードされていても、編集のためにディスク上のファイルをチェックする。複数のプロセスをもつアプリケーションで、それらが同じ SharedPreferences ファイルに書き込みをする場合に必要となる。

# MODE_MULTI_PROCESS は API Level 11 (= Android 3.0 で追加されたAPI) です。

getSharedPreferences の第2引数に上記のモードを設定します。

SharedPreferences mSharedPreferences = getSharedPreferences("yanzm_name", MODE_WORLD_READABLE);
Editor prefsPrivateEditor = mSharedPreferences.edit();
prefsPrivateEditor.putString("name", "yanzm");
prefsPrivateEditor.commit();


この yanzm_name という SharedPreference ファイルを別のアプリケーション (= 別のパッケージ) から読むには、yanzm_name を作成したパッケージの Context を生成する必要があります。


try {
Context mContext = createPackageContext("yanzm.example.hoge", CONTEXT_RESTRICTED);

SharedPreferences mSharedPreferences = mContext.getSharedPreferences(
"yanzm_name",
Context.MODE_PRIVATE);

String name = mSharedPreferences.getString("name", "");
} catch (NameNotFoundException e) {
Log.e("SharedPref", e.getLocalizedMessage());
}


createPackageContext() で SharedPreference を作ったパッケージの Context オブジェクトを作成します。


createPackageContext (String packageName, int flags)

 起動時と同じ Context を返す
 同じリソース、クラスローダーを含む
 このメソッドの呼び出しごとに新しい Context オブジェクトのインスタンスを返す
 Context オブジェクト自体は share されないが、common state (Resources, ClassLoader など) は share するので、Content instance 自身はとても軽量

第1引数にはアプリケーションのパッケージ名を指定します。
パッケージ名に相当するアプリない場合 PackageManager.NameNotFoundException
が発行されます。

第2引数に設定するフラグには次の3つがあります。

CONTEXT_INCLUDE_CODE (0x01)
 アプリケーションコードを含む Context
 つまり、呼んだプロセス内にコードがロードされるので、アプリケーションのクラスをインスタンスするのに getClassLoader() を使うことができる。このフラグをセットすることでどのアプリケーション Context にアクセスできるかのセキュリティ制限を設定する。リクエストしたアプリケーションがプロセスにとって安全ではない場合 java.lang.SecurityException が発行される。このフラグがセットされていない場合、ロード可能なパッケージ上に制限はないが、 getClassLoader() は常にデフォルトシステムの class loader を返す。

CONTEXT_IGNORE_SECURITY (0x02)
 要求されている Context 上のすべてのセキュリテイ制限を無視し、常にロードを許可する。CONTEXT_INCLUDE_CODE と一緒に使うと、たとえそれが安全でなくても、プロセス内にコードがロードされるので、使うときは十分注意すること!
 
CONTEXT_RESTRICTED (0x04)
 特定の機能が無効になった制限された Context
 例えば、制限された Context に関連する View は特定の XML 属性を無視する

このフラグの設定とアプリケーションの SharedUserId によっては java.lang.SecurityException が投げられます。


ShareUserId が違う場合で試してみました。

その1 CONTEXT_INCLUDE_CODE だけ --- SecurityException

Caused by: java.lang.SecurityException: Requesting code from yanzm.example.hoge (with uid 10117) to be run in process yanzm.example.hogehoge (with uid 10064)

その2 CONTEXT_INCLUDE_CODE | CONTEXT_RESTRICTED --- SecurityException

Caused by: java.lang.SecurityException: Requesting code from yanzm.example.hoge (with uid 10117) to be run in process yanzm.example.hogehoge (with uid 10064)

その3 CONTEXT_RESTRICTED だけ --- OK

その4 CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY --- OK

その5 CONTEXT_IGNORE_SECURITY だけ --- OK



 

2011年2月23日水曜日

Android 3.0 Platform - 3 -

長いので分割します。
ここには、以下が含まれます。

 ・Graphics
 ・Media
 ・Keyboard support
 ・Split touch events
 ・WebKit
 ・Browser
 ・JSON utilities

Android 3.0 Platform - 1 -
Android 3.0 Platform - 2 -
Android 3.0 Platform - 3 -

---------------------------

Graphics

■ Hardware accelerated 2D graphics :
 2D グラフィックスのハードウェアアクセラレーション

マニフェストの <application> エレメント、もしくは個々の <activity> エレメントで android:hardwareAccelerated="true" を設定することで アプリケーションの OpneGL renderer を有効にできるようになった。

このフラグはより速く描画を行うことによって、アプリケーションを支援します。この結果はよりスムーズなアニメーション、スムーズなスクロール、全体のパフォーマンスの改善とユーザーインタラクションへのレスポンスの改善として現れます。


■ ハードウェアとソフトウェアレイアーに対する View サポート
 View support for hardware and software layers

デフォルトでは、View は特定のレイヤーを持っていません。setLayerType() もしくは layerType 属性を使って、 LAYER_TYPE_HARDWARELAYER_TYPE_SOFTWARE 値によって指定されるハードウェアまたはソフトウェアレイヤーに View をバックアップするよう指定できるようになりました。

ハードウェアレイヤーはハードウェア固有のテクスチャ(一般的には OpenGL ハードウェア上での Frame Buffer Object か FBO)でバックアップされ、Android のハードウェアレンダリングパイプラインを使ってレンダリングされる View を引き起こすが、ハードウェアアクセラレーションは View の階層に対してのみオンになる。ハードウェアアクセラレーションがオフになっている場合、ハードウェアレイヤーは完全にソフトウェアレイヤーとして振舞う。

ソフトウェアレイヤーはビットマップによってバックアップされ、ハードウェアアクセラレーションが有効になっていても、Android のソフトウェアレンダリングパイプラインを使ってレンダリングされる View を引き起こす。View 階層の頻繁なアップデートの影響をうける場合、ソフトウェアレイヤーは避けるべきである。毎回のアップデートはソフトウェアレイヤーの再レンダリングを要求するので、潜在的に遅くなる可能性がある。

より詳しい情報は、LAYER_TYPE_HARDWARELAYER_TYPE_SOFTWARE ドキュメントを見てください。

■ レンダースクリプト 3D グラフィックスエンジン :
 Renderscript 3D graphics engine

レンダースクリプトは 3D シーンを構築する API と、最高のパフォーマンスを得るためのプラットフォームに依存しないシェーダー言語の両方を提供する ランタイム 3D フレームワークです。レンダースクリプトを使用することで、グラフィック操作とデータ解析をアクセラレートできます。レンダースクリプトはアプリケーション、壁紙、カルーセルなどにハイパフォーマンスの 3D エフェクトを作成する理想的な方法です。

より詳しい情報は 3D Rendering and Computation with Renderscript ドキュメントを見てください。

---------------------------

Media

■ Time lapse video

Camcorder API が time lapse video の録画をサポートするようになりました。 setCaptureRate() でどのフレームをキャプチャーするか設定できます。

■ Texture support for image streams

新しい SurfaceTexture によって OpenGL ES テクスチャとしてイメージストリームをキャプチャーできるようになりました。Camera インスタンスに対して setPreviewTexture() を呼ぶことで、どの SurfaceTexture にカメラからのビデオプレイバックやプレビューフレームを描画するか指定できます。

■ HTTP Live streaming

アプリケーションは HTTP ライブストリーミングセッションを開始するために、メディアフレームワークに M3U プレイリストを投げることができるようになりました。メディアフレームワークはほとんどの HTTP ライブストリーミングの仕様(ビットレートの適用を含む)をサポートします。より詳しい情報は、Supported Media Formats ドキュメントを見てください。

■ EXIF data

ExifInterface は絞り(photo aperture), ISO, 露光時間(exposure time) 用の新しいフィールドを持つようになりました。

■ Camcorder profiles

新しい hasProfile() メソッドといくつかのビデオ画質プロファイル(QUALITY_1080P, QUALITY_720P, QUALITY_CIF, など) によって、camcorder の画質オプション決定できるようになりました。

■ Digital media file transfer

新しいプラットフォームでは USB を介した Media/Picture Transfer Protocol (MTP/PTP) をビルドインでサポートします。これにより、ユーザーは簡単にいろんなタイプのメディアファイルをデバイスとホストコンピュータ間で転送できるようになります。開発者は、ユーザーがデバイス間で転送したりシェアしたりしたくなる、リッチなメディアファイルを作成・管理するアプリケーションをこのサポートの上に作成することができます。

■ Digital rights management (DRM)

デジタル著作権をチェックし管理する、新しい拡張可能な digital rights management (DRM) フレームワークです。これは 2 つのアーキテクチャ層に実装されています。

  ・DRM フレームワーク API。これは、アプリケーションに公開されていて、標準のアプリケーションとして Dalvik VM を通して動く。

  ・DRM マネジャーのネイティブコード。これはフレームワーク API を実装し、著作権の管理と、いくつかの DRM スキームの複合をハンドルする DRM プラグインのインタフェースを公開する。

アプリケーション開発者に対して、保護されたコンテンツの管理を簡単にするための統一された抽象 API を公開します。APIは DRM 操作の複雑さを隠蔽し、保護されている・保護されていないコンテンツ両方に対して、またいくつかの DRM スキームに渡って、同じ操作モードを許可します。

デバイスメーカー、コンテンツオーナー、インターネットデジタルメディアプロバイダーにたいして、 DRM フレームワークプラグイン API はコンテンツ保護の安全な実施のために、Androidシステムに最適のDRMスキーマのサポートが追加されることを意味します。

プレビューリリースではデジタル著作権をチェックし管理するためのネイティブの DRM プラグインは提供されていません。しかし、デバイスメーカーは彼らのデバイスに DRM プラグインを付加して出荷できます。

全ての DRM API は android.drm パッケージで見ることができます。

---------------------------

Keyboard support

■ Control, Meta, Caps Lock, Num Lock, Scroll Lock のサポート。より詳しい情報は META_CTRL_ON と関連するフィールドをみてください。

■ フルデスクトップスタイルのキーボードのサポート。Escape, Home, End, Delete, その他のキーのサポートを含む。キーイベントがフルキーボードのものかどうかは、getKeyboardType() で判別でき、どのキーが押されたかは KeyCharacterMap.FULL を使ってチェックできる。

■ TextView が Ctrl+X, Ctrl+C, Ctrl+V, Ctrl+A のキーの組み合わせによるキーボードベースの cut, copy, paste, select-all をサポートするようになりました。さらに PageUp/PageDown, Home/End, キーボードベースのテキスト選択もサポートするようになりました。

■ キー修飾子の状態を正しく一貫して簡単にチェックするための、いくつかの新しいメソッドが KeyEvent に追加されました。hasModifiers(int), hasNoModifiers(), metaStateHasModifiers(), metaStateHasNoModifiers() を見てください。

■ アプリケーションは Activity, Dialog, もしくは View をサブクラス化し、onKeyShortcut() を実装することでカスタムキーボードショートカットを実装することができます。フレームワークは Ctrl キーと組み合わせてあるキーが押されたときにこのメソッドを呼びます。Option Menu の生成時に、android:alphabeticShortcut もしくは android:numericShortcut 属性を各 <item> エレメントに設定する (もしくは setShortcut() を呼ぶ)ことで、キーボードショートカットを登録することができます。

■ Android 3.0 には id が KeyCharacterMap.VIRTUAL_KEYBOARD である、新しい "virtual keyboard" デバイスが含まれています。virtual keyboard はデスクトップスタイルの US キー配置で、入力をテストするためのキーイベントを合成するために有用です。

---------------------------

Split touch events

以前は、1度に 1つのビューのみがタッチイベントを受けることができました。Android 3.0 では複数の View や Window でタッチイベントを分割するためのサポートが追加されました。つまり、異なる View で同時にタッチイベントを受けることができるということです。

タッチイベントの分割は Android 3.0 をターゲットとしたアプリケーション (つまり、android:minSdkVersion もしくは android:targetSdkVersion 属性の値が "11" のアプケーション) では、デフォルトで有効になっています。

しかし、以下のプロパティを設定することで、特定の View Group 内やウィンドウ内でタッチイベントの分割を無効にすることができます。

■ View Group に対して android:splitMotionEvents 属性を指定することで、その子 View の間でのタッチイベントの分割を無効にできます。
例えば :

<LinearLayout android:splitMotionEvents="false" ... >
...
</LinearLayout>

この場合、linear layout の子 View はタッチイベントを分割できません。つまり、1度に1つの View だけたタッチイベントを受信できます。

■ android:windowEnableSplitTouch スタイルプロパティを指定することで、ウィンドウをまたいだタッチイベントの分割を無効にすることができます。これは、Activity もしくはアプリケーション全体のテーマに適用します。
例えば :

<style name="NoSplitMotionEvents" parent="android:Theme.Holo">
<item name="android:windowEnableSplitTouch">false</item>
...
</style>

このテーマが <activity> もしくは <application> に適用された場合、タッチイベントは現在の Activity ウィンドウ内でのみ受信できます。例えば、ウィンドウをまたいだタッチイベントを無効にすると、システムバーは Activity と同時にタッチイベントを受信することができなくなります。これは Activity 内の View がタッチイベントを分割できるかどうには影響しません。デフォルトでは Activity は View をまたいだタッチイベントを分割することができます。
テーマを作成のより詳しい情報は Applying Styles and Themes を読んでください。

---------------------------

WebKit

WebView のフラグメント構成を作成するための新しい WebViewFragment クラス

■ 新http://www.blogger.com/img/blank.gifしい WebSettings メソッド:

  ・setDisplayZoomControls() によって、ユーザーがフィンガージェスチャーでズームしている間、画面上のズームコントロールを隠すことができる(setBuiltInZoomControls() は true に設定されていなければならない)。

  ・新しい WebSettings メソッド の setEnableSmoothTransition() は、画面の拡大・縮小時のスムーズな遷移を有効にする。有効にした場合、WebView パフォーマンスを最大にする解決方法を選択する (例えば、WebView は遷移の間アップデートされなくなる)。

■ 新しい WebView メソッド:

  ・onPause() コールバックは、WebView が隠れるときに関連する処理を一時停止する。これは WebView が前面にない場合に必要のない CPU やネットワークトラフィックを削減するのに有用である。

  ・onResume() コールバックは、onPause() で一時停止された WebView に関連する処理を再開する。

  ・saveWebArchive() によって現在の View を web archive としてデバイス上に保存できる。

  ・showFindDialog() 現在の View のテキスト検索を開始する。


---------------------------

Browser

ウェブアプリケーションをサポートするために、ブラウザアプリケーションは次の機能を追加します。


■ Media capture

HTML Media Capture 仕様で定義されているように、ブラウザはウェブアプリケーションにデバイスのオーディオ、画像、ビデオキャプチャー機能へのアクセスを許可します。例えば、以下の HTML はユーザーがアップロードする画像を選択するための入力を提供します。


<input type="file" accept="image/*;capture=camera" />


もしくは capture=camera パラメータを除くことで、ユーザーはカメラで新しい画像を撮影するか、デバイスから(ギャラリーアプリケーションなどから)選択するか選ぶことができます。

■ Device Orientation

Device Orientation Event 仕様で定義されているように、ブラウザはデバイスの物理的な向きや動きの情報を提供する DOM イベントをウェブアプリケーションが受信することを許可します。

デバイスの向きは x, y, z 軸で表現され、角度と動きは加速度と回転速度のデータとして表現されます。ウェブページは "deviceorientation" イベントタイプで window.addEventListener を呼ぶことで向きの変更イベントのリスナーを登録できます。また、"devicemotion" イベントタイプでモーションイベントのリスナーを登録できます。

■ CSS 3D Transforms


CSS 3D Transform Module
仕様で定義されているように、ブラウザは 3次元で変形させるための CSS によってエレメントをレンダリングすることを許可します。

---------------------------

JSON utilities

新しいクラス JsonReaderJsonWriter は JSON ストリームの読み書きを助けるクラスです。この新しい API はメモリ内のドキュメントを操作する org.json クラスを補完します。

コンストラクタメソッドを呼んで JsonReader のインスタンスを生成し、JSON 文字列のInputStreamReader を渡します。beginObject() を呼ぶことでオブジェクトを読み始めます。次のキーネームを読むには nextName() を、値を読むにはタイプに対応したメソッド、例えば nextString() や nextInt() などを呼びます。hasNext() が true の間これを続けます。

コンストラクタメソッドを呼んで JsonWriter のインスタンスを生成し、適切な OutputStreamWriter を渡します。そして、reader と似たようなマナーで JSON データを書いていきます。name() でプロパティ名を追加し、適切な value() メソッドで対応する値を追加します。

これらのクラスはデフォルトで厳格です。各クラスの setLenient() メソッドはこれらをより寛容になるように設定することができます。この lenient parse mode は org.json のデフォルトパーサーと互換性があります。

Android 3.0 Platform - 2 -

長いので分割します。
ここには、以下が含まれます。

 ・App widgets
 ・Status bar notifications
 ・Content loaders
 ・Bluetooth A2DP and headset APIs
 ・Animation framework
 ・Extended UI framework

Android 3.0 Platform - 1 -
Android 3.0 Platform - 2 -
Android 3.0 Platform - 3 -

---------------------------

App widgets

Android 3.0 はユーザーのホームスクリーン上でよりインタラクティブな app widget を実現するための、いつくかの新しい widget クラスをサポートします。これには GridView, ListView, StackView, ViewFlipper, AdapterViewFlipper などが含まれます。

より重要なのは、新しい RemoteViewService を使って content provider などから得られるリモードデータのコレクションを GridView, ListView ,StackView などの widget で実現できることです。

AppWidgetProviderInfo クラス (XML 内で <appwidget-provider> エレメントとして定義される) は 2 つの新しいフィールド: autoAdvanceViewIdpreviewImage をサポートします。autoAdvanceViewid フィールドでは、本来 app widget のホストによって auto-advanced される app widget subview の View ID を個別に指定することができます。previewImage フィールドは app widget がどのように見えるかのプレビューを指定し、このプレビューはユーザーが widget picker から選択するときに表示されます。このフィールドがサポートされていない場合、プレビューには app widget のアイコンが使われます。

プレビュー画像の作成を助けるために、Android のエミュレータには "Widget Preview" と呼ばれるアプリケーションが含まれています。プレビュー画像を作成するには、アプリケーションを起動し、あなたのアプリケーションの app widget を選択し、プレビュー画像で表示したい状態にセットします。そして、それを保存しあなたのアプリケーションの drawable リソースに置いてください。

この新しい app widget の機能の実装は StackView App WidgetWeather List Widget アプリケーションで見ることができます。

---------------------------

Status bar notifications

コンテンツとしてよりリッチなステータスバー通知をサポートするために、Notification API が拡張されました。また、新しい Notification.Builder クラスによってより簡単に Notification オブジェクトを作成できるようになりました。

新しい機能:

  ・setlargeIcon() を使うことで大きなアイコンによる通知がサポートされました。これは通常ソーシャルアプリケーションで通知元の人物のコンタクトフォトを表示する場合や、メディアアプリでアルバムのサムネイルを表示する場合などに使われます。

  ・setTicker() を使うことで、status bar ticker 内のレイアウトをカスタマイズできます

  ・よりインタラクティブな通知ウィジェットのために、カスタム通知レイアウトのサポートには、PendingIntent のボタンが含まれます。例えば、Activity をスタートさせずに通知から音楽のプレイバックをコントロールできます。

---------------------------

Content loaders

Loader クラスを使うことで新しい framework API では、データの非同期読み込みが簡単になりました。View や Fragment などの UI コンポーネントと組み合わせることで worker スレッドから動的にデータを読み込むことができます。CursorLoader サブクラスは ContentProvider でバックアップされたデータに対して、このような動作を実現するために特別にデザインされています。

必要なことは、新しい loader がリクエストされたりデータが変わった時に呼ばれるコールバックを受け取るための LoaderCallbacks インタフェースを実装し、initLoader() を呼んで Activity や Fragment に対して loader を初期化することだけです。

より詳しい情報は Loaders ドキュメントを読んでください。FragmentListCursorLoaderLoaderThrottle サンプルで loader を使うコード例をみることができます。

---------------------------

Bluetooth A2DP and headset APIs

接続された Bluetooth A2DP とヘッドセットプロファイルデバイスの状態を確認する API が追加されました。例えば、アプリケーションは 音楽を聴くために Bluetooth ヘッドセットが接続されているかどうか識別することができ、適切な通知をユーザーに行えます。また、アプリケーションはベンダー固有の AT コマンドに対するブロードキャストを受け取ることもでき、接続されたデバイスの状態(例えば、接続デバイスのバッテリーが少なくなったなど)をユーザーに通知することができます。

プロファイル定数として A2DP, HEADSET のいずれかと、Bluetooth client が接続・切断されたときに呼ばれるコールバックを受信する BluetoothProfile.ServiceListener を指定して getProfileProxy() を呼ぶことで、個々の BluetoothProfile を初期化することができます。

---------------------------

Animation framework

新しい柔軟性のあるアニメーションフレームワークによって、全てのオブジェクト (View, Drawable, Fragment, Object その他すべて) に対して任意のプロパティをアニメーションすることができます。これは、あるアニメーションのいくつかのアスペクトを定義することができるということです。例えば、

 ・期間 (Duration)
 ・繰り返し回数と振る舞い (Repeat amount and behavior)
 ・時間補間のタイプ (Type of time interpolation)
 ・複数のアニメーションを、同時・連続・指定した遅延後 に再生するように設定
 ・フレーム更新の遅延 (Frame refresh delay)

これらのアニメーションアスペクト、その他オブジェクトの int, float, 16進色 の値はデフォルトで定義できます。つまり、これらのタイプのフィールドを 1 つでも持つオブジェクトは、アニメーションとしてその値を時間に応じて変化させることができるということです。その他のタイプの値をアニメーションさせるには、そのタイプの値をどのように計算するのかを TypeEvaluator インタフェースを実装して、システムに伝える必要があります。

プロパティの値をアニメーションするのに使えるアニメ―タが 2 つあります。ValueAnimatorObjectAnimator です。ValueAnimator はアニメーションする値を計算しますが、アニメーションとして使われるプロパティや特定のオブジェクトを認識しません。これは単純に計算を実行するだけなので、更新を聞き、あなた自身のロジックでデータを処理しなければなりません。ObjectAnimator は ValueAnimator のサブクラスで、アニメーションさせるオブジェクトとプロパティを設定でき、全てのアニメーションワークをハンドルします。つまり、ObjectAnimator にアニメーションさせるオブジェクトと、時間に沿って変化させるオブジェクトのプロパティを与えるだけで、アニメーションが開始することができます。

加えて、LayoutTransition クラスを使って、Activity レイアウトに対して自動遷移アニメーションを作成することができます。レイアウトの一部として遷移を有効にするには、LayoutTransition オブジェクトを生成し、それを setLayoutTransition() で全ての ViewGroup にセットします。このグループにアイテムが追加されたり削除されたりしたときは、つねにデフォルトのアニメーションが走ります。カスタムアニメーションを指定するには、LayoutTransition の setAnimator() を呼んで ValueAnimator や ObjectAnimator などのカスタム Animator を提供します。

より詳しい情報は、Property Animation を見てください。アニメーション API を使ったいくつかのサンプルが API Demos アプリケーションにあります。

---------------------------

Extended UI framework

■ ListView と GridView での複数選択 :
 Multiple-choice selection for ListView and GridView

新しい CHOICE_MODE_MULTIPLE_MODAL モードを setChoiceMode() で指定することで、ListView と GridView で複数アイテムが選択できるようになりました。Action Bar と組み合わせて使用することで、ユーザーは複数のアイテムを選択でき、Action Bar (Multi-choice Action Mode に変わっている) 内のオプションのリストから実行するアクションを選択できます。

複数選択を有効にするには、setChoiceMode(CHOICE_MODE_MULTIPLE_MODAL) を呼び、setMultiChoiceModeListener()MultiChoiceModeListener を登録します。

ユーザーが long-press をアイテムに対して行うと、Action Bar は Multi-choice Action Mode に切り替わります。システムはアイテムが選択されたときに onItemCheckedStateChanged() を呼ぶことで MultiChoiceModeListener に通知します。

複数選択の例は API Demos サンプルアプリケーションの List15.java クラスを見てください。


■ View 変換の新しい API : New APIs to transform views

新しい API によって、あなたの Activity レイアウト内の View に、簡単に 2D, 3D 変換を適用できるようになりました。新しい変換は、レイアウトの位置、向き、透過度などを定義するオブジェクトプロパティのセットを可能にします。

View のプロパティを設定する新しいメソッドとして setAlpha(), setBottom(), setLeft(), setRight(), setPivotX(), setPivotY(), setRotationX(), setRotationY(), setScaleX(), setScaleY(), setAlpha(), その他、が含まれます。

いくつかのメソッドは対応する XML 属性をもっています。この属性をレイアウトファイルで指定するうことで、デフォルト変換として適用される値を設定できます。使用可能な属性として translationX, translationY, rotation, rotationX, rotationY, scaleX, scaleY, transformPivotX, transformPivotY, alpha があります。

これらの新しい View プロパティのいくつかを組み合わせて、上記の新しいアニメーションフレームワークで使用することで、簡単にファンシーなアニメーションをあなたの View に適用することができます。例えば、Y軸周りの View の回転をするには ObjectAnimator にその View と "rotationY" プロパティの開始値と終了値を与えるだけです。


ObjectAnimator animator = ObjectAnimator.ofFloat(myView, "rotationY", 0, 360);
animator.setDuration(2000);
animator.start();



■ 新しい holographic テーマ : New holographic themes

標準システムウィジェットと全体の見た目は再デザインされ、新しい "holographic" としてユーザーインタフェーステーマに組み込まれました。システムは標準の style and theme を使ってシステムにこの新しいテーマを適用します。

Android:minSdkVertion もしくは android:targetSdkVersion が "11" に設定された Android 3.0 platform 用のすべてのアプリケーションはデフォルトで holographic theme を継承します。しかし、もしアプリケーションが自身のテーマを適用するならば、そのテーマが holographic theme を継承したスタイルでない限り、holographic theme は上書きされます。
holographic theme を個々の Activity に適用する、もしくは自身のテーマで継承するには、いくつかの新しい Theme.Holo テーマのうち 1つを使います。もし、あなたのアプリケーションが Android 3.0 よりも低いバージョンと互換性があり、カスタムテーマを適用するならば、プラットフォームのバージョンに応じたテーマを選択しなければなりません。


■ 新しいウィジェット : New widgets

  ・AdapterViewAnimator
    View を切り替えるアニメーションを実行する AdapterView のベースクラス

  ・AdapterViewFlipper
    シンプルな ViewAnimator。これに追加された 2つ、もしくはそれ以上の View 間でアニメーションする。1度に1つの子要素しか表示できない。各子要素間で一定間隔で自動的にフリップするアニメーションをリクエストできる。

  ・CalendarView
    カレンダーをタッチすることでユーザーが日付を選択することができる。ウィジェット内の日付の範囲を設定することができる。
    
  ・ListPopupWindow
    EditText View でタイピング中に表示される候補リストのように、ホスト View をアンカーとして選択リストが表示される。

  ・NumberPicker
    事前に定義した範囲からユーザーが数字を選択できる。ウィジェットは入力フィールドと数字を選択するアップ・ダウンボタンを提供する。入力フィールドをタッチすることでユーザーは値をスクロールでき、さらにタッチすることで現在の値を直接編集できる。位置と文字列をマッピングすることができる。つまり、インデックス位置の変わりに対応する文字列を表示することができる。

  ・PopupMenu
    アンカーとなる View のモーダルポップアップウィンドウ内にメニューをを表示する。ポップアップはアンカー View の下に表示され、十分な room がない場合、上に表示される。もし IME (ソフトキーボード) が表示されていると、ユーザーがメニューをタッチするまで、ポップアップは IME にオーバーラップしない。

  ・SearchView
    Search Manager (これまでの検索ダイアログと同じマナー) を組み合わせて動く検索ボックスを提供する。最近のクエリーを候補として表示することができ、search provider を設定することで候補をカスタマイズできる。このウィジェットは Action Bar で検索を提供する場合に非常に便利である。

  ・StackView
    子要素を 3D スタックとして表示できる View。ユーザーは rolodex のように View をスワイプできる。



 

Android 3.0 Platform - 1 -

長いので分割します。
ここには、以下が含まれます。

 ・Fragments
 ・Action Bar
 ・System clipboard
 ・Drag and drop

Android 3.0 Platform - 1 -
Android 3.0 Platform - 2 -
Android 3.0 Platform - 3 -

---------------------------

Android 3.0 Platform

API Level: 11

Android 3.0 platform が Android SDK としてダウンロードできるようになりました。ダウンロードできる platform には Andorid のライブラリとシステムイメージ、エミュレータのスキンなどが含まれますが、外部ライブラリは含まれません。

Android 3.0 の開発とテストを開始するには Android SDK Manager を使って platform をあなたの SDK にダウンロードしてください。より詳しい情報は Adding SDK Components を見てください。もし Android 開発が初めてなら、 download the SDK Starter Package から初めてください。

Android 3.0 のよりハイレベルの紹介は Platform Highlights を見てください。

Note: すでに Android アプリケーションを公開している場合、できる限り早く、あなたのアプリケーションを Android 3.0 でテストし最適化してください。あなたのアプリケーションが最新の Android-powered デバイスでベストな体験ができることをユーザーに確約すべきです。そのために何ができるかのより詳しい情報は Optimizing Apps for Android 3.0 を見てください。

---------------------------

API Overview

以下のセクションは Android 3.0 で新しく追加された機能・以前のAPIから変更された内容のテクニカルオーバービューです。

---------------------------

Fragments

Fragment は新しいフレームワークコンポーネントです。これにより、自身の UI とライフサイクルを定義した self-contained なモジュールに Activityの異なるのエレメントを分離することができます。Fragment を作成するには、Fragment クラスを継承し、Activity に似たいくつかのライフサイクルコールバックメソッドを実装しなければなりません。複数の Fragment を合わせることで、1つの Activity 内で multi-pane UI を作成することができ、各 pane が自身のライフサイクルとユーザーの入力を管理します。

さらに、UIを提供しないで Fragment を使い、Activity が走っている間だけ発生する download の進捗管理など、Activity 用の worker として使用することができます。

加えて:

 ・Fragment は self-contained で複数の Activity で再利用できる。

 ・Activity 内で、Fragment の追加、削除、置換、アニメーションが可能。

 ・Activity によって管理される back stack に Fragment を追加でき、変更時に Fragment の状態を保存するので、ユーザーは様々な状態を介して前後に移動できる。

 ・代替レイアウトを提供する(providing alternative layouts) ことで、画面サイズおよび向きに応じて Fragment を混ぜたり合わせたりできる

 ・Fragment はそれらの含む Activity への直接アクセスを持っているので、Activity の Action Bar (次で述べる) のアイテムに寄与できる。

Activity 内で Fragment を管理するには FragmentManager を使う必要があります。これは、Fragment とインタラクトするいくつかの API を提供します。例えば、Activity 内の Fragment を見つけたり、以前の状態をリストアするために back stack へ Fragment を pop したりできます。

Fragment の追加や削除などの transaction を行うには、FragmentTransaction を生成する必要があります。その後、add(), remove(), replace() などのメソッドを呼ぶことで transaction を実行できます。transaction に対して行いたい全ての変更を適用するには、commit() メソッドを呼ばなければなりません。そうするとシステムが Fragment の transaction を Activity に適用します。

Fragment を使用するためのより詳しい情報は、Fragments ドキュメントを読んでください。いくつかのサンプルは API Demos アプリケーションにあります。

---------------------------

Action Bar

Action Bar は Activity Window の上部にあったこれまでのタイトルバーを置き換えるものです。これはアプリケーションのロゴを左隅に含み、Option Menu 内のアイテムへの新しいインタフェースを提供します。加えて、Action Bar は次のことが可能です。

 ・"action items" として Action Bar に直接メニューアイテムを追加することができる

  メニューアイテムの XML 定義で、android:showAsAction 属性に "ifRoom" を設定します。十分な room がある場合、メニューアイテムは Action Bar に直接表示されます。そうではない場合、Action Bar の右側にあるメニューアイコンで表示される overflow メニュー内に配置されます。

 ・"action view" を作成することで、検索ボックスのようなウィジェットに action item を置き換えられる

  メニューアイテムの XML 定義で、android:actionViewLayout 属性にレイアウトリソースを指定し、android:actionViewClass 属性にウィジェットのクラス名を指定します(Action Bar にアイテムが現れるように android:showAsAction 属性も定義しなければなりません)。Action Bar に十分な room がなくアイテムが overflow メニューに表示される場合、それはこれまでのメニューアイテムのように振る舞い、ウィジェットは表示されません。

 ・アプリケーションロゴにアクションを追加し、カスタムロゴに置き換える

  アプリケーションロゴは自動的に android.R.id.home ID が割り当てられ、タッチされたときシステムから Activity の onOptionItemSelected() コールバックに渡されます。コールバックメソッド内でこの ID に単純に応答することで、アプリケーションの "home" Activity へ移動するなどのアクションを実装できます。

  ロゴをアイコンに置き換えるには、マニフェストファイル内で android:logo 属性にロゴを指定します。そうすると、Activity で setDisplayUseLogoEnabled(true) が呼ばれます。

 ・Fragment の back stack へのナビゲーションとしてパンくずリストを追加する

 ・Fragment へのナビゲーションとしてタブもしくは drop-down list を追加する

 ・テーマと背景で Action Bar をカスタマイズする

Action Bar は新しい holographic theme を使う全てのアプリケーションにとって標準です。つまり android:minSdkVersion もしくは android:targetSdkVersion"11" に設定されている場合にとって標準になります。

Action Bar のより詳しい情報は、Action Bar ドキュメントを読んでください。いくつかのサンプルは API Demos アプリケーションにあります。

---------------------------

System clipboard

アプリケーションは system-wide クリップボードへデータ(単なるテキストを超えて)コピー&ペーストできるようになりました。クリップボードデータはプレーンテキストやURI、Intent も可能です。

content provider を通して、ユーザーにコピーさせたいデータへのシステムアクセスを提供することで、ユーザーは複雑なコンテント(画像やデータ構造など)をあなたのアプリケーションからコピーし、そのコンテントタイプをサポートする別のアプリケーションにペーストすることができます。

クリップボードを使うには、まず getSystemService(CLIPBOARD_SERVICE) を呼んで、グローバルの ClipboardManager オブジェクトを取得します。

クリップボードにアイテムをコピーするには、新しい ClipData オブジェクトを生成し、単一のエンティティが記述された 1つ以上の ClipData.Item をそれに保持させる必要があります。1つの ClipData.Item を含むだけの ClipData オブジェクト を作成する場合、newPlainText(), newUri(), newIntent() などのヘルパーメソッドを使うことができます。これらはあなたが提供した ClipData.Item を pre-loaded して ClipData オブジェクトを返します。

ClipData をクリップボードに追加するには、ClipboardManager のインスタンスの setPrimaryClip() メソッドで ClipData を渡します。

そうすると、ClipboardManager の getPriimaryClip() を呼ぶことでクリップボードからファイルを読むことができます。あなたが受け取る ClipData のハンドリングは複雑になる可能性があります。そのため、実際に張り付ける前にクリップボード内のデータタイプがハンドルできるかどうか確認する必要があります。

クリップボードはクリップするデータの一欠片(つまり ClipData オブジェクト) しか保持することができません。しかし、一つの ClipData は複数の ClipData.Item を含むことができます。

より詳しい情報は Copy and Paste ドキュメントを読んでください。また、コピー&ペーストの簡単な実装は API Demos に、より複雑な実装は Note Pad アプリケーションで見ることができます。

---------------------------

Drag and drop

新しい API はあなたのアプリケーションのユーザーインタフェースでのドラッグ&ドロップ操作を単純化します。ドラッグ操作はある場所から別の場所へいくつか種類のデータ転送(ClipData オブジェクト内で運ばれる)です。ドラッグ操作の開始と終了地点は View です。そのため、ドラッグ&ドロップ操作を直接ハンドルする API は View クラス内にあります。

ドラッグ&ドロップ操作は ACTION_DRAG_STARTED, ACTION_DRAG_ENTERED, ACTION_DROP などの、いくつかのドラッグアクション(DragEvent オブジェクトで定義される)で定義されたライフサイクルを持ちます。ドラッグ操作に携わりたい各 View はこれらのアクションを listen することができます。

あなたの Activity でコンテンツのドラッグを開始するには、View の startDrag() を呼びます。これはドラッグするデータを表す ClipData オブジェクト提供します。View.DragShadowBuilder によって、ユーザーがドラッグしている間指の下に見える "shadow" を簡単に作ることができます。startDrag() で提供される Object はドラッグするオブジェクトの情報を、受け取る view との間で共有することができます。

View で ドラッグされたオブジェクトを許可する ("drop" を受け取る) には、setOnDragListener() を呼んで view に OnDragListener をレジストします。view 上でドラッグイベントが起こると、システムは OnDragListener に対して onDrag() を呼びます。これは、発生したドラッグアクションのタイプ (ACTION_DRAG_STARTED, ACTION_DRAG_ENTERED, ACTION_DROP など)が記述された DragEvent を受け取ります。ドラッグイベントのストリームを配信するために、ドラッグの間システムは繰り返しドラッグ下にある view に対して onDrag() を呼びます。受け取る view は onDragEvent() に運ばれるイベントタイプを DragEvent の getAction() を呼ぶことで問い合わせることができます。


Note: ドラッグイベントは ClipData オブジェクトを運びますが、これはシステムのクリップボードとは関係ありません。ドラッグ&ドロップ操作はドラッグしているデータをシステムのクリップボードに入れることはありません。

より詳しい情報は、Dragging and Dropping ドキュメントを読んでください。ドラッグ&ドロップの実装は API Demos アプリケーションと Honeycomb Gallery アプリケーションで見ることができます。


 

2011年2月20日日曜日

Android RadioButton の画像とテキストの間隔を広げる

どうもね、デフォルトだと詰まり過ぎてると感じるんですよ。私は。

RadioButton の画像とテキストの間のことです。



それで、この間に余白いれようかなと思ったんです。

android:drawablePadding

かなと思ったんですけど、ダメでした。

ということでコード見たんです。RadioButton.java
この方は、CompoundButton を継承して、toggle の設定してるだけなので

CompoundButton.java を見ると、

onDraw で縦方向の位置しか調整してないんですよ。


229 @Override
230 protected void onDraw(Canvas canvas) {
231 super.onDraw(canvas);
232
233 final Drawable buttonDrawable = mButtonDrawable;
234 if (buttonDrawable != null) {
235 final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
236 final int height = buttonDrawable.getIntrinsicHeight();
237
238 int y = 0;
239
240 switch (verticalGravity) {
241 case Gravity.BOTTOM:
242 y = getHeight() - height;
243 break;
244 case Gravity.CENTER_VERTICAL:
245 y = (getHeight() - height) / 2;
246 break;
247 }
248
249 buttonDrawable.setBounds(0, y, buttonDrawable.getIntrinsicWidth(), y + height);
250 buttonDrawable.draw(canvas);
251 }
252 }
253


ん? じゃあどこで調整してるの?
横方向 0 から画像部分描画してるけど、それだと文字とかぶるんじゃ。。。

とりあえず theme.xml と style.xml も見ておくか。

theme.xml

173 <item name="radioButtonStyle">@android:style/Widget.CompoundButton.RadioButton</item>


style.xml

280 <style name="Widget.CompoundButton.RadioButton">
281 <item name="android:background">@android:drawable/btn_radio_label_background</item>
282 <item name="android:button">@android:drawable/btn_radio</item>
283 </style>


む。 @android:drawable/btn_radio が画像部分なのは分かるとして、android:background を設定している。これはなんだ。

画像を見てみた。

btn_radio_label_background.9.png


9 patch だよ。

わかりずらいと思いますが、下部の 1px ラインは右側にちょこっとあるだけなんです。つまり、この透明部分がボタンのパディングとして作用しているということなんですよ。


あれ、ということは、RadioButton タグで android:background="#000066" とかしたらまずいんじゃ。。。

やってみた。



うは。かぶったw


つまり、背景&画像とテキストの間隔を変更するには

  1. 9 patch png を作り直す

  2. LinearLayout で RadioButton と TextView を組み合わせ、
    Chackable を implements したクラスを作る

  3. shape で背景を作る

の方法があることがわかったんです。

1. は微調整や変更がしにくい。
2. はコーディングが多くなるし、View の階層が増える

ということで、3 にしました。

# shape いいよ。shape 便利。みんなもっと shape 使うべきだよ


shape タグ には padding というタグで余白を指定できます。

# shape の使い方は Android Layout Cookbook に詳しく書いたよん。

こんな感じでOK。
背景色を付けるなら solid か gradient タグで。

drawable/bg.xml

<?xml version="1.0" encoding="utf-8" ?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#660000" />
<padding
android:left="50dip"
android:top="0dip"
android:right="0dip"
android:bottom="0dip" />
</shape>


あとは、RadioButton タグで android:background="@drawable/bg" と指定すればいい。



一番上が shape 使ったやつです。ちゃんと間隔を広げることができました。


 

2011年2月16日水曜日

Android PreferenceActivity の背景をカスタマイズ

またしても くごー先生からの依頼です。

くごー先生の依頼は断れませんね。

なんか倒したくなったちゃいますね。はい。


今回はちょっと苦労しました。

■ 単純に PreferenceActivity の起動画面の背景だけ変えるなら、、、

* Window の背景を設定


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

getWindow().setBackgroundDrawableResource(R.drawable.bg);

addPreferencesFromResource(R.xml.pref);
}


* ListView の背景を設定(その1)

# PreferenceActivity は ListActivity を extends してるんですよ。
# しってました?


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

ListView lv = getListView();
lv.setBackgroundResource(R.drawable.bg);

addPreferencesFromResource(R.xml.pref);
}


* ListView の背景を設定(その2)

main2.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/bg"
/>



@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main2);

addPreferencesFromResource(R.xml.pref);
}


ただし、この場合は問題があります!

次のような、root の PreferenceScreen の中に PreferenceScreen が入っている場合は、入れ子の PreferenceScreen の背景は変わってくれないのです!残念!


<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Application Setting">
<CheckBoxPreference
android:key="checkbox_value"
android:title="Setting1"
android:summary="sample of checkbox setting" />
<EditTextPreference
android:key="edittext_value"
android:title="Setting2"
android:summary="sample of edittext setting"
android:dialogTitle="Setting edittext"
android:dialogMessage="please set values" />
<PreferenceScreen
android:title="PrefereceScreen2">
<ListPreference
android:key="list_value"
android:title="Setting3"
android:summary="sample of list setting"
android:entries="@array/setting_items"
android:entryValues="@array/setting_items_value" />
<RingtonePreference
android:key="ringtone_value"
android:title="Setting4"
android:summary="sample of ringtone setting"
android:showDefault="true"
android:showSilent="true"
android:ringtoneType="ringtone" />
</PreferenceScreen>
</PreferenceCategory>
</PreferenceScreen>



でも大丈夫。方法を見つけました。

PreferenceActivity が ListActivity を継承していることを思い出してください。

ListView のデフォルトの背景を変えてしまえばいいのです。

ということで、


■ 入れ子の PreferenceScreen も合わせて背景を変更

ListView のテーマを指定します。

style.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CustomTheme.Black" parent="@android:style/Theme.Black">
<item name="android:listViewStyle">@style/CustomListView</item>
</style>
<style name="CustomListView" parent="@android:style/Widget.ListView">
<item name="android:background">@drawable/bg</item>
<item name="android:cacheColorHint">@android:color/transparent</item>
</style>
</resources>


あとは、AndroidManifest.xml で指定するだけ


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
... >
<application android:icon="@drawable/icon" android:label="@string/app_name">
...
<activity android:name=".MainPreferenceActivity"
android:label="@string/app_name"
android:theme="@style/CustomTheme.Black"
>
</activity>
</application>
</manifest>


これでOK。

# Preference関係の style のパラメータは一行のなかのレイアウトなので使えませんでしたん。

ListView の背景をかえるときは CacheColorHint も一緒に指定しないとスクロールしたときなどにとっても残念なことになるので気をつけてね。


 


 

Android launchMode の違い

android:launchMode については以前のエントリ

Android Activity, Task, Stack, Launch mode

にも少し書いたのですが、それぞれの違いについてもう少し詳しく説明したいと思います。

上記のエントリで私がまとめた launchMode の表を再掲します。



この表に載っている

 「インテントに応答するアクティビティをどのタスクに保持するか」
 「アクティビティのインスタンスを複数生成できるか」
 「インスタンスに他のアクティビティを含めることができるか」
 「クラスの新しいインスタンスを起動して新しいインテントを処理するかどうか」

について順番に説明します。


■ インテントに応答するアクティビティをどのタスクに保持するか

ここに アプリX があるとします。

このアプリは ACTION_SEND を処理できる Activity A を持っています。


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MyActivity" android:label="@string/app_name"
android:launchMode="LAUNCHMODE">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
...
</application>
</manifest>


では、Twicca からこのアプリを呼び出した場合


-----------
| Twicca
-----------


この状態のスタックはどうなるでしょうか?

* standard(default mode), singleTop の場合


-------------
| Twicca A
-------------


のように画面A は Twicca と同じタスクに属します。
インテントに応答するアクティビティが startActivity() を呼び出したタスクに保持されるからです。

この状態で、ホームボタンを長押しして別のアプリにしたあと、またホームボタン長押しで Twicca を選択してみてください。画面A になったでしょ? このようにタスクごと切り替わるので、画面A が Twicca の一部のように振る舞います。


* singleTask, singleInstance の場合


--------------
| Twicca | A
--------------


のように画面A は Twicca とは別のタスクに属します。
インテントに応答するアクティビティが常にタスクのルートアクティビティになるからです。
ここで、ホームボタン長押して Twicca を選択すると


--------------
| A | Twicca
--------------


のように Twicca が前面にきます。さらにここでバックキーを押すと後ろに行った
画面A が出てきます。



■ アクティビティのインスタンスを複数生成できるか

アプリX の画面A には 画面B に遷移するボタンがあります。
画面B には画面A に遷移するボタンがあります。
画面B のアクティビティは standard(default mode) です。

では、ランチャーから アプリX を起動したあと、各画面のボタンを押していくとどうなるでしょう?

* standard(default mode), singleTop の場合


------------------------
| A B A' B' A'' B'' ...
------------------------


のように一つのタスクに画面A と画面B のインスタンスが複数生成されることになります。
バックキーを押していくと、B'' A'' B' A' B A ホーム のように画面遷移することになります。
これは、standard と singleTop では、アクティビティのインスタンスを複数生成することができるからです。


* singleTask の場合


--------------
| A
--------------

--------------
| A B
--------------

onNewIntent が呼ばれる
--------------
| A
--------------

--------------
| A B'
--------------

onNewIntent が呼ばれる
----------------
| A
----------------


singleTask の場合、画面B から 画面A を呼び出そうとすると、画面B でバックキーを押したときのような動作をします。つまり画面B が finish してしまうのです。これは画面B のアクティビティが画面Aと同じタスクになるため、画面Aが新しいインテントを処理するために前面に来るときに、その上のアクティビティを破棄してしまうからです。画面A のアクティビティでは新しいインテントを処理するために onNewIntent() メソッドが呼ばれます。


* singleInstance の場合


--------------
| A
--------------

--------------
| A | B
--------------

onNewIntent が呼ばれる
--------------
| B | A
--------------

--------------
| A | B'
--------------

onNewIntent が呼ばれる
----------------
| B' | A
----------------


singleInstance の場合、singleTask と違ってバックキーのような動作にはなりません。画面B はそのままバックグラウンドに移動し、画面A の onNewIntent() メソッドが呼ばれます。なぜ 画面B がバックグラウンドに移動できるかというと、画面A と 画面B が別のタスクになっているからです(理由は次の項目で説明)。そのため、この状態で ホームキー長押し -> Twicca -> ホームキー長押し -> アプリX と選択すると


-------------------
| B' | Twicca | A
-------------------


のようになります。



■ インスタンスのタスクに他のアクティビティを含めることができるか

先程の例で、 singleTask と singleInstance の違いに注目してください。
画面A から 画面B を呼び出したとき、singleTask では 画面B は 画面A と同じタスクに属していますが、singleInstance では別のタスクに属しています。これは、singleInstane は他の3つと違い、インスタンスのタスクに他のアクティビティを含むことが出来ないからです。



■ クラスの新しいインスタンスを起動して新しいインテントを処理するかどうか

さて、アプリX を少し改造して、画面A から 画面B を呼び出すのではなくて、
画面A から画面A を呼び出すようにしてみます。


public class MyActivity extends Activity {

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

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}

public void onButtonClick(View view) {
Intent i = new Intent(this, MyActivity.class);
startActivity(i);
}
}


ランチャーから起動した直後のスタックは


-----
| A
-----


のようになっています。
ここで、ボタンをクリックしたら(= onButtonClick() を呼び出したら)スタックの
状態はどうなるでしょうか?

* standard(default mode) の場合


--------
| A A'
--------


のように新しいインスタンスが生成されます。
これは、新しいインテントに応答するときは必ず新しいインスタンスが作成されるからです。


* singleTask, singleInstance の場合


--------
| A
--------


のままで、onNewIntent() メソッドが呼ばれます。
これは、インスタンスは常に新しいインテントを処理するからです。


* singleTop の場合


--------
| A
--------


この場合、singleTop も singleTask, singleInstance と同じで onNewIntent() が呼ばれます。
これは、クラスの既存のインスタンスが対象タスクのアクティビティスタックの最上位にあるからです。

そういえば、アプリX は ACTION_SEND で呼び出せるんでした。


-------------
| A | Twicca
-------------


この状態で Twicca から アプリX を起動したらどうなるでしょう?


----------------
| A | Twicca A'
----------------


そう、クラスの既存のインスタンスが最上位にないので、新しいインスタンスが作成されます。


ちなみに、
* singleTask, singleInstance の場合


----------------
| Twicca | A
----------------


インスタンスは 1 つなので、Aが手前にきて新しいインスタンスを処理します。


■ アプリX

 ここからどうぞ


■ 次回は

FLAG_ACTIVITY_hogehoge をやります!


 

2011年2月15日火曜日

vCard のメモ

ちょっと、vCard の仕様が知りたくなったので調べてみた。

■ 参考ページ

 vCardはIrMC内で定められている個人情報のデータ-フォーマット

 ・vCardの仕様書

 ・vCard Overview


■ vCard のバージョン

 ・vCard 2.1
   ・"7BIT"禁止
   ・"BASE64"禁止
 (・vCard 2.1 for Europe
   ・名前の順番が "Prefix Middle Given Family Suffix")
 ・vCard 3.0 (RFC 2426)
   ・"QUOTED-PRINTABLE"禁止
   ・"CHARSET"禁止
 ・vCard 4.0


* Card 2.1 までの属性

・BEGIN : VCARD
  exp) BEGIN:VCARD

・VERSION : [2.1 | 3.0 | 4.0]
  exp) VERSION:3.0

・N : string // Name
  exp) N:Yuki

・FN : string // Full Name
  exp) FN:Yuki Anzai

・ADR : string // Address
  exp) ADR;TYPE=HOME:;;1-2;目黒区;東京都;000-0000;日本

・EMAIL : string // Mail Address
  exp) EMAIL;TYPE=PREF;INTERNET:android@gmail.com

・NOTE : string // Memo
  exp) Note:Android好き

・ORG : string // 所属組織
  exp) ORG:Android女子部

"SOUND"

・TEL : number // phone number
  exp) TEL;TYPE=PREF;HOME:0001112222
  exp) TEL;WORK:0001112222
  exp) TEL;FAX:0001112222
  exp) TEL;CELL:0001112222

・TITLE : string // 肩書き
  exp) TITLE:総長

"ROLE"
"PHOTO"
"LOGO"

・ URL : url
  exp) URL:http://android.com

・END : VCARD
  exp) END:VCARD


* Card 3.0 で追加された属性
・NAME : string // N とどう違うのかよくわからない // (3.0, 4,0)

・NICKNAME : string // (3.0, 4.0)

・PROFILE

・SOURCE

・CLASS : string
  exp) CLASS:PRIVATE

・BDAY : date? // Birthday (3.0, 4.0)

・SORT-STRING : string // (3.0, 4.0)
  exp) SORT-STRING:アンザイユキ

・CATEGORIES : string // カテゴリ名
  exp) CATEGORIES:無所属

・PRODID

* Docomo 独自の属性? (3.0)
"ENCODING"
"CHARSET"
"HOME"
"WORK"
"FAX"
"CELL"
"VOICE"
"INTERNET"

* Card 4.0 で追加された属性
"BIRTH" // Place of birth (4.0)
"ANNIVERSARY" // Date of marriage (4.0)


■ Android での実装

まずは vcard で検索

VCardParser.java とか VCardInterpreter.java とかいますねー

このへんみるといろいろありすぎw
http://tools.oesf.biz/android-2.3_r1.0/xref/frameworks/base/core/java/android/pim/vcard/VCardConstants.java


190 /*
191 * vCard 3.0 defines
192 *
193 * param = param-name "=" param-value *("," param-value)
194 * param-name = iana-token / x-name
195 * param-value = ptext / quoted-string
196 * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
197 * QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII
198 * ; Any character except CTLs, DQUOTE
199 *
200 * QSAFE-CHAR must not contain DQUOTE, including escaped one (\").
201 */

212 /*
213 * param-value = ptext / quoted-string
214 * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
215 * QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII
216 * ; Any character except CTLs, DQUOTE
217 *
218 * QSAFE-CHAR must not contain DQUOTE, including escaped one (\")
219 */


V3.0 用のコード
http://tools.oesf.biz/android-2.3_r1.0/xref/frameworks/base/core/java/android/pim/vcard/VCardParser_V30.java

http://tools.oesf.biz/android-2.3_r1.0/xref/frameworks/base/core/java/android/pim/vcard/VCardParserImpl_V30.java
では、
「vCard 3.0 では "CHARSET" 属性は許可されていないが、実際に使われているファイルでは "UTF-8" が使われていないものもあり、"CHARSET" も許すようにしてます。"7BIT" と "BASE64"は vCard 2.1 では許可されていないけどパースします。」ってコメントがあるね。



NDEF の vCard 関連だと Tag アプリの中に実装がありますね。
http://tools.oesf.biz/android-2.3_r1.0/xref/packages/apps/Tag/src/com/android/apps/tag/record/VCardRecord.java

jQuery Mobile でちょっと遊んでみた。

jQuery Mobile
 ・JavaScript framework の jQuery のプラグインとして動作
 ・スクリプトを書かずにマークアップだけで画面遷移などが書ける
 ・Query Mobileの本体サイズは圧縮状態で < 20 KB
 ・Download から j-query-mobile-**.js と j-query-mobile-**.css をダウンロード

参考サイト
 ・「jQuery Mobile」の登場で、モバイルアプリケーション開発は大きく変わる - Publickey -
 ・吉川徹さんのプレゼンテーション「jQuery Mobile [基礎編]」
 ・サンプル集


■ 設定項目

画面構成
data-role : [page | header | content | footer | navbar | button |
slider | controlgroup | coolapsible | collapsible-set |
fieldcontain | listview | list-divider]

class : [ui-bar | ui-grid-[a-d] | ui-block-* | ui-btn-left | ui-btn-right]

data-inline : [true | false] // 部品を1行にまとめる]

data-type : [horizontal | vertical]

画面をフルスクリーンにする
data-fullscreen : [true | false]

戻るボタンを自動生成するかどうか
data-backbtn : [true | false]

自動生成される戻るボタンのテキスト設定
data-back-btn-text : string

位置 (ヘッダーを固定するなど)
data-position : [fixed]

画面遷移のエフェクト
data-transition : [slide | slideup | slidedown | pop | fade | flip]

画面遷移のエフェクト方向
data-direction : [reverse]

ダイアログ/戻るボタン
data-rel : [dialog | back]

アイコン
data-icon : [arrow-l | arrow-r | arrow-u | arrow-d | delete |
plus | minus | check | gear | refresh | forward |
back | grid | star | alert | info | search | home | false]
data-split-icon : data-icon と同じ

アイコンの位置
data-iconpos : [top | bottom | right | left | notext ]

装飾
data-theme : [a | b | c | d | e]

入力ボックス関係
placeholder : string // テキストボックスに出るヒント

Expander
data-collapsed : [true | false]

リスト関係
data-inset : [true | false]
data-filter : [true | false] // 検索ボックスを表示するかどうか
data-theme : [a-e]
data-dividertheme : [a-e]
data-counttheme : [a-e]
data-splittheme : [a-e]
data-spliticon : [a-e]

部品の永続化(フッターを共有するなど)
data-id : [persistent]


■ ちょいと遊んでみた

yanzm's site

html ソース

<!DOCTYPE html>
<head>
<title>yanzm's site</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
<script src="http://code.jquery.com/jquery-1.5.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>
</head>
<body>

<!-- メインページ -->
<div data-role="page" id="foo">

<!-- メインページのヘッダ -->
<div data-role="header" data-backbtn="false">
<h1>yanzm's site</h1>
</div><!-- /header -->

<!-- メインページの内容。サブページへのボタン -->
<div data-role="content">
<p><img src="../images/yanzm.jpg"></p>
<p>Yuki Anzai</p>
<p>Blog : <a href="http://y-anz-m.blogspot.com">Y.A.M の雑記帳</a></p>
<p>twitter : <a href="http://twitter.com/yanzm">@yanzm</a></p>

<p>Android Applications</p>
<div data-role="collapsible-set">
<div data-role="collapsible" data-collapsed="true">
<h1>Libraroid - 図書館予約 -</h1>
<a href="https://market.android.com/details?id=yanzm.products.libraroid">Libraroid at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>BooXpress</h1>
<a href="https://market.android.com/details?id=yanzm.products.expfa">BooXpress at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>Wolfraroid</h1>
<a href="https://market.android.com/details?id=yanzm.products.wolfraroid">Wolfraroid at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>SkyMemo</h1>
<a href="https://market.android.com/details?id=layout.example.section8_3">SkyMemo at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>Suica Reader</h1>
<a href="https://market.android.com/details?id=yanzm.products.suicareader">Suica Reader at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>FeliCaLiteBridge</h1>
<a href="https://market.android.com/details?id=yanzm.products.felicalitebridge">FeliCaLiteBridge at Android Market</a>
</div>
<div data-role="collapsible" data-collapsed="true">
<h1>FeliCaWriter</h1>
<a href="https://market.android.com/details?id=yanzm.products.felicawriter">FeliCaWriter at Android Market</a>
</div>
</div>
</div><!-- /content -->

<!-- メインページのフッター -->
<!--
<div data-role="footer" data-position="fixed" data-id="persistent">
</div>
-->
</div><!-- /page -->
</body>

# 画面遷移するとちらつきが気になったので入れませんでした。

2011年2月11日金曜日

root がなくても FeliCaLite の NDEF データが取れるアプリ FeliCaLiteBridge をリリースしました。

 


こんばんは。あんざいです。

以前のエントリで、Android 2.3 の NFC は FeliCaLite をNDEF として認識しない、ということを書きました。

Android NFC での FeliCa の NDEF 判定

Sonyさんが Nexus S で FeliCa Lite を読めるようにするためのパッチ を公開してくださっているのですが、root が必要です。

root 取りたくない人もいるので( > 私)

root なくても FeliCa Lite の NDEF データが読めるアプリを公開しました。

FeliCaLiteBridge - Android Market


中のデータを読み込んで、Intent に詰めて発行し直すだけです。
このアプリ自体は NDEF データを解析できるわけではありません。
再発行された Intent によって、再びアプリ選択が画面が出るので、そこで Tag アプリなど NDEF データが解析できるアプリを選択してください。


使い方

1. NDEF データが書かれた FeliCa Lite をかざします

2. アプリの選択画面で、カードをかざしたまま、FeliCaLiteBridge を起動します。

3. 再びアプリの選択画面が出るので、Tag アプリなど NDEF データを解析するアプリを起動します。



# Andorid 2.3.3 で FeliCaLite が読めるようになってるかもしれないので、短命なアプリになるんだろうなぁ。


 

2011年2月10日木曜日

Android 2.3.3 Platform

Android 2.3.3 Platform

API Level: 10

Android 2.3.3 は Android 2.3 platform にいくつかの改善した API を付加したリリースです。

開発者は Android 2.3.3 platform を Android SDK のコンポーネントとしてダウンロードできます。ダウンロードできる platform は Android library と system image を含み、エミュレータのスキンなどのセットも含まれます。ダウンロードできる platform には外部ライブラリは含まれません。

Android 2.3.3 用の開発とテストを開始するには、Android SDK Manager で SDK に platform をダウンロードしてください。より詳しい情報は Android SDK Components を見てください。初めて Android 開発を始める方はまず download the SDK Starter Package を行ってください。

Android 2.3 のより詳しい紹介は Platform Highlights を見てください。

-----------------------------------
API Overview

以下のセクションは 2.3.3 で新しくなった機能・変わった点の technical overview です。

Near Field Communication (NFC)

Android 2.3.3 では、改善・拡張された NFC サポートを提供します。これによりアプリケーションはより多くのタイプのタグと新しい方法でインタラクトできます。

より広い範囲の標準タグテクノロジーに read / write access する新しい包括的な API セットが提供されます。
これには以下が含まれます。
  ・NFC-A (ISO 14443-3A)
  ・NFC-B (ISO 14443-3B)
  ・NFC-F (JIS 6319-4)
  ・NFC-V (ISO 15693)
  ・ISO-DEP (ISO 14443-4)
  ・Mifare Classic
  ・Mifare Ultralight
  ・NFC Forum NDEF tags

さらに、platform は限定的なP2P接続プロトコル (limited peer-to-peer communication protocol) と API を提供します。前面の Activity は API を使って NDEF message を登録することができ、登録した message は他のデバイスが接続されたときに push されます。

進化した tag 発行 (dispatching) は、NFC tag が見つかったときに、どのように・いつそれが発行されたかのより多くのコントロールをアプリケーションに提供します。以前の platform では、tag が見つかったことを知らせるのに single-step の intent 発行を使っていました。 今回から platform は、タグイベントのコントロールが他のアプリケーションへパスされる前に、前面のアプリケーションがそれをとれるように four-step process を使います (android.nfc.NfcAdapter.enableForegroundDispatch())。新しい発行プロセス (dispatch process) では、 2 つの新しい intent actions - android.nfc.action.NDEF_DISCOVERED and android.nfc.action.TECH_DISCOVERED を使うことで、アプリケーションが特定のタグコンテンツやタグテクノロジーを listen することができます。

NFC API は android.nfcandroid.nfc.tech packages で利用できます。
鍵となるクラスは

NfcAdapter : デバイス上のNFCのハードウェアを表す

NdefMessage : NDEF データメッセージを表す。デバイスとタグ間で標準形式の "records" でデータを転送する。NDEF メッセージは異なるタイプの多くの NDEF records を特定する。アプリケーションはこれらのメッセージを NDEF_DISCOVERED, TECH_DISCOVERED, or TAG_DISCOVERED Intents から受信できる

NdefRecord : NdefMessage 内で運ばれる。自身に含まれるデータのタイプを記述する

Tag : デバイスによってスキャンされたタグを表す。タグテクノロジーに基づいて、複数のタイプのタグをサポートしている

TagTechnology : タグプロパティへのアクセスおよび I/O操作をアプリケーションに与えるためのインタフェース。Android 2.3.3 でサポートされている全ての tag technology リストは android.nfc.tech を見てください。

NFC接続はデバイスハードウェアのワイヤレステクノロジーに依存しています。そのため、全ての Android デバイスで提供されているわけではありません。NFC をサポートしていない Android デバイスでは、getDefaultAdapter(Context) は null object を返します。そして、context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC) は false を返します。 ハードウェアがサポートしてるかに関わらず、NFC API は常に存在します。

NFC API を使うには、アプリケーションは permission をリクエストしなければなりません。<uses-permission android:name="android.permission.NFC"> を manifest ファイルに定義してください。

加えて、開発者は Android Market で NFC がサポートされていないデバイスで見つからないようにフィルタリングをリクエストできます。フィルタリングをリクエストするには <uses-feature android:name="android.hardware.nfc" android:required="true"> をマニフェストに定義してください。

NFC の sample code は NFCDemo app, filtering by tag technology, using foreground dispatch, and foreground NDEF push (P2P) をみてください。


Bluetooth

Android 2.3.3 で Blutooth の nonsecure socket connection をサポートする API が platform に追加されました。これにより、アプリケーションは UI での認証を依頼することなく、単純なデバイスと接続することができます。より詳しい情報は createInsecureRfcommSocketToServiceRecord(java.util.UUID)listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) を見てください。


Graphics

・新しく BitmapRegionDecoder クラスが追加されました。これによりアプリケーションは画像の矩形領域をデコードすることができます。この API は オリジナル画像が大きく、アプリケーションがその一部だけ必要な場合にとても便利です。

BitmapFactory.Options クラスに新しく inPreferQualityOverSpeed フィールドが追加されました。これにより、アプリケーションはJPEG デコードに、より正確だが少し遅い IDCT メソッドを 使えます。再構成された画像のクオリティを改善することに使えます。


Media framework

・新しく MediaMetadataRetriever が追加されました。これにより frame と metadata を入力メディアファイルから受け取る単一のインタフェースが提供されます。

MediaRecorder.AudioEncoderMediaRecorder.OutputFormat は AMR Wideband と AAC フォーマットを指定するための新しいフィールドを含みます。


Speech recognition

speech-recognition API (音声認識API) は音声検索の結果を新しい方法で管理するための、新しい定数を含みます。新しい定数は通常の音声認識の使用では必要ありませんが、これは、音声検索の結果をアプリケーションの異なる View に提供することができます。この情報については RecognizerResultsIntent を見てください。



 

2011年2月7日月曜日

Android 1画面 複数Activity で画面遷移 - ActivityGroup -

以前のエントリで「Android 複数画面 1 Activity で画面遷移 」を紹介しました。

今回は 1画面 複数Activity です。

# 複数の Activity は同じプロセスになります。

ActivityGroup を継承します。

TabActivity はこの ActivityGroup を継承していて、そのため各タブに Acitivity を割り当てることが可能なんです。

構造としてはこんな感じ


親Activity (ActivityGroup)
|
|+---- 子Activity1 (Activity)
|
|+---- 子Activity2 (Activity)
|
...


親 Activity は getLocalActivityManager() で取得した LocalActivityManagerstartActivity(String id, Intent intent) で子Activityを起動します。

startActivity(String id, Intent intent) は戻り値として Window を返すので、この Window の getDecorView() で取得した View を対応するコンテナ (LinearLayout とか FrameLayout) とかに addView() すればOK。

startActivity の第1引数の String は Activity の識別子(id)で、LocalActivityManager.getCurrentId() を使って現在の Activity の id を取得することが可能。

LocalActivityManager.getActivity(String id) で特定の id のActivity を取得することができるし、LocalActivityManagergetCurrentActivity() で現在の Activity を取得することもできる。


■ ボタンをクリックしたら 同じ画面で Activity を切り替えるサンプル

# まずは最小構成で。

親 Activity のレイアウト (parent.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="@+id/parent"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showChild1"
android:text="show child1 Activity"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showChild2"
android:text="show child2 Activity"
/>
</LinearLayout>

<LinearLayout
android:id="@+id/child"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center">
</LinearLayout>
</LinearLayout>


id/child に子 Activity の View を入れることになります。

子1 Activity のレイアウト (child1.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is child1 Activity"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
</LinearLayout>


子2 Activity のレイアウト (child2.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is child2 Activity"/>
</LinearLayout>


親 Activity

import android.app.ActivityGroup;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.LinearLayout;

public class MyActivityGroup extends ActivityGroup {
LinearLayout container;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parent);

container = (LinearLayout) findViewById(R.id.child);
}

public void showChild1(View v) {
container.removeAllViews();
Intent intent = new Intent(MyActivityGroup.this, Child1Activity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Window childActivity = getLocalActivityManager().startActivity("child1Activity",intent);
container.addView(childActivity.getDecorView());
}

public void showChild2(View v) {
container.removeAllViews();
Intent intent = new Intent(MyActivityGroup.this, Child2Activity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Window childActivity = getLocalActivityManager().startActivity("child2Activity",intent);
container.addView(childActivity.getDecorView());
}
}



さて、ここからが応用です。

■ Tab の中で画面遷移

TabContent に入れる Activity を AcitivityGroup にすればタブの中で画面遷移ができます。
上記 MyActivityGroup をそのまま TabActivity の Content に入れてみます。





構造はこんな感じ

TabActivity (Activity)
|
|+--- Tab1 (ActivityGroup)
| |
| |+---- 子Activity1 (Activity)
| |
| |+---- 子Activity2 (Activity)
|
|+--- Tab2 (Activity)
|
|+--- Tab3 (Activity)


AndroidManifest.xml に Activity を宣言するの忘れずに!


package yanzm.example.activitygroup2;

import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;

public class MyActivity extends TabActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab_layout);

Resources res = getResources();

TabHost tabHost = getTabHost();

TabHost.TabSpec spec;
Intent intent;

intent = new Intent().setClass(this, MyActivityGroup.class);
spec = tabHost.newTabSpec("tab1")
.setIndicator("Home", res.getDrawable(R.drawable.ic_tab_home))
.setContent(intent);
tabHost.addTab(spec);

intent = new Intent().setClass(this, Tab2Activity.class);
spec = tabHost
.newTabSpec("tab2")
.setIndicator("Camera",
res.getDrawable(R.drawable.ic_tab_camera))
.setContent(intent);
tabHost.addTab(spec);

intent = new Intent().setClass(this, Tab3Activity.class);
spec = tabHost.newTabSpec("tab3")
.setIndicator("Star", res.getDrawable(R.drawable.ic_tab_star))
.setContent(intent);
tabHost.addTab(spec);

tabHost.setCurrentTab(2);
}
}


LocalManager の startActivity() メソッドのリファレンスでも触れられているように、Activity のライフサイクルをちゃんと管理しないとダメでしょうね。

ここでは、

 * Intent が現在は知っているのとは異なる Activity コンポーネントにマップされる場合、現在の Activity は finish して、新しいのがスタートする。

* 現在の Activity が non-multiple launch mode (singleTop のような) を使っている場合、もしくは Intent に FLAG_ACTIVITY_SINGLE_TOP flag がセットされている場合、現在の Activity は走ったまま残り、Activity.onNewIntent() メソッドが呼ばれる。

* 新しい Intent が extras を除いて以前のと同じで、新しい Intent に FLAG_ACTIVITY_CLEAR_TOP が設定されていない場合、現在の Activity はそのままの状態で走り続ける。

* それ以外の場合、現在の Activity は finish して新しいのがスタートする

などが書かれています。


タブの中で画面遷移するサンプル zip はこちら ActivityGroupSample2.zip