1 package com.android.phone.settings; 2 3 import android.content.ComponentName; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.content.pm.PackageManager; 7 import android.content.pm.ResolveInfo; 8 import android.graphics.drawable.Icon; 9 import android.net.sip.SipManager; 10 import android.os.Bundle; 11 import android.os.UserManager; 12 import android.preference.ListPreference; 13 import android.preference.Preference; 14 import android.preference.PreferenceCategory; 15 import android.preference.PreferenceFragment; 16 import android.preference.SwitchPreference; 17 import android.telecom.PhoneAccount; 18 import android.telecom.PhoneAccountHandle; 19 import android.telecom.TelecomManager; 20 import android.telephony.CarrierConfigManager; 21 import android.telephony.SubscriptionInfo; 22 import android.telephony.SubscriptionManager; 23 import android.telephony.TelephonyManager; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import com.android.internal.telephony.Phone; 28 import com.android.phone.PhoneUtils; 29 import com.android.phone.R; 30 import com.android.phone.SubscriptionInfoHelper; 31 import com.android.services.telephony.sip.SipAccountRegistry; 32 import com.android.services.telephony.sip.SipPreferences; 33 import com.android.services.telephony.sip.SipUtil; 34 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.Comparator; 38 import java.util.Iterator; 39 import java.util.List; 40 import java.util.stream.Collectors; 41 42 public class PhoneAccountSettingsFragment extends PreferenceFragment 43 implements Preference.OnPreferenceChangeListener, 44 AccountSelectionPreference.AccountSelectionListener { 45 46 private static final String ACCOUNTS_LIST_CATEGORY_KEY = 47 "phone_accounts_accounts_list_category_key"; 48 49 private static final String ALL_CALLING_ACCOUNTS_KEY = "phone_accounts_all_calling_accounts"; 50 51 private static final String SIP_SETTINGS_CATEGORY_PREF_KEY = 52 "phone_accounts_sip_settings_category_key"; 53 private static final String USE_SIP_PREF_KEY = "use_sip_calling_options_key"; 54 private static final String SIP_RECEIVE_CALLS_PREF_KEY = "sip_receive_calls_key"; 55 56 private static final String MAKE_AND_RECEIVE_CALLS_CATEGORY_KEY = 57 "make_and_receive_calls_settings_category_key"; 58 private static final String DEFAULT_OUTGOING_ACCOUNT_KEY = "default_outgoing_account"; 59 private static final String SMART_FORWARDING_CONFIGURATION_PREF_KEY = 60 "smart_forwarding_configuration_key"; 61 62 private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT = 63 "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; 64 65 /** 66 * Value to start ordering of phone accounts relative to other preferences. By setting this 67 * value on the phone account listings, we ensure that anything that is ordered before 68 * {value} in the preference XML comes before the phone account list and anything with 69 * a value significantly larger will list after. 70 */ 71 private static final int ACCOUNT_ORDERING_START_VALUE = 100; 72 73 private static final String LOG_TAG = PhoneAccountSettingsFragment.class.getSimpleName(); 74 75 private TelecomManager mTelecomManager; 76 private TelephonyManager mTelephonyManager; 77 private SubscriptionManager mSubscriptionManager; 78 79 private PreferenceCategory mAccountList; 80 81 private AccountSelectionPreference mDefaultOutgoingAccount; 82 private Preference mAllCallingAccounts; 83 84 private PreferenceCategory mMakeAndReceiveCallsCategory; 85 private boolean mMakeAndReceiveCallsCategoryPresent; 86 87 private ListPreference mUseSipCalling; 88 private SwitchPreference mSipReceiveCallsPreference; 89 private SipPreferences mSipPreferences; 90 91 private final SubscriptionManager.OnSubscriptionsChangedListener 92 mOnSubscriptionsChangeListener = 93 new SubscriptionManager.OnSubscriptionsChangedListener() { 94 @Override 95 public void onSubscriptionsChanged() { 96 updateAccounts(); 97 } 98 }; 99 100 @Override onCreate(Bundle icicle)101 public void onCreate(Bundle icicle) { 102 super.onCreate(icicle); 103 104 mTelecomManager = getActivity().getSystemService(TelecomManager.class); 105 mTelephonyManager = TelephonyManager.from(getActivity()); 106 mSubscriptionManager = SubscriptionManager.from(getActivity()); 107 } 108 109 @Override onResume()110 public void onResume() { 111 super.onResume(); 112 113 if (getPreferenceScreen() != null) { 114 getPreferenceScreen().removeAll(); 115 } 116 117 addPreferencesFromResource(R.xml.phone_account_settings); 118 119 /** 120 * Here we make decisions about what we will and will not display with regards to phone- 121 * account settings. The basic settings structure is this: 122 * (1) <Make Calls With...> // Lets user pick a default account for outgoing calls 123 * (2) <Account List> 124 * <Account> 125 * ... 126 * <Account> 127 * </Account List> 128 * (3) <All Accounts> // Lets user enable/disable third-party accounts. SIM-based accounts 129 * // are always enabled and so aren't relevant here. 130 * 131 * Here are the rules that we follow: 132 * - (1) is only shown if there are multiple enabled accounts, including SIM accounts. 133 * This can be 2+ SIM accounts, 2+ third party accounts or any combination. 134 * - (2) The account list only lists (a) enabled third party accounts and (b) SIM-based 135 * accounts. However, for single-SIM devices, if the only account to show is the 136 * SIM-based account, we don't show the list at all under the assumption that the user 137 * already knows about the account. 138 * - (3) Is only shown if there exist any third party accounts. If none exist, then the 139 * option is hidden since there is nothing that can be done in it. 140 * 141 * By far, the most common case for users will be the single-SIM device without any 142 * third party accounts. IOW, the great majority of users won't see any of these options. 143 */ 144 mAccountList = (PreferenceCategory) getPreferenceScreen().findPreference( 145 ACCOUNTS_LIST_CATEGORY_KEY); 146 mDefaultOutgoingAccount = (AccountSelectionPreference) 147 getPreferenceScreen().findPreference(DEFAULT_OUTGOING_ACCOUNT_KEY); 148 mAllCallingAccounts = getPreferenceScreen().findPreference(ALL_CALLING_ACCOUNTS_KEY); 149 150 mMakeAndReceiveCallsCategory = (PreferenceCategory) getPreferenceScreen().findPreference( 151 MAKE_AND_RECEIVE_CALLS_CATEGORY_KEY); 152 mMakeAndReceiveCallsCategoryPresent = false; 153 154 updateAccounts(); 155 updateMakeCallsOptions(); 156 157 if (isPrimaryUser() && SipUtil.isVoipSupported(getActivity())) { 158 mSipPreferences = new SipPreferences(getActivity()); 159 160 mUseSipCalling = (ListPreference) 161 getPreferenceScreen().findPreference(USE_SIP_PREF_KEY); 162 mUseSipCalling.setEntries(!SipManager.isSipWifiOnly(getActivity()) 163 ? R.array.sip_call_options_wifi_only_entries 164 : R.array.sip_call_options_entries); 165 mUseSipCalling.setOnPreferenceChangeListener(this); 166 167 int optionsValueIndex = 168 mUseSipCalling.findIndexOfValue(mSipPreferences.getSipCallOption()); 169 if (optionsValueIndex == -1) { 170 // If the option is invalid (eg. deprecated value), default to SIP_ADDRESS_ONLY. 171 mSipPreferences.setSipCallOption( 172 getResources().getString(R.string.sip_address_only)); 173 optionsValueIndex = 174 mUseSipCalling.findIndexOfValue(mSipPreferences.getSipCallOption()); 175 } 176 mUseSipCalling.setValueIndex(optionsValueIndex); 177 mUseSipCalling.setSummary(mUseSipCalling.getEntry()); 178 179 mSipReceiveCallsPreference = (SwitchPreference) 180 getPreferenceScreen().findPreference(SIP_RECEIVE_CALLS_PREF_KEY); 181 mSipReceiveCallsPreference.setEnabled(SipUtil.isPhoneIdle(getActivity())); 182 mSipReceiveCallsPreference.setChecked( 183 mSipPreferences.isReceivingCallsEnabled()); 184 mSipReceiveCallsPreference.setOnPreferenceChangeListener(this); 185 } else { 186 getPreferenceScreen().removePreference( 187 getPreferenceScreen().findPreference(SIP_SETTINGS_CATEGORY_PREF_KEY)); 188 } 189 190 SubscriptionManager.from(getActivity()).addOnSubscriptionsChangedListener( 191 mOnSubscriptionsChangeListener); 192 } 193 194 @Override onPause()195 public void onPause() { 196 SubscriptionManager.from(getActivity()).removeOnSubscriptionsChangedListener( 197 mOnSubscriptionsChangeListener); 198 super.onPause(); 199 } 200 201 /** 202 * Handles changes to the preferences. 203 * 204 * @param pref The preference changed. 205 * @param objValue The changed value. 206 * @return True if the preference change has been handled, and false otherwise. 207 */ 208 @Override onPreferenceChange(Preference pref, Object objValue)209 public boolean onPreferenceChange(Preference pref, Object objValue) { 210 if (pref == mUseSipCalling) { 211 String option = objValue.toString(); 212 mSipPreferences.setSipCallOption(option); 213 mUseSipCalling.setValueIndex(mUseSipCalling.findIndexOfValue(option)); 214 mUseSipCalling.setSummary(mUseSipCalling.getEntry()); 215 return true; 216 } else if (pref == mSipReceiveCallsPreference) { 217 final boolean isEnabled = !mSipReceiveCallsPreference.isChecked(); 218 new Thread(new Runnable() { 219 public void run() { 220 handleSipReceiveCallsOption(isEnabled); 221 } 222 }).start(); 223 return true; 224 } 225 return false; 226 } 227 228 /** 229 * Handles a phone account selection for the default outgoing phone account. 230 * 231 * @param pref The account selection preference which triggered the account selected event. 232 * @param account The account selected. 233 * @return True if the account selection has been handled, and false otherwise. 234 */ 235 @Override onAccountSelected(AccountSelectionPreference pref, PhoneAccountHandle account)236 public boolean onAccountSelected(AccountSelectionPreference pref, PhoneAccountHandle account) { 237 if (pref == mDefaultOutgoingAccount) { 238 mTelecomManager.setUserSelectedOutgoingPhoneAccount(account); 239 return true; 240 } 241 return false; 242 } 243 244 /** 245 * Repopulate the dialog to pick up changes before showing. 246 * 247 * @param pref The account selection preference dialog being shown. 248 */ 249 @Override onAccountSelectionDialogShow(AccountSelectionPreference pref)250 public void onAccountSelectionDialogShow(AccountSelectionPreference pref) { 251 if (pref == mDefaultOutgoingAccount) { 252 updateDefaultOutgoingAccountsModel(); 253 } 254 } 255 256 @Override onAccountChanged(AccountSelectionPreference pref)257 public void onAccountChanged(AccountSelectionPreference pref) {} 258 handleSipReceiveCallsOption(boolean isEnabled)259 private synchronized void handleSipReceiveCallsOption(boolean isEnabled) { 260 Context context = getActivity(); 261 if (context == null) { 262 // Return if the fragment is detached from parent activity before executed by thread. 263 return; 264 } 265 266 mSipPreferences.setReceivingCallsEnabled(isEnabled); 267 268 SipUtil.useSipToReceiveIncomingCalls(context, isEnabled); 269 270 // Restart all Sip services to ensure we reflect whether we are receiving calls. 271 SipAccountRegistry sipAccountRegistry = SipAccountRegistry.getInstance(); 272 sipAccountRegistry.restartSipService(context); 273 } 274 275 /** 276 * Queries the telcomm manager to update the default outgoing account selection preference 277 * with the list of outgoing accounts and the current default outgoing account. 278 */ updateDefaultOutgoingAccountsModel()279 private void updateDefaultOutgoingAccountsModel() { 280 mDefaultOutgoingAccount.setModel( 281 mTelecomManager, 282 getCallingAccounts(true /* includeSims */, false /* includeDisabled */), 283 mTelecomManager.getUserSelectedOutgoingPhoneAccount(), 284 getString(R.string.phone_accounts_ask_every_time)); 285 } 286 initAccountList(List<PhoneAccountHandle> enabledAccounts)287 private void initAccountList(List<PhoneAccountHandle> enabledAccounts) { 288 289 boolean isMultiSimDevice = mTelephonyManager.isMultiSimEnabled(); 290 291 // On a single-SIM device, do not list any accounts if the only account is the SIM-based 292 // one. This is because on single-SIM devices, we do not expose SIM settings through the 293 // account listing entry so showing it does nothing to help the user. Nor does the lack of 294 // action match the "Settings" header above the listing. 295 if (!isMultiSimDevice && getCallingAccounts( 296 false /* includeSims */, false /* includeDisabled */).isEmpty()){ 297 return; 298 } 299 300 // Obtain the list of phone accounts. 301 List<PhoneAccount> accounts = new ArrayList<>(); 302 for (PhoneAccountHandle handle : enabledAccounts) { 303 PhoneAccount account = mTelecomManager.getPhoneAccount(handle); 304 if (account != null) { 305 accounts.add(account); 306 } 307 } 308 309 // Sort the accounts according to how we want to display them. 310 Collections.sort(accounts, new Comparator<PhoneAccount>() { 311 @Override 312 public int compare(PhoneAccount account1, PhoneAccount account2) { 313 int retval = 0; 314 315 // SIM accounts go first 316 boolean isSim1 = account1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 317 boolean isSim2 = account2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 318 if (isSim1 != isSim2) { 319 retval = isSim1 ? -1 : 1; 320 } 321 322 int subId1 = mTelephonyManager.getSubIdForPhoneAccount(account1); 323 int subId2 = mTelephonyManager.getSubIdForPhoneAccount(account2); 324 if (subId1 != SubscriptionManager.INVALID_SUBSCRIPTION_ID && 325 subId2 != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 326 retval = (mSubscriptionManager.getSlotIndex(subId1) < 327 mSubscriptionManager.getSlotIndex(subId2)) ? -1 : 1; 328 } 329 330 // Then order by package 331 if (retval == 0) { 332 String pkg1 = account1.getAccountHandle().getComponentName().getPackageName(); 333 String pkg2 = account2.getAccountHandle().getComponentName().getPackageName(); 334 retval = pkg1.compareTo(pkg2); 335 } 336 337 // Finally, order by label 338 if (retval == 0) { 339 String label1 = nullToEmpty(account1.getLabel().toString()); 340 String label2 = nullToEmpty(account2.getLabel().toString()); 341 retval = label1.compareTo(label2); 342 } 343 344 // Then by hashcode 345 if (retval == 0) { 346 retval = account1.hashCode() - account2.hashCode(); 347 } 348 return retval; 349 } 350 }); 351 352 int order = ACCOUNT_ORDERING_START_VALUE; 353 354 // Add an entry for each account. 355 for (PhoneAccount account : accounts) { 356 PhoneAccountHandle handle = account.getAccountHandle(); 357 Intent intent = null; 358 359 // SIM phone accounts use a different setting intent and are thus handled differently. 360 if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 361 362 // For SIM-based accounts, we only expose the settings through the account list 363 // if we are on a multi-SIM device. For single-SIM devices, the settings are 364 // more spread out so there is no good single place to take the user, so we don't. 365 if (isMultiSimDevice) { 366 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo( 367 mTelephonyManager.getSubIdForPhoneAccount(account)); 368 369 if (subInfo != null) { 370 intent = new Intent(TelecomManager.ACTION_SHOW_CALL_SETTINGS); 371 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 372 SubscriptionInfoHelper.addExtrasToIntent(intent, subInfo); 373 } 374 } 375 } else { 376 intent = buildPhoneAccountConfigureIntent(getActivity(), handle); 377 } 378 379 // Create the preference & add the label 380 Preference accountPreference = new Preference(getActivity()); 381 CharSequence accountLabel = account.getLabel(); 382 boolean isSimAccount = 383 account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 384 accountPreference.setTitle((TextUtils.isEmpty(accountLabel) && isSimAccount) 385 ? getString(R.string.phone_accounts_default_account_label) : accountLabel); 386 387 // Add an icon. 388 Icon icon = account.getIcon(); 389 if (icon != null) { 390 accountPreference.setIcon(icon.loadDrawable(getActivity())); 391 } 392 393 // Add an intent to send the user to the account's settings. 394 if (intent != null) { 395 accountPreference.setIntent(intent); 396 } 397 398 accountPreference.setOrder(order++); 399 mAccountList.addPreference(accountPreference); 400 } 401 } 402 shouldShowConnectionServiceList(List<PhoneAccountHandle> allNonSimAccounts)403 private boolean shouldShowConnectionServiceList(List<PhoneAccountHandle> allNonSimAccounts) { 404 return mTelephonyManager.isMultiSimEnabled() || allNonSimAccounts.size() > 0; 405 } 406 updateAccounts()407 private void updateAccounts() { 408 if (mAccountList != null) { 409 mAccountList.removeAll(); 410 List<PhoneAccountHandle> allNonSimAccounts = 411 getCallingAccounts(false /* includeSims */, true /* includeDisabled */); 412 // Check to see if we should show the entire section at all. 413 if (shouldShowConnectionServiceList(allNonSimAccounts)) { 414 List<PhoneAccountHandle> enabledAccounts = 415 getCallingAccounts(true /* includeSims */, false /* includeDisabled */); 416 // Initialize the account list with the set of enabled & SIM accounts. 417 initAccountList(enabledAccounts); 418 419 // Only show the 'Make Calls With..." option if there are multiple accounts. 420 if (enabledAccounts.size() > 1) { 421 mMakeAndReceiveCallsCategory.addPreference(mDefaultOutgoingAccount); 422 mMakeAndReceiveCallsCategoryPresent = true; 423 mDefaultOutgoingAccount.setListener(this); 424 updateDefaultOutgoingAccountsModel(); 425 } else { 426 mMakeAndReceiveCallsCategory.removePreference(mDefaultOutgoingAccount); 427 } 428 429 // If there are no third party (nonSim) accounts, 430 // then don't show enable/disable dialog. 431 if (!allNonSimAccounts.isEmpty()) { 432 mAccountList.addPreference(mAllCallingAccounts); 433 } else { 434 mAccountList.removePreference(mAllCallingAccounts); 435 } 436 } else { 437 getPreferenceScreen().removePreference(mAccountList); 438 } 439 } 440 } 441 getCallingAccounts( boolean includeSims, boolean includeDisabledAccounts)442 private List<PhoneAccountHandle> getCallingAccounts( 443 boolean includeSims, boolean includeDisabledAccounts) { 444 PhoneAccountHandle emergencyAccountHandle = getEmergencyPhoneAccount(); 445 446 List<PhoneAccountHandle> accountHandles = 447 mTelecomManager.getCallCapablePhoneAccounts(includeDisabledAccounts); 448 for (Iterator<PhoneAccountHandle> i = accountHandles.iterator(); i.hasNext();) { 449 PhoneAccountHandle handle = i.next(); 450 if (handle.equals(emergencyAccountHandle)) { 451 // never include emergency call accounts in this piece of code. 452 i.remove(); 453 continue; 454 } 455 456 PhoneAccount account = mTelecomManager.getPhoneAccount(handle); 457 if (account == null) { 458 i.remove(); 459 } else if (!includeSims && 460 account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 461 i.remove(); 462 } 463 } 464 return accountHandles; 465 } 466 nullToEmpty(String str)467 private String nullToEmpty(String str) { 468 return str == null ? "" : str; 469 } 470 getEmergencyPhoneAccount()471 private PhoneAccountHandle getEmergencyPhoneAccount() { 472 return PhoneUtils.makePstnPhoneAccountHandleWithPrefix( 473 (Phone) null, "" /* prefix */, true /* isEmergency */); 474 } 475 buildPhoneAccountConfigureIntent( Context context, PhoneAccountHandle accountHandle)476 public static Intent buildPhoneAccountConfigureIntent( 477 Context context, PhoneAccountHandle accountHandle) { 478 Intent intent = buildConfigureIntent( 479 context, accountHandle, TelecomManager.ACTION_CONFIGURE_PHONE_ACCOUNT); 480 481 if (intent == null) { 482 // If the new configuration didn't work, try the old configuration intent. 483 intent = buildConfigureIntent( 484 context, accountHandle, LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT); 485 if (intent != null) { 486 Log.w(LOG_TAG, "Phone account using old configuration intent: " + accountHandle); 487 } 488 } 489 return intent; 490 } 491 buildConfigureIntent( Context context, PhoneAccountHandle accountHandle, String actionStr)492 private static Intent buildConfigureIntent( 493 Context context, PhoneAccountHandle accountHandle, String actionStr) { 494 if (accountHandle == null || accountHandle.getComponentName() == null || 495 TextUtils.isEmpty(accountHandle.getComponentName().getPackageName())) { 496 return null; 497 } 498 499 // Build the settings intent. 500 Intent intent = new Intent(actionStr); 501 intent.setPackage(accountHandle.getComponentName().getPackageName()); 502 intent.addCategory(Intent.CATEGORY_DEFAULT); 503 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle); 504 505 // Check to see that the phone account package can handle the setting intent. 506 PackageManager pm = context.getPackageManager(); 507 List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); 508 if (resolutions.size() == 0) { 509 intent = null; // set no intent if the package cannot handle it. 510 } 511 512 return intent; 513 } 514 515 /** 516 * @return Whether the current user is the primary user. 517 */ isPrimaryUser()518 private boolean isPrimaryUser() { 519 final UserManager userManager = (UserManager) getActivity() 520 .getSystemService(Context.USER_SERVICE); 521 return userManager.isPrimaryUser(); 522 } 523 updateMakeCallsOptions()524 private void updateMakeCallsOptions() { 525 if (mMakeAndReceiveCallsCategory == null) { 526 return; 527 } 528 529 Intent smartForwardingUiIntent = getLaunchSmartForwardingMenuIntent(); 530 if (smartForwardingUiIntent != null) { 531 mMakeAndReceiveCallsCategory.findPreference(SMART_FORWARDING_CONFIGURATION_PREF_KEY) 532 .setIntent(smartForwardingUiIntent); 533 mMakeAndReceiveCallsCategoryPresent = true; 534 } else { 535 mMakeAndReceiveCallsCategory.removePreference( 536 getPreferenceScreen().findPreference(SMART_FORWARDING_CONFIGURATION_PREF_KEY)); 537 } 538 539 if (!mMakeAndReceiveCallsCategoryPresent) { 540 getPreferenceScreen().removePreference(mMakeAndReceiveCallsCategory); 541 } 542 } 543 544 /** 545 * @return Smart forwarding configuration UI Intent when supported 546 */ getLaunchSmartForwardingMenuIntent()547 private Intent getLaunchSmartForwardingMenuIntent() { 548 if (mTelephonyManager.getPhoneCount() <= 1) { 549 return null; 550 } 551 552 final CarrierConfigManager configManager = (CarrierConfigManager) 553 getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE); 554 if (configManager == null) { 555 return null; 556 } 557 558 List<SubscriptionInfo> subscriptions = 559 mSubscriptionManager.getActiveSubscriptionInfoList(); 560 if (subscriptions == null) { 561 return null; 562 } 563 564 List<SubscriptionInfo> effectiveSubscriptions = subscriptions.stream() 565 .filter(subInfo -> !subInfo.isOpportunistic()) 566 .collect(Collectors.toList()); 567 if (effectiveSubscriptions.size() < 2) { 568 return null; 569 } 570 571 List<String> componentNames = effectiveSubscriptions.stream() 572 .map(subInfo -> configManager.getConfigForSubId(subInfo.getSubscriptionId())) 573 .filter(bundle -> (bundle != null)) 574 .map(bundle -> bundle.getString( 575 CarrierConfigManager.KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING)) 576 .filter(componentName -> !TextUtils.isEmpty(componentName)) 577 .collect(Collectors.toList()); 578 579 String componentNameOfMenu = null; 580 for (String componentName : componentNames) { 581 if (componentNameOfMenu == null) { 582 componentNameOfMenu = componentName; 583 } 584 else if (!componentNameOfMenu.equals(componentName)) { 585 Log.w(LOG_TAG, "ignore smart forward component: " + componentName); 586 } 587 } 588 589 if (TextUtils.isEmpty(componentNameOfMenu)) { 590 return null; 591 } 592 593 Intent intent = new Intent(Intent.ACTION_MAIN); 594 intent.setComponent(ComponentName.unflattenFromString(componentNameOfMenu)); 595 596 PackageManager pm = getActivity().getPackageManager(); 597 List<ResolveInfo> resolutions = pm.queryIntentActivities(intent, 0); 598 if (resolutions.size() == 0) { 599 intent = null; // set no intent if no package can handle it. 600 } 601 602 return intent; 603 } 604 } 605