1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.car.settings.common; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Bundle; 23 24 import androidx.annotation.VisibleForTesting; 25 import androidx.preference.Preference; 26 import androidx.preference.PreferenceGroup; 27 28 import java.util.Map; 29 30 /** 31 * Injects preferences from other system applications at a placeholder location. The placeholder 32 * should be a {@link PreferenceGroup} which sets the controller attribute to the fully qualified 33 * name of this class. The preference should contain an intent which will be passed to 34 * {@link ExtraSettingsLoader#loadPreferences(Intent)}. 35 * 36 * <p>For example: 37 * <pre>{@code 38 * <PreferenceCategory 39 * android:key="@string/pk_system_extra_settings" 40 * android:title="@string/system_extra_settings_title" 41 * settings:controller="com.android.settings.common.ExtraSettingsPreferenceController"> 42 * <intent android:action="com.android.settings.action.EXTRA_SETTINGS"> 43 * <extra android:name="com.android.settings.category" 44 * android:value="com.android.settings.category.system"/> 45 * </intent> 46 * </PreferenceCategory> 47 * }</pre> 48 * 49 * @see ExtraSettingsLoader 50 */ 51 // TODO: investigate using SettingsLib Tiles. 52 public class ExtraSettingsPreferenceController extends PreferenceController<PreferenceGroup> { 53 54 @VisibleForTesting 55 static final String META_DATA_DISTRACTION_OPTIMIZED = "distractionOptimized"; 56 57 private ExtraSettingsLoader mExtraSettingsLoader; 58 private boolean mSettingsLoaded; 59 ExtraSettingsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions restrictionInfo)60 public ExtraSettingsPreferenceController(Context context, String preferenceKey, 61 FragmentController fragmentController, CarUxRestrictions restrictionInfo) { 62 super(context, preferenceKey, fragmentController, restrictionInfo); 63 mExtraSettingsLoader = new ExtraSettingsLoader(context); 64 } 65 66 @VisibleForTesting(otherwise = VisibleForTesting.NONE) setExtraSettingsLoader(ExtraSettingsLoader extraSettingsLoader)67 public void setExtraSettingsLoader(ExtraSettingsLoader extraSettingsLoader) { 68 mExtraSettingsLoader = extraSettingsLoader; 69 } 70 71 @Override getPreferenceType()72 protected Class<PreferenceGroup> getPreferenceType() { 73 return PreferenceGroup.class; 74 } 75 76 @Override onApplyUxRestrictions(CarUxRestrictions uxRestrictions)77 protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) { 78 super.onApplyUxRestrictions(uxRestrictions); 79 80 // If preference intents into an activity that's not distraction optimized, disable the 81 // preference. This will override the UXRE flags config_ignore_ux_restrictions and 82 // config_always_ignore_ux_restrictions because navigating to these non distraction 83 // optimized activities will cause the blocking activity to come up, which dead ends the 84 // user. 85 for (int i = 0; i < getPreference().getPreferenceCount(); i++) { 86 Preference preference = getPreference().getPreference(i); 87 if (uxRestrictions.isRequiresDistractionOptimization() 88 && !preference.getExtras().getBoolean(META_DATA_DISTRACTION_OPTIMIZED)) { 89 preference.setEnabled(false); 90 } else { 91 preference.setEnabled(getAvailabilityStatus() != AVAILABLE_FOR_VIEWING); 92 } 93 } 94 } 95 96 @Override updateState(PreferenceGroup preference)97 protected void updateState(PreferenceGroup preference) { 98 Map<Preference, Bundle> preferenceBundleMap = mExtraSettingsLoader.loadPreferences( 99 preference.getIntent()); 100 if (!mSettingsLoaded) { 101 addExtraSettings(preferenceBundleMap); 102 mSettingsLoaded = true; 103 } 104 preference.setVisible(preference.getPreferenceCount() > 0); 105 } 106 107 /** 108 * Adds the extra settings from the system based on the intent that is passed in the preference 109 * group. All the preferences that resolve these intents will be added in the preference group. 110 * 111 * @param preferenceBundleMap a map of {@link Preference} and {@link Bundle} representing 112 * settings injected from system apps and their metadata. 113 */ addExtraSettings(Map<Preference, Bundle> preferenceBundleMap)114 protected void addExtraSettings(Map<Preference, Bundle> preferenceBundleMap) { 115 for (Preference setting : preferenceBundleMap.keySet()) { 116 Bundle metaData = preferenceBundleMap.get(setting); 117 boolean distractionOptimized = false; 118 if (metaData.containsKey(META_DATA_DISTRACTION_OPTIMIZED)) { 119 distractionOptimized = 120 metaData.getBoolean(META_DATA_DISTRACTION_OPTIMIZED); 121 } 122 setting.getExtras().putBoolean(META_DATA_DISTRACTION_OPTIMIZED, distractionOptimized); 123 getPreference().addPreference(setting); 124 } 125 } 126 } 127