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