Android 4.2 API

API レベル: 17

Android 4.2(JELLY_BEAN_MR1)は Jelly Bean リリースのアップデートであり、ユーザーとアプリ デベロッパー向けに新機能を提供します。このドキュメントでは、デベロッパー向けの特に注目すべき新しい API を紹介します。

アプリ デベロッパーは、Android 4.2 のシステム イメージと SDK プラットフォームを、できるだけ早く SDK Manager からダウンロードする必要があります。アプリをテストするための 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:targetSdkVersionandroid:minSdkVersion の値が 17 未満であっても、Android 4.2 以上での実行時に Settings.Global に移動した設定をアプリで変更することはできません。

  • アプリで WebView を使用している場合、Android 4.2 ではセキュリティのレイヤが追加され、より安全に JavaScript を Android コードにバインドできます。targetSdkVersion を 17 以上に設定した場合、JavaScript で使用できるようにするメソッドに @JavascriptInterface アノテーションを追加する必要があります(メソッドもパブリックである必要があります)。アノテーションを指定しない場合、Android 4.2 以降で稼働中に WebView のウェブページからメソッドにアクセスできません。targetSdkVersion を 16 以下に設定している場合、このアノテーションは不要ですが、ターゲット バージョンを更新して、セキュリティ強化のためにアノテーションを追加することをおすすめします。

    詳しくは、Android コードへの JavaScript コードのバインドをご覧ください。

Daydream

Daydream は、Android デバイス向けの新しいインタラクティブなスクリーンセーバー モードです。デバイスをホルダーに挿入した場合や、充電器に接続している状態でアイドル状態のままの場合に、(画面をオフにせずに)自動的にアクティブになります。Daydream は、一度に 1 つの夢を表示します。これは、タップによって閉じられる純粋に視覚的なパッシブなディスプレイである場合もあれば、すべての入力イベントに反応して応答する場合もあります。夢はアプリのプロセスで実行され、ビュー、レイアウト、アニメーションなどの Android UI ツールキットに完全にアクセスできるため、ライブ壁紙やアプリ ウィジェットよりも柔軟でパワフルです。

DreamService のサブクラスを実装することで、Daydream の dream を作成できます。DreamService API は、Activity の API と同様の設計になっています。夢のような UI を指定するには、ウィンドウが作成された後(onAttachedToWindow() コールバックなど)の任意の時点でレイアウト リソース ID または ViewsetContentView() に渡します。

DreamService クラスは、基本の Service API(onDreamingStarted()onDreamingStopped()onDetachedFromWindow() など)に加えて、その他の重要なライフサイクル コールバック メソッドを提供します。DreamService はアプリから起動できません。アプリは自動的に起動します。

インタラクティブな機能があれば、その夢の中のアクティビティを開始して、アプリの 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() コールバック メソッドを実装します。このメソッドは、新しいプレゼンテーション ディスプレイが接続されたときにシステムによって呼び出されます。次に、MediaRouter.SimpleCallbackROUTE_TYPE_LIVE_VIDEO ルートタイプとともに MediaRouter.addCallback() に渡して登録します。onRoutePresentationDisplayChanged() への呼び出しを受け取った場合は、上記のように MediaRouter.getSelectedRoute() を呼び出します。

セカンダリ画面用に Presentation の UI をさらに最適化するには、アプリまたはアクティビティに適用した <style>android:presentationTheme 属性を指定して、別のテーマを適用します。

ユーザーのデバイスに接続されている画面は、画面サイズがより大きく、画面密度が異なる可能性が高いことにご注意ください。画面の特性が異なる可能性があるため、そのような大きなディスプレイ向けに最適化されたリソースを提供する必要があります。Presentation から追加のリソースをリクエストする必要がある場合は、getContext().getResources() を呼び出して、ディスプレイに対応する Resources オブジェクトを取得します。これにより、セカンダリ ディスプレイの画面サイズと密度に最適な、アプリから適切なリソースが提供されます。

詳細とコードサンプルについては、Presentation クラスのドキュメントをご覧ください。

ロック画面ウィジェット

