API レベル: 17
Android 4.2(JELLY_BEAN_MR1
)は Jelly Bean リリースのアップデートであり、ユーザーとアプリ デベロッパー向けに新機能を提供します。このドキュメントでは、デベロッパー向けの最も注目すべき有用な新しい API の概要を説明します。
アプリ デベロッパーは、できるだけ早く SDK Manager から Android 4.2 のシステム イメージと SDK プラットフォームをダウンロードする必要があります。アプリをテストするための Android 4.2 を搭載したデバイスがない場合は、Android 4.2 システム イメージを使用して Android Emulator でアプリをテストします。次に、Android 4.2 プラットフォームに対応したアプリをビルドし、最新の API の使用を開始します。
Android 4.2 搭載デバイス向けにアプリをより適切に最適化するには、targetSdkVersion
を "17"
に設定し、Android 4.2 システム イメージにインストールしてテストし、この変更を含むアップデートを公開する必要があります。
Android 4.2 の API を使用しながら、古いバージョンもサポートするには、minSdkVersion
でサポートされていない API を実行する前に、システム API レベルをチェックする条件をコードに追加します。下位互換性の維持について詳しくは、下位互換性のある UI の作成をご覧ください。
API レベルの仕組みについて詳しくは、API レベルとはをご覧ください。
重要な動作の変更点
以前に Android 向けアプリを公開したことがある場合は、アプリの動作に影響する可能性がある次の変更に注意してください。
- コンテンツ プロバイダはデフォルトでエクスポートされなくなりました。つまり、
android:exported
属性のデフォルト値は“false"
です。他のアプリからコンテンツ プロバイダにアクセスできるようにする必要がある場合は、android:exported="true"
を明示的に設定する必要があります。この変更は、
android:targetSdkVersion
またはandroid:minSdkVersion
を 17 以上に設定した場合にのみ有効になります。それ以外の場合、Android 4.2 以降で実行している場合でも、デフォルト値は“true"
のままです。 - 以前のバージョンの Android と比較すると、アプリが
ACCESS_COARSE_LOCATION
権限をリクエストしてもACCESS_FINE_LOCATION
権限をリクエストしていない場合、ユーザーの位置情報の結果の精度が低下することがあります。ユーザーのプライバシー保護に応えるために、アプリが精度の高い位置情報ではなくおおよその位置情報の利用許可をリクエストする場合、都市ブロックより正確なユーザー位置情報の推定値は提供されません。
Settings.System
で定義された一部のデバイス設定が読み取り専用になりました。Settings.System
で定義された設定のうち、Settings.Global
に移行されたものをアプリが書き込もうとすると、Android 4.2 以上での実行時に、書き込みオペレーションは通知なく失敗します。android:targetSdkVersion
とandroid:minSdkVersion
の値が 17 未満であっても、Android 4.2 以降でのアプリの実行時にSettings.Global
に移動した設定は変更できません。- アプリで
WebView
を使用している場合、Android 4.2 ではセキュリティ レイヤが追加され、より安全に JavaScript を Android コードにバインドできます。targetSdkVersion
を 17 以上に設定する場合、JavaScript で使用できるようにするメソッドに@JavascriptInterface
アノテーションを追加する必要があります(メソッドもパブリックである必要があります)。アノテーションを指定しないと、Android 4.2 以降で実行しているWebView
のウェブページからこのメソッドにアクセスできません。targetSdkVersion
を 16 以下に設定する場合、アノテーションは不要ですが、ターゲット バージョンを更新してアノテーションを追加することにより、セキュリティを強化することをおすすめします。詳しくは、JavaScript コードを Android コードにバインドするをご覧ください。
Daydream
Daydream は、Android デバイス向けの新しいインタラクティブなスクリーンセーバー モードです。この機能は、デバイスをホルダーに挿入したときや、充電器に接続している状態でアイドル状態のまま(画面がオフになるのではなく)放置されているときに、自動的に有効になります。Daydream は、一度に 1 つの夢を表示します。これは、タッチすると消える純粋に視覚的なパッシブ ディスプレイの場合もあれば、すべての入力イベントにインタラクティブで応答性がある場合もあります。夢はアプリのプロセスで実行されます。Android UI ツールキット(ビュー、レイアウト、アニメーションなど)へのフルアクセスが可能なため、ライブ壁紙やアプリ ウィジェットよりも柔軟で強力になります。
Daydream の夢を作成するには、DreamService
のサブクラスを実装します。DreamService
API は、Activity
の API と同様の設計になっています。目的に合った UI を指定するには、ウィンドウの取得後(onAttachedToWindow()
コールバックなど)の任意の時点で、レイアウト リソース ID または View
を setContentView()
に渡します。
DreamService
クラスは、基本の Service
API に加えて、onDreamingStarted()
、onDreamingStopped()
、onDetachedFromWindow()
などの重要なライフサイクル コールバック メソッドを提供します。DreamService
は、システムによって自動的に起動されるため、アプリから開始することはできません。
Dream がインタラクティブな場合は、Dream からアクティビティを開始し、ユーザーをアプリのフル UI に誘導して、詳細やコントロールを行えるようにできます。finish()
を使用して Dream を終了し、ユーザーが新しいアクティビティを表示できるようにします。
システムで daydream を利用できるようにするには、マニフェスト ファイルで <service>
要素を使用して DreamService
を宣言します。次に、アクション "android.service.dreams.DreamService"
を含むインテント フィルタを含める必要があります。次に例を示します。
<service android:name=".MyDream" android:exported="true" android:icon="@drawable/dream_icon" android:label="@string/dream_label" > <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
DreamService
には他にも注意すべき便利なメソッドがいくつかあります。
setInteractive(boolean)
は、Dream が入力イベントを受け取るか、ユーザー入力直後に終了するかを制御します。dream がインタラクティブの場合、ユーザーは [戻る] ボタンまたは [ホーム] ボタンを使用して dream を終了できます。また、finish()
を呼び出して dream を停止することもできます。- 完全に没入できるディスプレイが必要な場合は、
setFullscreen()
を呼び出してステータスバーを非表示にできます。 - Daydream が開始する前に、ディスプレイが暗くなり、アイドル タイムアウトが近づいていることをユーザーに知らせます。
setScreenBright(true)
を呼び出すと、ディスプレイを通常の明るさに設定できます。
詳細については、DreamService
のドキュメントをご覧ください。
セカンダリ ディスプレイ
Android では、有線接続または Wi-Fi でユーザーのデバイスに接続されている追加画面に、アプリで独自のコンテンツを表示できるようになりました。セカンダリ ディスプレイ用に独自のコンテンツを作成するには、Presentation
クラスを拡張して onCreate()
コールバックを実装します。onCreate()
内で、setContentView()
を呼び出してセカンダリ ディスプレイの UI を指定します。Dialog
クラスの拡張として、Presentation
クラスは、アプリがセカンダリ ディスプレイに一意の UI を表示できる領域を提供します。
Presentation
を表示できるセカンダリ ディスプレイを検出するには、DisplayManager
API または MediaRouter
API を使用します。DisplayManager
API を使用すると、一度に接続される複数のディスプレイを列挙できますが、通常は MediaRouter
を使用して、システムのプレゼンテーションのデフォルト ディスプレイにすばやくアクセスする必要があります。
プレゼンテーションのデフォルト表示を取得するには、MediaRouter.getSelectedRoute()
を呼び出して ROUTE_TYPE_LIVE_VIDEO
を渡します。これにより、システムで現在選択されている動画プレゼンテーションのルートを表す MediaRouter.RouteInfo
オブジェクトが返されます。MediaRouter.RouteInfo
が null でない場合、getPresentationDisplay()
を呼び出して、接続されたディスプレイを表す Display
を取得します。
次に、Display
オブジェクトを Presentation
クラスのコンストラクタに渡して、プレゼンテーションを表示できます。プレゼンテーションがセカンダリ ディスプレイに表示されます。
実行時に新しいディスプレイが接続されたことを検出するには、MediaRouter.SimpleCallback
のインスタンスを作成し、その中で onRoutePresentationDisplayChanged()
コールバック メソッドを実装します。このメソッドは、新しいプレゼンテーション ディスプレイが接続されたときにシステムによって呼び出されます。次に、ROUTE_TYPE_LIVE_VIDEO
ルートタイプとともに MediaRouter.addCallback()
に渡して、MediaRouter.SimpleCallback
を登録します。onRoutePresentationDisplayChanged()
への呼び出しを受け取った場合は、上記のように MediaRouter.getSelectedRoute()
を呼び出します。
セカンダリ画面の Presentation
の UI をさらに最適化するには、アプリまたはアクティビティに適用した <style>
で android:presentationTheme
属性を指定して、別のテーマを適用します。
ユーザーのデバイスに接続されている画面は、画面サイズのほうが大きく、画面密度も異なる傾向があることに留意してください。画面の特性は異なる場合があるため、そのような大きなディスプレイ向けに最適化されたリソースを用意する必要があります。Presentation
から追加のリソースをリクエストする必要がある場合は、getContext()
.getResources()
を呼び出して、ディスプレイに対応する Resources
オブジェクトを取得します。これにより、セカンダリ ディスプレイの画面サイズと密度に最適な、アプリからの適切なリソースが提供されます。
詳細とコードサンプルについては、Presentation
クラスのドキュメントをご覧ください。
ロック画面ウィジェット
Android では、ユーザーがアプリ ウィジェットをロック画面に追加できるようになりました。アプリ ウィジェットをロック画面で使用できるようにするには、AppWidgetProviderInfo
を指定する XML ファイルに android:widgetCategory
属性を追加します。この属性は、home_screen
と keyguard
の 2 つの値をサポートします。この属性はデフォルトで home_screen
に設定されているため、ユーザーはアプリ ウィジェットをホーム画面に追加できます。アプリ ウィジェットをロック画面でも利用できるようにする場合は、keyguard
の値を追加します。
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
また、ロック画面でアプリ ウィジェットの初期レイアウトを android:initialKeyguardLayout
属性で指定する必要があります。これは、アプリ ウィジェットが初期化されてレイアウトを更新できるまですぐに表示できるレイアウトを提供するという点で、android:initialLayout
と同じように機能します。
ロック画面でアプリ ウィジェットを作成する方法など、ロック画面用のアプリ ウィジェットの作成について詳しくは、アプリ ウィジェットのガイドをご覧ください。
複数ユーザー
Android では、タブレットなどの共有可能なデバイスで複数のユーザー スペースを利用できるようになりました。デバイス上の各ユーザーには、独自のアカウント、アプリ、システム設定、ファイル、その他のユーザー関連データのセットがあります。
アプリ デベロッパーは、1 つのデバイスで複数のユーザーを対象としてアプリを正しく動作させるために、何か特別なことをする必要はありません。デバイスに存在するユーザー数に関係なく、アプリが特定のユーザーについて保存するデータは、アプリが他のユーザーのために保存するデータとは区別して保存されます。システムは、アプリが実行されているユーザー プロセスに属するユーザーデータを追跡し、アプリがそのユーザーのデータにのみアクセスできるようにし、他のユーザーのデータにはアクセスできないようにします。
マルチユーザー環境でのデータの保存
アプリがユーザー設定を保存したり、データベースを作成したり、ユーザーの内部または外部ストレージにファイルを書き込むと、そのデータにアクセスできるのは、そのユーザーとして実行されているときのみです。
マルチユーザー環境でアプリが適切に動作するように、ハードコードされたパスを使用して内部アプリ ディレクトリや外部ストレージの場所を参照せず、常に適切な API を使用してください。
- 内部ストレージにアクセスするには、
getFilesDir()
、getCacheDir()
、またはopenFileOutput()
を使用します。 - 外部ストレージにアクセスするには、
getExternalFilesDir()
またはgetExternalStoragePublicDirectory()
を使用します。
特定のユーザーのデータを保存するためにどの API を使用しても、別のユーザーとして実行している間はデータにアクセスできません。アプリの観点からは、各ユーザーはまったく異なるデバイスで実行されています。
マルチユーザー環境でのユーザーの特定
分析情報を収集したり、他のアカウントの関連付けを作成したりするなどして、アプリでユニーク ユーザーを識別する場合は、一意のインストールを識別するための推奨方法に従う必要があります。アプリの初回起動時に新しい UUID
を作成することで、1 台のデバイスにアプリをインストールしたユーザーの数に関係なく、各ユーザーをトラッキングするための一意の ID を確実に取得できます。または、サーバーから取得したローカル トークンを保存するか、Google Cloud Messaging が提供する登録 ID を使用できます。
アプリがハードウェア デバイス識別子(Wi-Fi MAC アドレスや SERIAL
番号など)のいずれかをリクエストする場合、これらの識別子はユーザーではなくハードウェアに関連付けられているため、どのユーザーも同じ値を提供します。言うまでもなく、これらの識別子が原因で発生するその他の問題については、アプリのインストールを特定するブログ投稿をご覧ください。
新しい全般設定
Settings.Global
の追加により、複数のユーザーをサポートするようにシステム設定が更新されました。この一連の設定は読み取り専用であるため、Settings.Secure
設定と似ていますが、デバイス上のすべてのユーザー空間にグローバルに適用されます。
いくつかの既存の設定が、Settings.System
または Settings.Secure
からここに移動しました。以前 Settings.System
で定義した設定(AIRPLANE_MODE_ON
など)をアプリが現在変更している場合、Android 4.2 以降を搭載しているデバイスでは、これらの設定を Settings.Global
に移行すると、この変更が機能しなくなります。Settings.Global
にある設定は引き続き読み取ることができますが、この設定はアプリを変更しても安全とはみなされなくなったため、変更しようとすると通知なく失敗し、Android 4.2 以降でアプリを実行すると、システムログに警告が書き込まれます。
RTL レイアウトのサポート
Android では、レイアウトの向きを適切に変換するユーザー インターフェースを作成できる API がいくつか提供され、右から左(RTL)UI を使用する言語や、アラビア語やヘブライ語などの読み上げ方向を使用する言語をサポートできるようになりました。
アプリで RTL レイアウトのサポートを開始するには、マニフェスト ファイルの <application>
要素に android:supportsRtl
属性を設定し、“true"
に設定します。有効にすると、さまざまな RTL API が有効になり、アプリを RTL レイアウトで表示できるようになります。たとえば、アクションバーの右側にはアイコンとタイトル、左側にアクション ボタンが表示されます。フレームワークが提供する View
クラスで作成したレイアウトも逆になります。
RTL レイアウトで表示したときのアプリの外観をさらに最適化する必要がある場合は、次の 2 つの基本的なレベルで最適化を行います。
- 左向きと右向きのレイアウト プロパティを、開始向きと終了向きのレイアウト プロパティに変換します。
たとえば、
android:layout_marginLeft
の代わりにandroid:layout_marginStart
を、android:layout_marginRight
の代わりにandroid:layout_marginEnd
を使用します。RelativeLayout
クラスには、左右の位置を置き換える対応するレイアウト属性も用意されています。たとえば、android:layout_toLeftOf
の代わりにandroid:layout_alignParentLeft
とandroid:layout_toStartOf
を置き換えるandroid:layout_alignParentStart
などです。 - RTL レイアウトを完全に最適化するには、
ldrtl
リソース修飾子(ldrtl
は layout-direction-right-to-left} の略)を使用して、完全に個別のレイアウト ファイルを指定します。たとえば、デフォルトのレイアウト ファイルはres/layout/
に保存し、RTL に最適化されたレイアウトはres/layout-ldrtl/
に保存できます。ldrtl
修飾子はドローアブル リソースに適しています。そのため、読み取り方向に対応する向きのグラフィックを提供できます。
RTL レイアウトをサポートする他のさまざまな API がフレームワーク全体で利用可能です。たとえば、View
クラスではカスタムビューに適切な動作を実装でき、Configuration
では現在のレイアウト方向をクエリできます。
注: SQlite を使用していて、「数値のみ」のテーブル名または列名がある場合は、注意が必要です。デバイスがアラビア語ロケールに設定されている場合に、String.format(String, Object...)
を使用すると、対応する数字がアラビア語に変換されてエラーが発生する可能性があります。数値が ASCII として保持されるようにするには、String.format(Locale,String,Object...)
を使用する必要があります。また、数値の書式設定には String.valueOf(int)
ではなく String.format("%d", int)
を使用します。
Fragment のネスト
フラグメントをフラグメント内に埋め込むことができるようになりました。これは、動的で再利用可能な UI コンポーネントを、それ自体が動的で再利用可能な UI コンポーネントに配置する、さまざまな状況で役立ちます。たとえば、ViewPager
を使用して左右にスワイプして画面スペースの大部分を消費するフラグメントを作成する場合、各フラグメント ページにフラグメントを挿入できるようになりました。
フラグメントをネストするには、フラグメントを追加する Fragment
で getChildFragmentManager()
を呼び出します。これにより FragmentManager
が返されます。これをトップレベル アクティビティから通常どおり使用してフラグメント トランザクションを作成できます。たとえば、既存の Fragment
クラス内からフラグメントを追加するコードは次のようになります。
Kotlin
val videoFragment = VideoPlayerFragment() childFragmentManager.beginTransaction().apply { add(R.id.video_fragment, videoFragment) commit() }
Java
Fragment videoFragment = new VideoPlayerFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.video_fragment, videoFragment).commit();
ネストされたフラグメント内から、getParentFragment()
を呼び出すことで、親フラグメントへの参照を取得できます。
Android サポート ライブラリでは、ネストされたフラグメントもサポートされるようになりました。これにより、Android 1.6 以降では、ネストされたフラグメントの設計を実装できます。
注: レイアウトに <fragment>
が含まれている場合、レイアウトをフラグメントにインフレートすることはできません。ネストされたフラグメントは、フラグメントに動的に追加される場合にのみサポートされます。
Renderscript
RenderScript の計算機能が拡張され、次の機能が追加されました。
- スクリプト組み込み関数
次のような一般的なオペレーションを実装する、Renderscript の組み込みスクリプト組み込みを使用できます。
Blends
Blur
Color matrix
3x3 convolve
5x5 convolve
Per-channel lookup table
Converting an Android YUV buffer to RGB
スクリプト組み込みを使用するには、各組み込み関数の静的
create()
メソッドを呼び出して、スクリプトのインスタンスを作成します。次に、組み込みスクリプトごとに使用可能なset()
メソッドを呼び出して、必要な入力とオプションを設定します。最後に、forEach()
メソッドを呼び出してスクリプトを実行します。- スクリプト グループ
-
ScriptGroup
を使用すると、関連する RenderScript スクリプトを連結し、1 回の呼び出しで実行できます。ScriptGroup.Builder
を使用し、addKernel()
を呼び出してすべてのスクリプトをグループに追加します。すべてのスクリプトを追加したら、addConnection()
を呼び出してスクリプト間の接続を作成します。接続の追加が完了したら、create()
を呼び出してスクリプト グループを作成します。スクリプト グループを実行する前に、入力Allocation
とsetInput(Script.KernelID, Allocation)
メソッドで実行する初期スクリプトを指定し、結果が書き込まれる出力Allocation
と、setOutput()
で実行する最終的なスクリプトを指定します。最後に、execute()
を呼び出してスクリプト グループを実行します。 - FilterScript
-
Filterscript は既存の Renderscript API に制約を定義します。これにより、生成されるコードをさまざまなプロセッサ(CPU、GPU、DSP)で実行できるようになります。Filterscript ファイルを作成するには、
.rs
ファイルではなく.fs
ファイルを作成し、#pragma rs_fp_relaxed
を指定して、スクリプトが厳格な IEEE 754-2008 浮動小数点精度を必要としないことを Renderscript ランタイムに伝えます。この精度により、denorms のゼロへのフラッシュとゼロへの丸めが可能になります。また、Filterscript スクリプトでは 32 ビットの組み込み型を使用せず、__attribute__((kernel))
属性を使用してカスタムルート関数を指定する必要があります。これは、root()
関数のデフォルトのシグネチャで定義されているポインタが Filterscript でサポートされていないためです。
注: Filterscript のサポートはプラットフォームに存在しますが、デベロッパー サポートは SDK Tools リリース 21.0.1 で利用できるようになります。
Android 4.2 におけるすべての API の変更点について詳しくは、API 差分レポートをご覧ください。