• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.app.settings;
17 
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.SharedPreferences;
21 import android.net.Uri;
22 import android.os.Build.VERSION;
23 import android.os.Build.VERSION_CODES;
24 import android.os.Bundle;
25 import android.os.UserManager;
26 import android.preference.PreferenceManager;
27 import android.provider.Settings;
28 import android.support.annotation.Nullable;
29 import android.telecom.PhoneAccount;
30 import android.telecom.PhoneAccountHandle;
31 import android.telecom.TelecomManager;
32 import android.telephony.TelephonyManager;
33 import android.view.MenuItem;
34 import android.widget.Toast;
35 import com.android.dialer.about.AboutPhoneFragment;
36 import com.android.dialer.app.R;
37 import com.android.dialer.assisteddialing.ConcreteCreator;
38 import com.android.dialer.blocking.FilteredNumberCompat;
39 import com.android.dialer.common.LogUtil;
40 import com.android.dialer.compat.telephony.TelephonyManagerCompat;
41 import com.android.dialer.configprovider.ConfigProviderBindings;
42 import com.android.dialer.proguard.UsedByReflection;
43 import com.android.dialer.util.PermissionsUtil;
44 import com.android.dialer.voicemail.settings.VoicemailSettingsFragment;
45 import com.android.voicemail.VoicemailClient;
46 import java.util.List;
47 
48 /** Activity for dialer settings. */
49 @SuppressWarnings("FragmentInjection") // Activity not exported
50 @UsedByReflection(value = "AndroidManifest-app.xml")
51 public class DialerSettingsActivity extends AppCompatPreferenceActivity {
52 
53   protected SharedPreferences preferences;
54   private boolean migrationStatusOnBuildHeaders;
55   private List<Header> headers;
56 
57   @Override
onCreate(Bundle savedInstanceState)58   protected void onCreate(Bundle savedInstanceState) {
59     LogUtil.enterBlock("DialerSettingsActivity.onCreate");
60     super.onCreate(savedInstanceState);
61     preferences = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
62 
63     Intent intent = getIntent();
64     Uri data = intent.getData();
65     if (data != null) {
66       String headerToOpen = data.getSchemeSpecificPart();
67       if (headerToOpen != null && headers != null) {
68         for (Header header : headers) {
69           if (headerToOpen.equals(header.fragment)) {
70             LogUtil.i("DialerSettingsActivity.onCreate", "switching to header: " + headerToOpen);
71             switchToHeader(header);
72             break;
73           }
74         }
75       }
76     }
77   }
78 
79   @Override
onResume()80   protected void onResume() {
81     super.onResume();
82     /*
83      * The blockedCallsHeader need to be recreated if the migration status changed because
84      * the intent needs to be updated.
85      */
86     if (migrationStatusOnBuildHeaders != FilteredNumberCompat.hasMigratedToNewBlocking(this)) {
87       invalidateHeaders();
88     }
89   }
90 
91   @Override
onBuildHeaders(List<Header> target)92   public void onBuildHeaders(List<Header> target) {
93     // Keep a reference to the list of headers (since PreferenceActivity.getHeaders() is @Hide)
94     headers = target;
95 
96     if (showDisplayOptions()) {
97       Header displayOptionsHeader = new Header();
98       displayOptionsHeader.titleRes = R.string.display_options_title;
99       displayOptionsHeader.fragment = DisplayOptionsSettingsFragment.class.getName();
100       target.add(displayOptionsHeader);
101     }
102 
103     Header soundSettingsHeader = new Header();
104     soundSettingsHeader.titleRes = R.string.sounds_and_vibration_title;
105     soundSettingsHeader.id = R.id.settings_header_sounds_and_vibration;
106     target.add(soundSettingsHeader);
107 
108     Header quickResponseSettingsHeader = new Header();
109     Intent quickResponseSettingsIntent =
110         new Intent(TelecomManager.ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS);
111     quickResponseSettingsHeader.titleRes = R.string.respond_via_sms_setting_title;
112     quickResponseSettingsHeader.intent = quickResponseSettingsIntent;
113     target.add(quickResponseSettingsHeader);
114 
115     TelephonyManager telephonyManager =
116         (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
117 
118     // "Call Settings" (full settings) is shown if the current user is primary user and there
119     // is only one SIM. Before N, "Calling accounts" setting is shown if the current user is
120     // primary user and there are multiple SIMs. In N+, "Calling accounts" is shown whenever
121     // "Call Settings" is not shown.
122     boolean isPrimaryUser = isPrimaryUser();
123     if (isPrimaryUser && TelephonyManagerCompat.getPhoneCount(telephonyManager) <= 1) {
124       Header callSettingsHeader = new Header();
125       Intent callSettingsIntent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS);
126       callSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
127 
128       callSettingsHeader.titleRes = R.string.call_settings_label;
129       callSettingsHeader.intent = callSettingsIntent;
130       target.add(callSettingsHeader);
131     } else if ((VERSION.SDK_INT >= VERSION_CODES.N) || isPrimaryUser) {
132       Header phoneAccountSettingsHeader = new Header();
133       Intent phoneAccountSettingsIntent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS);
134       phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
135 
136       phoneAccountSettingsHeader.titleRes = R.string.phone_account_settings_label;
137       phoneAccountSettingsHeader.intent = phoneAccountSettingsIntent;
138       target.add(phoneAccountSettingsHeader);
139     }
140     if (FilteredNumberCompat.canCurrentUserOpenBlockSettings(this)) {
141       Header blockedCallsHeader = new Header();
142       blockedCallsHeader.titleRes = R.string.manage_blocked_numbers_label;
143       blockedCallsHeader.intent = FilteredNumberCompat.createManageBlockedNumbersIntent(this);
144       target.add(blockedCallsHeader);
145       migrationStatusOnBuildHeaders = FilteredNumberCompat.hasMigratedToNewBlocking(this);
146     }
147 
148     addVoicemailSettings(target, isPrimaryUser);
149 
150     if (isPrimaryUser
151         && (TelephonyManagerCompat.isTtyModeSupported(telephonyManager)
152             || TelephonyManagerCompat.isHearingAidCompatibilitySupported(telephonyManager))) {
153       Header accessibilitySettingsHeader = new Header();
154       Intent accessibilitySettingsIntent =
155           new Intent(TelecomManager.ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS);
156       accessibilitySettingsHeader.titleRes = R.string.accessibility_settings_title;
157       accessibilitySettingsHeader.intent = accessibilitySettingsIntent;
158       target.add(accessibilitySettingsHeader);
159     }
160 
161     boolean isAssistedDialingEnabled =
162         ConcreteCreator.isAssistedDialingEnabled(
163             ConfigProviderBindings.get(getApplicationContext()));
164     LogUtil.i(
165         "DialerSettingsActivity.onBuildHeaders",
166         "showing assisted dialing header: " + isAssistedDialingEnabled);
167     if (isAssistedDialingEnabled) {
168 
169       Header assistedDialingSettingsHeader = new Header();
170       assistedDialingSettingsHeader.titleRes =
171           com.android.dialer.assisteddialing.ui.R.string.assisted_dialing_setting_title;
172       assistedDialingSettingsHeader.intent =
173           new Intent("com.android.dialer.app.settings.SHOW_ASSISTED_DIALING_SETTINGS");
174       target.add(assistedDialingSettingsHeader);
175     }
176 
177     if (showAbout()) {
178       Header aboutPhoneHeader = new Header();
179       aboutPhoneHeader.titleRes = R.string.about_phone_label;
180       aboutPhoneHeader.fragment = AboutPhoneFragment.class.getName();
181       target.add(aboutPhoneHeader);
182     }
183   }
184 
addVoicemailSettings(List<Header> target, boolean isPrimaryUser)185   private void addVoicemailSettings(List<Header> target, boolean isPrimaryUser) {
186     if (!isPrimaryUser) {
187       LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "user not primary user");
188       return;
189     }
190     if (VERSION.SDK_INT < VERSION_CODES.O) {
191       LogUtil.i(
192           "DialerSettingsActivity.addVoicemailSettings",
193           "Dialer voicemail settings not supported by system");
194       return;
195     }
196 
197     if (!PermissionsUtil.hasReadPhoneStatePermissions(this)) {
198       LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "Missing READ_PHONE_STATE");
199       return;
200     }
201 
202     LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "adding voicemail settings");
203     Header voicemailSettings = new Header();
204     voicemailSettings.titleRes = R.string.voicemail_settings_label;
205     PhoneAccountHandle soleAccount = getSoleSimAccount();
206     if (soleAccount == null) {
207       LogUtil.i(
208           "DialerSettingsActivity.addVoicemailSettings", "showing multi-SIM voicemail settings");
209       voicemailSettings.fragment = PhoneAccountSelectionFragment.class.getName();
210       Bundle bundle = new Bundle();
211       bundle.putString(
212           PhoneAccountSelectionFragment.PARAM_TARGET_FRAGMENT,
213           VoicemailSettingsFragment.class.getName());
214       bundle.putString(
215           PhoneAccountSelectionFragment.PARAM_PHONE_ACCOUNT_HANDLE_KEY,
216           VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE);
217       bundle.putBundle(PhoneAccountSelectionFragment.PARAM_ARGUMENTS, new Bundle());
218       bundle.putInt(
219           PhoneAccountSelectionFragment.PARAM_TARGET_TITLE_RES, R.string.voicemail_settings_label);
220       voicemailSettings.fragmentArguments = bundle;
221       target.add(voicemailSettings);
222     } else {
223       LogUtil.i(
224           "DialerSettingsActivity.addVoicemailSettings", "showing single-SIM voicemail settings");
225       voicemailSettings.fragment = VoicemailSettingsFragment.class.getName();
226       Bundle bundle = new Bundle();
227       bundle.putParcelable(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE, soleAccount);
228       voicemailSettings.fragmentArguments = bundle;
229       target.add(voicemailSettings);
230     }
231   }
232 
233   /**
234    * @return the only SIM phone account, or {@code null} if there are none or more than one. Note:
235    *     having a empty SIM slot still count as a PhoneAccountHandle that is "invalid", and
236    *     voicemail settings should still be available for it.
237    */
238   @Nullable
getSoleSimAccount()239   private PhoneAccountHandle getSoleSimAccount() {
240     TelecomManager telecomManager = getSystemService(TelecomManager.class);
241     PhoneAccountHandle result = null;
242     for (PhoneAccountHandle phoneAccountHandle : telecomManager.getCallCapablePhoneAccounts()) {
243       PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
244       if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
245         LogUtil.i(
246             "DialerSettingsActivity.getSoleSimAccount", phoneAccountHandle + " is a SIM account");
247         if (result != null) {
248           return null;
249         }
250         result = phoneAccountHandle;
251       }
252     }
253     return result;
254   }
255 
256   /** Whether "about" should be shown in settings. Override to hide about. */
showAbout()257   public boolean showAbout() {
258     return true;
259   }
260 
261   /**
262    * Returns {@code true} or {@code false} based on whether the display options setting should be
263    * shown. For languages such as Chinese, Japanese, or Korean, display options aren't useful since
264    * contacts are sorted and displayed family name first by default.
265    *
266    * @return {@code true} if the display options should be shown, {@code false} otherwise.
267    */
showDisplayOptions()268   private boolean showDisplayOptions() {
269     return getResources().getBoolean(R.bool.config_display_order_user_changeable)
270         && getResources().getBoolean(R.bool.config_sort_order_user_changeable);
271   }
272 
273   /**
274    * For the "sounds and vibration" setting, we go directly to the system sound settings fragment.
275    * This helps since:
276    * <li>We don't need a separate Dialer sounds and vibrations fragment, as everything we need is
277    *     present in the system sounds fragment.
278    * <li>OEM's e.g Moto that support dual sim ring-tones no longer need to update the dialer sound
279    *     and settings fragment.
280    *
281    *     <p>For all other settings, we launch our our preferences fragment.
282    */
283   @Override
onHeaderClick(Header header, int position)284   public void onHeaderClick(Header header, int position) {
285     if (header.id == R.id.settings_header_sounds_and_vibration) {
286 
287       if (!Settings.System.canWrite(this)) {
288         Toast.makeText(
289                 this,
290                 getResources().getString(R.string.toast_cannot_write_system_settings),
291                 Toast.LENGTH_SHORT)
292             .show();
293       }
294 
295       startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS));
296       return;
297     }
298 
299     super.onHeaderClick(header, position);
300   }
301 
302   @Override
onOptionsItemSelected(MenuItem item)303   public boolean onOptionsItemSelected(MenuItem item) {
304     if (item.getItemId() == android.R.id.home) {
305       onBackPressed();
306       return true;
307     }
308     return false;
309   }
310 
311   @Override
onBackPressed()312   public void onBackPressed() {
313     if (!isSafeToCommitTransactions()) {
314       return;
315     }
316     super.onBackPressed();
317   }
318 
319   @Override
isValidFragment(String fragmentName)320   protected boolean isValidFragment(String fragmentName) {
321     return true;
322   }
323 
324   /** @return Whether the current user is the primary user. */
isPrimaryUser()325   private boolean isPrimaryUser() {
326     return getSystemService(UserManager.class).isSystemUser();
327   }
328 }
329