Android では、ロック画面にアプリ ウィジェットを追加できるようになりました。アプリ ウィジェットをロック画面で使用できるようにするには、AppWidgetProviderInfo を指定する XML ファイルに android:widgetCategory 属性を追加します。この属性は、home_screenkeyguard の 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 を使用してください。

どの 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 では、右から左(RTL)UI(アラビア語やヘブライ語など)や読み上げ方向を使用する言語をサポートするために、レイアウトの向きを適切に変換するユーザー インターフェースを構築できる API をいくつか提供しています。

アプリで RTL レイアウトのサポートを開始するには、マニフェスト ファイルで android:supportsRtl 属性を <application> 要素に設定し、“true" に設定します。有効にすると、さまざまな RTL API が有効になり、アプリを RTL レイアウトで表示できます。たとえば、アクションバーの右側にはアイコンとタイトル、左側にはアクション ボタンが表示されます。フレームワークが提供する View クラスで作成したレイアウトも逆になります。

RTL レイアウトで表示したときのアプリの外観をさらに最適化する必要がある場合は、基本的な最適化レベルが 2 つあります。

  1. 左向きと右向きのレイアウト プロパティを、開始向きと終了向きのレイアウト プロパティに変換します。

    たとえば、android:layout_marginLeft の代わりに android:layout_marginStart を使用し、android:layout_marginRight の代わりに android:layout_marginEnd を使用します。

    RelativeLayout クラスには、左右の位置を置き換える対応するレイアウト属性も用意されています。たとえば、android:layout_toLeftOf の代わりに android:layout_alignParentLeftandroid:layout_toStartOf を置き換える android:layout_alignParentStart などです。

  2. または、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 を使用して、左右にスワイプして画面領域の大部分を消費するフラグメントを作成する場合、各フラグメント ページにフラグメントを挿入できるようになりました。

フラグメントをネストするには、単に、フラグメントを追加する FragmentgetChildFragmentManager() を呼び出します。これは 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 の組み込みスクリプト組み込み関数を使用して、次のような一般的なオペレーションを実装できます。

スクリプト組み込みを使用するには、各組み込み機能の静的 create() メソッドを呼び出して、スクリプトのインスタンスを作成します。次に、各組み込みスクリプトで使用可能な set() メソッドを呼び出して、必要な入力とオプションを設定します。最後に、forEach() メソッドを呼び出してスクリプトを実行します。

スクリプト グループ

ScriptGroup を使用すると、関連する Renderscript スクリプトを連結して 1 回の呼び出しで実行できます。

ScriptGroup.Builder を使用して addKernel() を呼び出して、すべてのスクリプトをグループに追加します。すべてのスクリプトを追加したら、addConnection() を呼び出してスクリプト間の接続を作成します。接続の追加が完了したら、create() を呼び出してスクリプト グループを作成します。スクリプト グループを実行する前に、setInput(Script.KernelID, Allocation) メソッドで実行する入力 Allocation と初期スクリプトを指定します。また、結果が書き込まれる出力 Allocation と、setOutput() で実行する最終スクリプトを指定します。最後に、execute() を呼び出してスクリプト グループを実行します。

Filterscript

Filterscript は、結果のコードをさまざまなプロセッサ(CPU、GPU、DSP)で実行できるようにする既存の Renderscript API の制約を定義します。Filterscript ファイルを作成するには、.rs ファイルの代わりに .fs ファイルを作成し、#pragma rs_fp_relaxed を指定して、スクリプトが厳格な IEEE 754-2008 浮動小数点精度を必要としないことを Renderscript ランタイムに伝えます。この精度により、Denorm のゼロへのフラッシュとゼロへの丸めが可能になります。また、Filterscript は、32 ビットの組み込み型を使用せず、__attribute__((kernel)) 属性を使用してカスタムルート関数を指定する必要があります。これは、root() 関数のデフォルトの署名として定義されるポインタをサポートしていないためです。

注: Filterscript のサポートはプラットフォームに用意されていますが、デベロッパー サポートは SDK Tools リリース 21.0.1 で提供される予定です。

Android 4.2 で行われた API の変更点について詳しくは、API の違いレポートをご覧ください。