自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
偏好设置字幕
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
在大多数情况下,添加偏好设置摘要相对比较简单,因为这只涉及使用适当的字符串资源将 android:summary
属性添加到相应的偏好设置中。不过,如果字幕应动态更新,那么可能有必要使用自定义偏好设置控制器。
静态字幕
如需向偏好设置添加静态字幕,请执行以下操作:
- 将
android:summary
属性添加到偏好设置中。例如,如需向 L0 显示设置偏好设置添加摘要,请在偏好设置属性中添加以下内容:
android:summary="@string/display_settings_summary"
例如,考虑下面这个完整的偏好设置代码示例:
<Preference
android:fragment="com.android.car.settings.display.DisplaySettingsFragment"
android:icon="@drawable/ic_settings_display"
android:key="@string/pk_display_settings_entry"
android:title="@string/display_settings"
android:summary="@string/display_settings_summary"
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"/>
动态字幕
使用 android:summary
属性指定的字幕是静态的,因此无法根据特定条件进行更新。对于动态字幕,您需要修改相应偏好设置的偏好设置控制器。以下示例修改了 L0 位置信息偏好设置,使其具有如下的字幕:指定位置信息服务是处于开启还是关闭状态;如果处于开启状态,还会指明当前有权使用位置信息的应用数量。
- 定义新字符串:
<!-- Summary for Location settings when location is off [CHAR LIMIT=NONE] -->
<string name="location_settings_summary_location_off">Off</string>
<!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
<plurals name="location_settings_summary_location_on">
<item quantity="one">On - <xliff:g id="count">%1$d</xliff:g> app has access to location</item>
<item quantity="other">On - <xliff:g id="count">%1$d</xliff:g> apps have access to location</item>
</plurals>
<!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] -->
<string name="location_settings_loading_app_permission_stats">Loading\u2026</string>
- 创建一个新的 PreferenceController
LocationEntryPreferenceController
,以便动态设置和更改位置信息偏好设置摘要文本:
public class LocationEntryPreferenceController extends PreferenceController<Preference> {
private static final Logger LOG = new Logger(LocationEntryPreferenceController.class);
private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
private final Context mContext;
private final LocationManager mLocationManager;
/** Total number of apps that have location permissions. */
private int mNumTotal = -1;
private int mNumTotalLoading = 0;
private AtomicInteger mLoadingInProgress = new AtomicInteger(0);
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
refreshUi();
}
};
public LocationEntryPreferenceController(Context context, String preferenceKey,
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
super(context, preferenceKey, fragmentController, uxRestrictions);
mContext = context;
mLocationManager = (LocationManager) getContext().getSystemService(
Service.LOCATION_SERVICE);
}
@Override
protected Class<Preference> getPreferenceType() {
return Preference.class;
}
@Override
protected void onStartInternal() {
getContext().registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
}
@Override
protected void onStopInternal() {
getContext().unregisterReceiver(mReceiver);
}
@Override
protected void updateState(Preference preference) {
super.updateState(preference);
updateSummary(preference);
if (!mLocationManager.isLocationEnabled() || mLoadingInProgress.get() != 0) {
return;
}
mNumTotalLoading = 0;
// Retrieve a list of users inside the current user profile group.
List<UserHandle> users = mContext.getSystemService(
UserManager.class).getUserProfiles();
mLoadingInProgress.set(users.size());
for (UserHandle user : users) {
Context userContext = createPackageContextAsUser(mContext, user.getIdentifier());
if (userContext == null) {
if (mLoadingInProgress.decrementAndGet() == 0) {
setLocationAppCount(preference, mNumTotalLoading);
}
continue;
}
PermissionControllerManager permController =
userContext.getSystemService(PermissionControllerManager.class);
permController.countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED,
(numApps) -> {
mNumTotalLoading += numApps;
if (mLoadingInProgress.decrementAndGet() == 0) {
setLocationAppCount(preference, mNumTotalLoading);
}
}, null);
}
}
@VisibleForTesting
void setLocationAppCount(Preference preference, int numApps) {
mNumTotal = numApps;
updateSummary(preference);
}
private void updateSummary(Preference preference) {
String summary = "";
if (mLocationManager.isLocationEnabled()) {
if (mNumTotal == -1) {
summary = mContext.getString(R.string.location_settings_loading_app_permission_stats);
} else {
summary = mContext.getResources().getQuantityString(
R.plurals.location_settings_summary_location_on,
mNumTotal, mNumTotal);
}
} else {
summary = mContext.getString(R.string.location_settings_summary_location_off);
}
preference.setSummary(summary);
}
private Context createPackageContextAsUser(Context context, int userId) {
try {
return context.createPackageContextAsUser(
context.getPackageName(), 0 /* flags */, UserHandle.of(userId));
} catch (PackageManager.NameNotFoundException e) {
LOG.e("Failed to create user context", e);
}
return null;
}
}
对于此示例控制器:
- 如果停用了位置信息服务,摘要文本将设置为
location_settings_summary_location_off
字符串。
- 如果启用了位置信息服务,系统会添加具有位置信息权限的应用数量。在加载过程中,系统会显示
location_settings_loading_app_permission_stats
字符串。数据加载完毕后,控制器会将摘要设置为 location_settings_summary_location_on
字符串,并指明拥有访问权限的应用数量。
- 偏好设置控制器在启动后会注册接收器,并在位置信息服务状态更改时刷新偏好设置状态。
- 修改 fragment XML 文件,将新控制器附加到相关偏好设置:
<Preference
android:fragment="com.android.car.settings.location.LocationSettingsFragment"
android:icon="@drawable/ic_settings_location"
android:key="@string/pk_location_settings_entry"
android:title="@string/location_settings_title"
settings:controller="com.android.car.settings.location.LocationEntryPreferenceController"/>
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Preference subtitles\n\nFor the most part, adding preference summaries is relatively straightforward as it\ninvolves just adding the `android:summary` attribute to the respective preference\nwith the appropriate string resource. However, if the subtitles should update dynamically\nthen a custom preference controller may be necessary.\n\nStatic subtitles\n----------------\n\nTo add a static subtitle to a preference:\n\n1. Add the `android:summary` attribute to the preference. For example, to add a summary to the L0 display settings preference, add something like the following to the preference attributes: \n\n android:summary=\"@string/display_settings_summary\"\n\n For example, consider this full preference code sample: \n\n ```\n \u003cPreference\n android:fragment=\"com.android.car.settings.display.DisplaySettingsFragment\"\n android:icon=\"@drawable/ic_settings_display\"\n android:key=\"@string/pk_display_settings_entry\"\n android:title=\"@string/display_settings\"\n android:summary=\"@string/display_settings_summary\"\n settings:controller=\"com.android.car.settings.common.DefaultRestrictionsPreferenceController\"/\u003e\n ```\n\nDynamic subtitles\n-----------------\n\nSubtitles specified with the `android:summary` attribute are static so cannot\nupdate based on certain conditions. For dynamic subtitles, you need to modify the preference\ncontroller for the preference. The following example modifies the L0 location preference to\nhave a subtitle that specifies if location is on or off and, if on, state how many apps\ncurrently have location access.\n\n1. Define the new strings: \n\n ```\n \u003c!-- Summary for Location settings when location is off [CHAR LIMIT=NONE] --\u003e\n \u003cstring name=\"location_settings_summary_location_off\"\u003eOff\u003c/string\u003e\n \u003c!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]--\u003e\n \u003cplurals name=\"location_settings_summary_location_on\"\u003e\n \u003citem quantity=\"one\"\u003eOn - \u003cxliff:g id=\"count\"\u003e%1$d\u003c/xliff:g\u003e app has access to location\u003c/item\u003e\n \u003citem quantity=\"other\"\u003eOn - \u003cxliff:g id=\"count\"\u003e%1$d\u003c/xliff:g\u003e apps have access to location\u003c/item\u003e\n \u003c/plurals\u003e\n \u003c!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] --\u003e\n \u003cstring name=\"location_settings_loading_app_permission_stats\"\u003eLoading\\u2026\u003c/string\u003e\n ```\n2. Create a new PreferenceController, `LocationEntryPreferenceController`, to dynamically set and change the location preference summary text: \n\n ```\n public class LocationEntryPreferenceController extends PreferenceController\u003cPreference\u003e {\n\n private static final Logger LOG = new Logger(LocationEntryPreferenceController.class);\n private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =\n new IntentFilter(LocationManager.MODE_CHANGED_ACTION);\n\n private final Context mContext;\n private final LocationManager mLocationManager;\n /** Total number of apps that have location permissions. */\n private int mNumTotal = -1;\n private int mNumTotalLoading = 0;\n private AtomicInteger mLoadingInProgress = new AtomicInteger(0);\n\n private final BroadcastReceiver mReceiver = new BroadcastReceiver() {\n @Override\n public void onReceive(Context context, Intent intent) {\n refreshUi();\n }\n };\n\n public LocationEntryPreferenceController(Context context, String preferenceKey,\n FragmentController fragmentController, CarUxRestrictions uxRestrictions) {\n super(context, preferenceKey, fragmentController, uxRestrictions);\n mContext = context;\n mLocationManager = (LocationManager) getContext().getSystemService(\n Service.LOCATION_SERVICE);\n }\n\n @Override\n protected Class\u003cPreference\u003e getPreferenceType() {\n return Preference.class;\n }\n\n @Override\n protected void onStartInternal() {\n getContext().registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);\n }\n\n @Override\n protected void onStopInternal() {\n getContext().unregisterReceiver(mReceiver);\n }\n\n @Override\n protected void updateState(Preference preference) {\n super.updateState(preference);\n updateSummary(preference);\n if (!mLocationManager.isLocationEnabled() || mLoadingInProgress.get() != 0) {\n return;\n }\n mNumTotalLoading = 0;\n // Retrieve a list of users inside the current user profile group.\n List\u003cUserHandle\u003e users = mContext.getSystemService(\n UserManager.class).getUserProfiles();\n mLoadingInProgress.set(users.size());\n for (UserHandle user : users) {\n Context userContext = createPackageContextAsUser(mContext, user.getIdentifier());\n if (userContext == null) {\n if (mLoadingInProgress.decrementAndGet() == 0) {\n setLocationAppCount(preference, mNumTotalLoading);\n }\n continue;\n }\n PermissionControllerManager permController =\n userContext.getSystemService(PermissionControllerManager.class);\n permController.countPermissionApps(\n Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),\n PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED,\n (numApps) -\u003e {\n mNumTotalLoading += numApps;\n if (mLoadingInProgress.decrementAndGet() == 0) {\n setLocationAppCount(preference, mNumTotalLoading);\n }\n }, null);\n }\n }\n\n @VisibleForTesting\n void setLocationAppCount(Preference preference, int numApps) {\n mNumTotal = numApps;\n updateSummary(preference);\n }\n\n private void updateSummary(Preference preference) {\n String summary = \"\";\n if (mLocationManager.isLocationEnabled()) {\n if (mNumTotal == -1) {\n summary = mContext.getString(R.string.location_settings_loading_app_permission_stats);\n } else {\n summary = mContext.getResources().getQuantityString(\n R.plurals.location_settings_summary_location_on,\n mNumTotal, mNumTotal);\n }\n } else {\n summary = mContext.getString(R.string.location_settings_summary_location_off);\n }\n preference.setSummary(summary);\n }\n\n private Context createPackageContextAsUser(Context context, int userId) {\n try {\n return context.createPackageContextAsUser(\n context.getPackageName(), 0 /* flags */, UserHandle.of(userId));\n } catch (PackageManager.NameNotFoundException e) {\n LOG.e(\"Failed to create user context\", e);\n }\n return null;\n }\n }\n ```\n\n For this sample controller:\n - If location is disabled, summary text is set to the `location_settings_summary_location_off` string.\n - If location is enabled, the number of apps that have location permission is added. While this is loading, the `location_settings_loading_app_permission_stats` string is shown. When the data is loaded, the controller sets the summary to the `location_settings_summary_location_on` string with the number of apps with access specified.\n - When the preference controller is started, the controller registers a receiver and refreshes the preference state when the location state changes.\n3. Modify the fragment XML file to attach the new controller to the relevant preference: \n\n ```\n \u003cPreference\n android:fragment=\"com.android.car.settings.location.LocationSettingsFragment\"\n android:icon=\"@drawable/ic_settings_location\"\n android:key=\"@string/pk_location_settings_entry\"\n android:title=\"@string/location_settings_title\"\n settings:controller=\"com.android.car.settings.location.LocationEntryPreferenceController\"/\u003e\n ```"]]