Android 8.0 で設定アプリの新しい情報アーキテクチャが導入されて設定の構成方法がシンプルになり、ユーザーは Android デバイスをカスタマイズするための設定を簡単に見つけられるようになりました。Android 9 では、設定機能を追加して実装を簡略化する改善が行われました。
例とソース
現在、設定のほとんどのページは新しいフレームワークを使用して実装されています。そのわかりやすい例は DisplaySettings です(packages/apps/Settings/src/com/android/settings/DisplaySettings.java
)。
重要なコンポーネントのファイルパスを以下に示します。
- CategoryKey:
packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
- DashboardFragmentRegistry:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
- DashboardFragment:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
- AbstractPreferenceController:
frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
- BasePreferenceController(Android 9 で導入):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
実装
デバイス メーカーは、既存の設定の情報アーキテクチャを調整し、パートナー固有の機能に合わせて必要に応じて追加の設定ページを挿入することをおすすめします。以前のページ(SettingsPreferencePage
として実装されている)から新しいページ(DashboardFragment
を使用して実装される)に設定を移動する作業は複雑な場合があります。以前のページの設定が、PreferenceController
で実装されない可能性があるためです。
したがって、以前のページから新しいページに設定を移動する場合は、PreferenceController
を作成し、新しい DashboardFragment
でインスタンス化する前にコードをコントローラに移動する必要があります。PreferenceController
に必要な API は、Javadoc にそれぞれの名前が記述されています。
PreferenceController
ごとに単体テストを追加することを強くおすすめします。
変更を AOSP に送信する場合は、単体テストが必要です。
Robolectric ベースのテストの記述方法について詳しくは、readme ファイル packages/apps/Settings/tests/robotests/README.md
をご覧ください。
プラグインスタイルの情報アーキテクチャ
各設定項目は、Preference として実装されます。Preference はページ間で簡単に移動できます。
複数の設定を簡単に移動できるように、Android 8.0 には設定項目を含むプラグインスタイルのホスト フラグメントが導入されています。設定項目は、プラグインスタイルのコントローラとしてモデル化されます。したがって、設定ページは 1 つのホスト フラグメントと複数の設定コントローラで構成されます。
DashboardFragment
DashboardFragment
は、プラグインスタイルの設定コントローラのホストです。
このフラグメントは PreferenceFragment
を継承し、静的設定リストと動的設定リストの両方を展開して更新するフックを備えています。
静的設定
静的設定リストは、XML で <Preference>
タグを使用して定義されます。DashboardFragment
実装では、表示する設定の静的リストを含む XML ファイルの定義に getPreferenceScreenResId()
メソッドが使用されます。
動的設定
動的項目とは、外部または内部アクティビティを引き起こすインテント付きタイルのことです。通常は、インテントによって別の設定ページが表示されます。たとえば、設定ホームページの「Google」設定項目は動的項目です。動的項目は AndroidManifest
(以下で説明)で定義され、FeatureProvider
(
DashboardFeatureProvider
として定義)によって読み込まれます。
動的設定は静的に行われる設定よりも規模が大きくなるため、通常はデベロッパーが静的設定として設定を実装する必要があります。ただし、次のいずれかに該当するケースでは動的設定が有用な場合があります。
- 設定が設定アプリに直接実装されない(OEM アプリや携帯通信会社アプリによって実装された設定を追加する場合など)。
- 設定を設定ホームページに表示する必要がある。
- 設定のアクティビティがすでに存在し、追加の静的設定を実装したくない。
動的設定としてアクティビティを設定する方法は次のとおりです。
- アクティビティにインテントフィルタを追加することで、アクティビティを動的設定として指定します。
- 設定アプリに所属カテゴリを通知します。カテゴリは、
CategoryKey
で定義されている定数です。 - (省略可)設定が表示されるときの概要テキストを追加します。
設定アプリの DisplaySettings
の例を次に示します。
<activity android:name="Settings$DisplaySettingsActivity" android:label="@string/display_settings" android:icon="@drawable/ic_settings_display"> <!-- Mark the activity as a dynamic setting --> <intent-filter> <action android:name="com.android.settings.action.IA_SETTINGS" /> </intent-filter> <!-- Tell Settings app which category it belongs to --> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.ia.homepage" /> <!-- Add a summary text when the setting is displayed --> <meta-data android:name="com.android.settings.summary" android:resource="@string/display_dashboard_summary"/> </activity>
レンダリング時に、フラグメントは AndroidManifest
で定義された静的 XML と動的設定の両方の Preference リストを要求します。PreferenceController
が Java コードまたは XML のいずれで定義されていても、DashboardFragment
は各設定の処理ロジックを PreferenceController
(以下で説明)を介して管理します。これらは、混合リストとして UI に表示されます。
PreferenceController
このセクションで説明するように、Android 9 と Android 8.x では PreferenceController
の実装に違いがあります。
Android 9 リリースの PreferenceController
PreferenceController
には、表示、更新、検索インデックスなど、設定を操作するためのロジックがすべて含まれています。
PreferenceController
のインターフェースは BasePreferenceController
として定義されています。例については、packages/apps/Settings/src/com/android/settings/core/
BasePreferenceController.java
のコードをご覧ください。
BasePreferenceController
には複数のサブクラスがあり、設定アプリがデフォルトでサポートする特定の UI スタイルにそれぞれ関連付けられています。たとえば、TogglePreferenceController
の API はユーザーがトグルベースの設定 UI を操作する方法に直接関連付けられています。
BasePreferenceController
には、getAvailabilityStatus()
、displayPreference()
、handlePreferenceTreeClicked(),
などの API が用意されています。各 API の詳細なドキュメントはインターフェース クラスにあります。
BasePreferenceController
(および TogglePreferenceController
などのサブクラス)の実装に関する制限として、コンストラクタ シグネチャが次のいずれかに一致する必要があります。
public MyController(Context context, String key) {}
public MyController(Context context) {}
フラグメントに設定をインストールする際、表示時間より前に PreferenceController
をアタッチするメソッドがダッシュボードに表示されます。インストール時にコントローラがフラグメントに接続されるため、以降の関連イベントはすべてコントローラに送信されます。
DashboardFragment
によって、PreferenceController
のリストが画面に引き続き表示されます。フラグメントの onCreate()
で、すべてのコントローラが getAvailabilityStatus()
メソッド用に呼び出され、true が返されると、表示ロジックを処理するために displayPreference()
が呼び出されます。検索時に使用できる項目を設定フレームワークに指定するために、getAvailabilityStatus()
も重要です。
Android 8.x リリースの PreferenceController
PreferenceController
には、表示、更新、検索インデックスなど、設定を操作するためのロジックがすべて含まれています。
設定操作に対応して、
PreferenceController
のインターフェースには isAvailable()
、
displayPreference()
、handlePreferenceTreeClicked()
などの API が用意されています。各 API の詳細なドキュメントはインターフェース クラスにあります。
フラグメントに設定をインストールする際、表示時間より前に PreferenceController
をアタッチするメソッドがダッシュボードに表示されます。インストール時にコントローラがフラグメントに接続されるため、以降の関連イベントはすべてコントローラに送信されます。
DashboardFragment
によって、PreferenceControllers
のリストが画面に引き続き表示されます。フラグメントの onCreate()
で、すべてのコントローラが isAvailable()
メソッド用に呼び出され、true が返されると、表示ロジックを処理するために displayPreference()
が呼び出されます。
DashboardFragment の使用
ページ A から B への設定の移動
設定が元のページの設定 XML ファイルに静的に記載されている場合は、以下の該当する Android リリースの静的移動手順を実施してください。静的に記載されていない場合は、該当する Android リリースの動的移動手順を実施してください。
Android 9 での静的移動
- 元のページと移動先ページの設定 XML ファイルを探します。この情報はページの
getPreferenceScreenResId()
メソッドで確認できます。 - 元のページの XML から設定を削除します。
- 移動先ページの XML に設定を追加します。
- 元のページの Java 実装から、この設定の
PreferenceController
を削除します。通常はcreatePreferenceControllers()
にあります。コントローラは XML で直接宣言できます。注: 設定に
PreferenceController
が含まれていない場合もあります。 - 移動先ページの
createPreferenceControllers()
でPreferenceController
をインスタンス化します。古いページでPreferenceController
が XML で定義されている場合は、新しいページでも XML で定義します。
Android 9 での動的移動
- 元のページと移動先ページがホストするカテゴリを確認します。この情報は
DashboardFragmentRegistry
で確認できます。 - 移動する設定を含む
AndroidManifest.xml
ファイルを開き、この設定を表す Activity エントリを探します。 com.android.settings.category
のアクティビティのメタデータ値を新しいページのカテゴリキーに設定します。
Android 8.x リリースでの静的移動
- 元のページと移動先ページの設定 XML ファイルを探します。 この情報はページの
- 元のページの XML で設定を削除します。
- 移動先ページの XML に設定を追加します。
- 元のページの Java 実装で、この設定の
PreferenceController
を削除します。通常はgetPreferenceControllers()
にあります。 - 移動先ページの
getPreferenceControllers()
でPreferenceController
をインスタンス化します。
getPreferenceScreenResId()
メソッドで確認できます。
注: 設定に PreferenceController
が含まれていない場合もあります。
Android 8.x リリースでの動的移動
- 元のページと移動先ページがホストするカテゴリを確認します。この情報は
DashboardFragmentRegistry
で確認できます。 - 移動する設定を含む
AndroidManifest.xml
ファイルを開き、この設定を表す Activity エントリを探します。 com.android.settings.category
のアクティビティのメタデータ値を変更し、値点を新しいページのカテゴリキーに設定します。
ページの新しい設定の作成
設定が元のページの設定 XML ファイルに静的に記載されている場合は、以下の静的手順を実施してください。静的に記載されていない場合は、動的手順を実施してください。
静的設定の作成
- ページの設定 XML ファイルを探します。この情報は、ページの getPreferenceScreenResId() メソッドで確認できます。
- XML に新しい Preference 項目を追加します。一意の
android:key
があることを確認します。 - ページの
getPreferenceControllers()
メソッドで、この設定のPreferenceController
を定義します。- Android 8.x と Android 9(任意)では、ページの
createPreferenceControllers()
メソッドでこの設定のPreferenceController
をインスタンス化します。この設定がすでに他の場所に存在していた場合は、その設定の
PreferenceController
も存在する可能性があります。PreferenceController
は新たに構築しなくても再利用が可能です。 -
Android 9 以降では、XML で設定の次に
PreferenceController
を宣言することもできます。次に例を示します。<Preference android:key="reset_dashboard" android:title="@string/reset_dashboard_title" settings:controller="com.android.settings.system.ResetPreferenceController"/>
- Android 8.x と Android 9(任意)では、ページの
動的設定の作成
- 元のページと移動先ページがホストするカテゴリを確認します。この情報は
DashboardFragmentRegistry
で確認できます。 AndroidManifest
で新しい Activity を作成します。- 必要なメタデータを新しい Activity に追加して、設定を定義します。
com.android.settings.category
のメタデータ値をステップ 1 で定義した値に設定します。
新しいページの作成
DashboardFragment
を継承する新しいフラグメントを作成します。- そのカテゴリを
DashboardFragmentRegistry
で定義します。注: このステップは省略可能です。このページに動的設定が必要ない場合、カテゴリキーを指定する必要はありません。
- このページに必要な設定を追加する手順を行います。詳細については、実装セクションをご覧ください。
検証
- 設定で robolectric テストを実行します。既存のテストと新しいテストのすべてに合格する必要があります。
- 設定をビルドおよびインストールしてから、変更するページを手動で開きます。 ページがすぐに更新される必要があります。