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.ConfigProviderComponent; 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. Otherwise, "Calling accounts" is shown. 120 boolean isPrimaryUser = isPrimaryUser(); 121 if (isPrimaryUser && TelephonyManagerCompat.getPhoneCount(telephonyManager) <= 1) { 122 Header callSettingsHeader = new Header(); 123 Intent callSettingsIntent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS); 124 callSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 125 126 callSettingsHeader.titleRes = R.string.call_settings_label; 127 callSettingsHeader.intent = callSettingsIntent; 128 target.add(callSettingsHeader); 129 } else { 130 Header phoneAccountSettingsHeader = new Header(); 131 Intent phoneAccountSettingsIntent = new Intent(TelecomManager.ACTION_CHANGE_PHONE_ACCOUNTS); 132 phoneAccountSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 133 134 phoneAccountSettingsHeader.titleRes = R.string.phone_account_settings_label; 135 phoneAccountSettingsHeader.intent = phoneAccountSettingsIntent; 136 target.add(phoneAccountSettingsHeader); 137 } 138 if (FilteredNumberCompat.canCurrentUserOpenBlockSettings(this)) { 139 Header blockedCallsHeader = new Header(); 140 blockedCallsHeader.titleRes = R.string.manage_blocked_numbers_label; 141 blockedCallsHeader.intent = FilteredNumberCompat.createManageBlockedNumbersIntent(this); 142 target.add(blockedCallsHeader); 143 migrationStatusOnBuildHeaders = FilteredNumberCompat.hasMigratedToNewBlocking(this); 144 } 145 146 addVoicemailSettings(target, isPrimaryUser); 147 148 if (isPrimaryUser 149 && (TelephonyManagerCompat.isTtyModeSupported(telephonyManager) 150 || TelephonyManagerCompat.isHearingAidCompatibilitySupported(telephonyManager))) { 151 Header accessibilitySettingsHeader = new Header(); 152 Intent accessibilitySettingsIntent = 153 new Intent(TelecomManager.ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS); 154 accessibilitySettingsHeader.titleRes = R.string.accessibility_settings_title; 155 accessibilitySettingsHeader.intent = accessibilitySettingsIntent; 156 target.add(accessibilitySettingsHeader); 157 } 158 159 boolean isAssistedDialingEnabled = 160 ConcreteCreator.isAssistedDialingEnabled( 161 ConfigProviderComponent.get(getApplicationContext()).getConfigProvider()); 162 LogUtil.i( 163 "DialerSettingsActivity.onBuildHeaders", 164 "showing assisted dialing header: " + isAssistedDialingEnabled); 165 if (isAssistedDialingEnabled) { 166 167 Header assistedDialingSettingsHeader = new Header(); 168 assistedDialingSettingsHeader.titleRes = 169 com.android.dialer.assisteddialing.ui.R.string.assisted_dialing_setting_title; 170 assistedDialingSettingsHeader.intent = 171 new Intent("com.android.dialer.app.settings.SHOW_ASSISTED_DIALING_SETTINGS"); 172 target.add(assistedDialingSettingsHeader); 173 } 174 175 if (showAbout()) { 176 Header aboutPhoneHeader = new Header(); 177 aboutPhoneHeader.titleRes = R.string.about_phone_label; 178 aboutPhoneHeader.fragment = AboutPhoneFragment.class.getName(); 179 target.add(aboutPhoneHeader); 180 } 181 } 182 addVoicemailSettings(List<Header> target, boolean isPrimaryUser)183 private void addVoicemailSettings(List<Header> target, boolean isPrimaryUser) { 184 if (!isPrimaryUser) { 185 LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "user not primary user"); 186 return; 187 } 188 if (VERSION.SDK_INT < VERSION_CODES.O) { 189 LogUtil.i( 190 "DialerSettingsActivity.addVoicemailSettings", 191 "Dialer voicemail settings not supported by system"); 192 return; 193 } 194 195 if (!PermissionsUtil.hasReadPhoneStatePermissions(this)) { 196 LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "Missing READ_PHONE_STATE"); 197 return; 198 } 199 200 LogUtil.i("DialerSettingsActivity.addVoicemailSettings", "adding voicemail settings"); 201 Header voicemailSettings = new Header(); 202 voicemailSettings.titleRes = R.string.voicemail_settings_label; 203 PhoneAccountHandle soleAccount = getSoleSimAccount(); 204 if (soleAccount == null) { 205 LogUtil.i( 206 "DialerSettingsActivity.addVoicemailSettings", "showing multi-SIM voicemail settings"); 207 voicemailSettings.fragment = PhoneAccountSelectionFragment.class.getName(); 208 Bundle bundle = new Bundle(); 209 bundle.putString( 210 PhoneAccountSelectionFragment.PARAM_TARGET_FRAGMENT, 211 VoicemailSettingsFragment.class.getName()); 212 bundle.putString( 213 PhoneAccountSelectionFragment.PARAM_PHONE_ACCOUNT_HANDLE_KEY, 214 VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE); 215 bundle.putBundle(PhoneAccountSelectionFragment.PARAM_ARGUMENTS, new Bundle()); 216 bundle.putInt( 217 PhoneAccountSelectionFragment.PARAM_TARGET_TITLE_RES, R.string.voicemail_settings_label); 218 voicemailSettings.fragmentArguments = bundle; 219 target.add(voicemailSettings); 220 } else { 221 LogUtil.i( 222 "DialerSettingsActivity.addVoicemailSettings", "showing single-SIM voicemail settings"); 223 voicemailSettings.fragment = VoicemailSettingsFragment.class.getName(); 224 Bundle bundle = new Bundle(); 225 bundle.putParcelable(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE, soleAccount); 226 voicemailSettings.fragmentArguments = bundle; 227 target.add(voicemailSettings); 228 } 229 } 230 231 /** 232 * @return the only SIM phone account, or {@code null} if there are none or more than one. Note: 233 * having a empty SIM slot still count as a PhoneAccountHandle that is "invalid", and 234 * voicemail settings should still be available for it. 235 */ 236 @Nullable getSoleSimAccount()237 private PhoneAccountHandle getSoleSimAccount() { 238 TelecomManager telecomManager = getSystemService(TelecomManager.class); 239 PhoneAccountHandle result = null; 240 for (PhoneAccountHandle phoneAccountHandle : telecomManager.getCallCapablePhoneAccounts()) { 241 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle); 242 if (phoneAccount == null) { 243 continue; 244 } 245 if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 246 LogUtil.i( 247 "DialerSettingsActivity.getSoleSimAccount", phoneAccountHandle + " is a SIM account"); 248 if (result != null) { 249 return null; 250 } 251 result = phoneAccountHandle; 252 } 253 } 254 return result; 255 } 256 257 /** Whether "about" should be shown in settings. Override to hide about. */ showAbout()258 public boolean showAbout() { 259 return true; 260 } 261 262 /** 263 * Returns {@code true} or {@code false} based on whether the display options setting should be 264 * shown. For languages such as Chinese, Japanese, or Korean, display options aren't useful since 265 * contacts are sorted and displayed family name first by default. 266 * 267 * @return {@code true} if the display options should be shown, {@code false} otherwise. 268 */ showDisplayOptions()269 private boolean showDisplayOptions() { 270 return getResources().getBoolean(R.bool.config_display_order_user_changeable) 271 && getResources().getBoolean(R.bool.config_sort_order_user_changeable); 272 } 273 274 /** 275 * For the "sounds and vibration" setting, we go directly to the system sound settings fragment. 276 * This helps since: 277 * <li>We don't need a separate Dialer sounds and vibrations fragment, as everything we need is 278 * present in the system sounds fragment. 279 * <li>OEM's e.g Moto that support dual sim ring-tones no longer need to update the dialer sound 280 * and settings fragment. 281 * 282 * <p>For all other settings, we launch our our preferences fragment. 283 */ 284 @Override onHeaderClick(Header header, int position)285 public void onHeaderClick(Header header, int position) { 286 if (header.id == R.id.settings_header_sounds_and_vibration) { 287 288 if (!Settings.System.canWrite(this)) { 289 Toast.makeText( 290 this, 291 getResources().getString(R.string.toast_cannot_write_system_settings), 292 Toast.LENGTH_SHORT) 293 .show(); 294 } 295 296 startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS)); 297 return; 298 } 299 300 super.onHeaderClick(header, position); 301 } 302 303 @Override onOptionsItemSelected(MenuItem item)304 public boolean onOptionsItemSelected(MenuItem item) { 305 if (item.getItemId() == android.R.id.home) { 306 onBackPressed(); 307 return true; 308 } 309 return false; 310 } 311 312 @Override onBackPressed()313 public void onBackPressed() { 314 if (!isSafeToCommitTransactions()) { 315 return; 316 } 317 super.onBackPressed(); 318 } 319 320 @Override isValidFragment(String fragmentName)321 protected boolean isValidFragment(String fragmentName) { 322 return true; 323 } 324 325 /** @return Whether the current user is the primary user. */ isPrimaryUser()326 private boolean isPrimaryUser() { 327 return getSystemService(UserManager.class).isSystemUser(); 328 } 329 } 330