Предпочтительные субтитры

По большей части добавление сводки предпочтений относительно просто, поскольку для этого нужно просто добавить атрибут 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. Измените фрагмент 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"/>