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