• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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