偏好设置字幕

在大多数情况下,添加偏好设置摘要相对比较简单,因为这只涉及使用适当的字符串资源将 android:summary 属性添加到相应的偏好设置中。不过,如果字幕应动态更新,那么可能有必要使用自定义偏好设置控制器。

静态字幕

如需向偏好设置添加静态字幕,请执行以下操作:

  1. 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 位置信息偏好设置,使其具有如下的字幕:指定位置信息服务是处于开启还是关闭状态;如果处于开启状态,还会指明当前有权使用位置信息的应用数量。

  1. 定义新字符串:
    <!-- 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>
    
  2. 创建一个新的 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 字符串,并指明拥有访问权限的应用数量。
    • 偏好设置控制器在启动后会注册接收器,并在位置信息服务状态更改时刷新偏好设置状态。
  3. 修改 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"/>