1 /* 2 * Copyright (C) 2017 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 package com.android.dialer.assisteddialing.ui; 17 18 import android.icu.util.ULocale; 19 import android.icu.util.ULocale.Builder; 20 import android.os.Bundle; 21 import android.preference.ListPreference; 22 import android.preference.Preference; 23 import android.preference.PreferenceFragment; 24 import android.preference.SwitchPreference; 25 import android.telephony.TelephonyManager; 26 import com.android.dialer.assisteddialing.AssistedDialingMediator; 27 import com.android.dialer.assisteddialing.ConcreteCreator; 28 import com.android.dialer.assisteddialing.CountryCodeProvider; 29 import com.android.dialer.common.LogUtil; 30 import com.android.dialer.configprovider.ConfigProviderComponent; 31 import com.android.dialer.logging.DialerImpression; 32 import com.android.dialer.logging.Logger; 33 import com.google.auto.value.AutoValue; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Optional; 37 38 /** The setting for Assisted Dialing */ 39 public class AssistedDialingSettingFragment extends PreferenceFragment { 40 41 private CountryCodeProvider countryCodeProvider; 42 private AssistedDialingMediator assistedDialingMediator; 43 44 @AutoValue 45 abstract static class DisplayNameAndCountryCodeTuple { 46 create( CharSequence countryDisplayName, CharSequence countryCode)47 static DisplayNameAndCountryCodeTuple create( 48 CharSequence countryDisplayName, CharSequence countryCode) { 49 return new AutoValue_AssistedDialingSettingFragment_DisplayNameAndCountryCodeTuple( 50 countryDisplayName, countryCode); 51 } 52 53 // The user-readable name of the country. countryDisplayname()54 abstract CharSequence countryDisplayname(); 55 56 // The ISO 3166-2 country code of the country. countryCode()57 abstract CharSequence countryCode(); 58 } 59 60 @Override onCreate(Bundle savedInstanceState)61 public void onCreate(Bundle savedInstanceState) { 62 super.onCreate(savedInstanceState); 63 64 assistedDialingMediator = 65 ConcreteCreator.createNewAssistedDialingMediator( 66 getContext().getSystemService(TelephonyManager.class), getContext()); 67 68 countryCodeProvider = 69 ConcreteCreator.getCountryCodeProvider( 70 ConfigProviderComponent.get(getContext()).getConfigProvider()); 71 72 // Load the preferences from an XML resource 73 addPreferencesFromResource(R.xml.assisted_dialing_setting); 74 SwitchPreference switchPref = 75 (SwitchPreference) 76 findPreference(getContext().getString(R.string.assisted_dialing_setting_toggle_key)); 77 78 ListPreference countryChooserPref = 79 (ListPreference) 80 findPreference(getContext().getString(R.string.assisted_dialing_setting_cc_key)); 81 82 updateCountryChoices(countryChooserPref); 83 updateCountryChooserSummary(countryChooserPref); 84 85 countryChooserPref.setOnPreferenceChangeListener(this::updateListSummary); 86 switchPref.setOnPreferenceChangeListener(this::logIfUserDisabledFeature); 87 } 88 updateCountryChooserSummary(ListPreference countryChooserPref)89 private void updateCountryChooserSummary(ListPreference countryChooserPref) { 90 String defaultSummaryText = countryChooserPref.getEntries()[0].toString(); 91 92 if (countryChooserPref.getEntry().equals(defaultSummaryText)) { 93 Optional<String> userHomeCountryCode = assistedDialingMediator.userHomeCountryCode(); 94 if (userHomeCountryCode.isPresent()) { 95 CharSequence[] entries = countryChooserPref.getEntries(); 96 try { 97 CharSequence regionalDisplayName = 98 entries[countryChooserPref.findIndexOfValue(userHomeCountryCode.get())]; 99 countryChooserPref.setSummary( 100 getContext() 101 .getString( 102 R.string.assisted_dialing_setting_cc_default_summary, regionalDisplayName)); 103 } catch (ArrayIndexOutOfBoundsException e) { 104 // This might happen if there is a mismatch between the automatically 105 // detected home country, and the countries currently eligible to select in the settings. 106 LogUtil.i( 107 "AssistedDialingSettingFragment.onCreate", 108 "Failed to find human readable mapping for country code, using default."); 109 } 110 } 111 } else { 112 countryChooserPref.setSummary(countryChooserPref.getEntry()); 113 } 114 } 115 116 /** 117 * Filters the default entries in the country chooser by only showing those countries in which the 118 * feature in enabled. 119 */ updateCountryChoices(ListPreference countryChooserPref)120 private void updateCountryChoices(ListPreference countryChooserPref) { 121 122 List<DisplayNameAndCountryCodeTuple> defaultCountryChoices = 123 buildDefaultCountryChooserKeysAndValues(countryChooserPref); 124 125 // Always include the default preference. 126 List<CharSequence> newKeys = new ArrayList<>(); 127 List<CharSequence> newValues = new ArrayList<>(); 128 newKeys.add(countryChooserPref.getEntries()[0]); 129 newValues.add(countryChooserPref.getEntryValues()[0]); 130 131 for (DisplayNameAndCountryCodeTuple tuple : defaultCountryChoices) { 132 if (countryCodeProvider.isSupportedCountryCode(tuple.countryCode().toString())) { 133 newKeys.add(tuple.countryDisplayname()); 134 newValues.add(tuple.countryCode()); 135 } 136 } 137 138 countryChooserPref.setEntries(newKeys.toArray(new CharSequence[newKeys.size()])); 139 countryChooserPref.setEntryValues(newValues.toArray(new CharSequence[newValues.size()])); 140 141 if (!newValues.contains(countryChooserPref.getValue())) { 142 ameliorateInvalidSelectedValue(countryChooserPref); 143 } 144 } 145 146 /** 147 * Restore an invalid user selected value to the default value. 148 * 149 * <p>In the Assisted Dialing settings in Dialer, this state is possible when a user selected a 150 * country code, and then that country code was removed from our filtered list, typically via a 151 * change in the available countries provided by a server side flag. 152 * 153 * @param countryChooserPref The list preference to restore to default when an invalid value is 154 * detected. 155 */ ameliorateInvalidSelectedValue(ListPreference countryChooserPref)156 private void ameliorateInvalidSelectedValue(ListPreference countryChooserPref) { 157 // Reset the preference value to the default value. 158 countryChooserPref.setValue(countryChooserPref.getEntryValues()[0].toString()); 159 LogUtil.i( 160 "AssistedDialingSettingFragment.ameliorateInvalidSelectedValue", 161 "Reset the country chooser preference to the default value."); 162 } 163 buildDefaultCountryChooserKeysAndValues( ListPreference countryChooserPref)164 private List<DisplayNameAndCountryCodeTuple> buildDefaultCountryChooserKeysAndValues( 165 ListPreference countryChooserPref) { 166 CharSequence[] keys = countryChooserPref.getEntries(); 167 CharSequence[] values = countryChooserPref.getEntryValues(); 168 169 if (keys.length != values.length) { 170 throw new IllegalStateException("Unexpected mismatch in country chooser key/value size"); 171 } 172 173 List<DisplayNameAndCountryCodeTuple> displayNamesandCountryCodes = new ArrayList<>(); 174 // getCountry() is actually getRegion() and conforms to the iso standards of input for the 175 // builder. 176 ULocale userLocale = 177 new ULocale.Builder() 178 .setRegion(getResources().getConfiguration().getLocales().get(0).getCountry()) 179 .setLanguage(getResources().getConfiguration().getLocales().get(0).getLanguage()) 180 .build(); 181 for (int i = 0; i < keys.length; i++) { 182 ULocale settingRowDisplayCountry = new Builder().setRegion(values[i].toString()).build(); 183 String localizedDisplayCountry = settingRowDisplayCountry.getDisplayCountry(userLocale); 184 String settingDisplayName = localizedDisplayCountry + " " + keys[i]; 185 displayNamesandCountryCodes.add( 186 DisplayNameAndCountryCodeTuple.create(settingDisplayName, values[i])); 187 } 188 189 return displayNamesandCountryCodes; 190 } 191 updateListSummary(Preference pref, Object newValue)192 boolean updateListSummary(Preference pref, Object newValue) { 193 ListPreference listPref = (ListPreference) pref; 194 CharSequence[] entries = listPref.getEntries(); 195 listPref.setSummary(entries[listPref.findIndexOfValue(newValue.toString())]); 196 return true; 197 } 198 logIfUserDisabledFeature(Preference pref, Object newValue)199 boolean logIfUserDisabledFeature(Preference pref, Object newValue) { 200 if (!((boolean) newValue)) { 201 Logger.get(getActivity().getApplicationContext()) 202 .logImpression(DialerImpression.Type.ASSISTED_DIALING_FEATURE_DISABLED_BY_USER); 203 } 204 205 return true; 206 } 207 } 208