1 /* 2 * Copyright (C) 2020 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 17 package com.android.settings.network.telephony; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.os.Bundle; 22 import android.os.UserManager; 23 import android.telephony.SubscriptionInfo; 24 import android.telephony.SubscriptionManager; 25 import android.telephony.TelephonyManager; 26 import android.telephony.UiccCardInfo; 27 import android.text.TextUtils; 28 import android.util.Log; 29 import android.view.View; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.settings.R; 33 import com.android.settings.SidecarFragment; 34 import com.android.settings.network.EnableMultiSimSidecar; 35 import com.android.settings.network.SubscriptionUtil; 36 import com.android.settings.network.SwitchToEuiccSubscriptionSidecar; 37 import com.android.settings.network.SwitchToRemovableSlotSidecar; 38 import com.android.settings.network.UiccSlotUtil; 39 import com.android.settings.sim.SimActivationNotifier; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 import java.util.stream.Collectors; 44 45 /** This dialog activity handles both eSIM and pSIM subscriptions enabling and disabling. */ 46 public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogActivity 47 implements SidecarFragment.Listener, ConfirmDialogFragment.OnConfirmListener { 48 49 private static final String TAG = "ToggleSubscriptionDialogActivity"; 50 // Arguments 51 @VisibleForTesting 52 public static final String ARG_enable = "enable"; 53 // Dialog tags 54 private static final int DIALOG_TAG_DISABLE_SIM_CONFIRMATION = 1; 55 private static final int DIALOG_TAG_ENABLE_SIM_CONFIRMATION = 2; 56 private static final int DIALOG_TAG_ENABLE_DSDS_CONFIRMATION = 3; 57 private static final int DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION = 4; 58 private static final int DIALOG_TAG_ENABLE_SIM_CONFIRMATION_MEP = 5; 59 60 // Number of SIMs for DSDS 61 private static final int NUM_OF_SIMS_FOR_DSDS = 2; 62 // Support RTL mode 63 private static final String LINE_BREAK = "\n"; 64 private static final int LINE_BREAK_OFFSET_ONE = 1; 65 private static final int LINE_BREAK_OFFSET_TWO = 2; 66 private static final String RTL_MARK = "\u200F"; 67 68 /** 69 * Returns an intent of ToggleSubscriptionDialogActivity. 70 * 71 * @param context The context used to start the ToggleSubscriptionDialogActivity. 72 * @param subId The subscription ID of the subscription needs to be toggled. 73 * @param enable Whether the activity should enable or disable the subscription. 74 */ getIntent(Context context, int subId, boolean enable)75 public static Intent getIntent(Context context, int subId, boolean enable) { 76 Intent intent = new Intent(context, ToggleSubscriptionDialogActivity.class); 77 intent.putExtra(ARG_SUB_ID, subId); 78 intent.putExtra(ARG_enable, enable); 79 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 80 return intent; 81 } 82 83 private SubscriptionInfo mSubInfo; 84 private SwitchToEuiccSubscriptionSidecar mSwitchToEuiccSubscriptionSidecar; 85 private SwitchToRemovableSlotSidecar mSwitchToRemovableSlotSidecar; 86 private EnableMultiSimSidecar mEnableMultiSimSidecar; 87 private boolean mEnable; 88 private boolean mIsEsimOperation; 89 private TelephonyManager mTelMgr; 90 private boolean isRtlMode; 91 private List<SubscriptionInfo> mActiveSubInfos; 92 93 @Override onCreate(Bundle savedInstanceState)94 protected void onCreate(Bundle savedInstanceState) { 95 super.onCreate(savedInstanceState); 96 Intent intent = getIntent(); 97 int subId = intent.getIntExtra(ARG_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 98 mTelMgr = getSystemService(TelephonyManager.class); 99 100 UserManager userManager = getSystemService(UserManager.class); 101 if (!userManager.isAdminUser()) { 102 Log.e(TAG, "It is not the admin user. Unable to toggle subscription."); 103 finish(); 104 return; 105 } 106 107 if (!SubscriptionManager.isUsableSubscriptionId(subId)) { 108 Log.e(TAG, "The subscription id is not usable."); 109 finish(); 110 return; 111 } 112 113 mActiveSubInfos = SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager); 114 mSubInfo = SubscriptionUtil.getSubById(mSubscriptionManager, subId); 115 mIsEsimOperation = mSubInfo != null && mSubInfo.isEmbedded(); 116 mSwitchToEuiccSubscriptionSidecar = 117 SwitchToEuiccSubscriptionSidecar.get(getFragmentManager()); 118 mSwitchToRemovableSlotSidecar = SwitchToRemovableSlotSidecar.get(getFragmentManager()); 119 mEnableMultiSimSidecar = EnableMultiSimSidecar.get(getFragmentManager()); 120 mEnable = intent.getBooleanExtra(ARG_enable, true); 121 isRtlMode = getResources().getConfiguration().getLayoutDirection() 122 == View.LAYOUT_DIRECTION_RTL; 123 Log.i(TAG, "isMultipleEnabledProfilesSupported():" + isMultipleEnabledProfilesSupported()); 124 125 if (savedInstanceState == null) { 126 if (mEnable) { 127 showEnableSubDialog(); 128 } else { 129 showDisableSimConfirmDialog(); 130 } 131 } 132 } 133 134 @Override onResume()135 protected void onResume() { 136 super.onResume(); 137 mSwitchToEuiccSubscriptionSidecar.addListener(this); 138 mSwitchToRemovableSlotSidecar.addListener(this); 139 mEnableMultiSimSidecar.addListener(this); 140 } 141 142 @Override onPause()143 protected void onPause() { 144 mEnableMultiSimSidecar.removeListener(this); 145 mSwitchToRemovableSlotSidecar.removeListener(this); 146 mSwitchToEuiccSubscriptionSidecar.removeListener(this); 147 super.onPause(); 148 } 149 150 @Override onStateChange(SidecarFragment fragment)151 public void onStateChange(SidecarFragment fragment) { 152 if (fragment == mSwitchToEuiccSubscriptionSidecar) { 153 handleSwitchToEuiccSubscriptionSidecarStateChange(); 154 } else if (fragment == mSwitchToRemovableSlotSidecar) { 155 handleSwitchToRemovableSlotSidecarStateChange(); 156 } else if (fragment == mEnableMultiSimSidecar) { 157 handleEnableMultiSimSidecarStateChange(); 158 } 159 } 160 161 @Override onConfirm(int tag, boolean confirmed, int itemPosition)162 public void onConfirm(int tag, boolean confirmed, int itemPosition) { 163 if (!confirmed 164 && tag != DIALOG_TAG_ENABLE_DSDS_CONFIRMATION 165 && tag != DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION) { 166 finish(); 167 return; 168 } 169 170 SubscriptionInfo removedSubInfo = null; 171 switch (tag) { 172 case DIALOG_TAG_DISABLE_SIM_CONFIRMATION: 173 if (mIsEsimOperation) { 174 Log.i(TAG, "Disabling the eSIM profile."); 175 showProgressDialog( 176 getString(R.string.privileged_action_disable_sub_dialog_progress)); 177 int port = mSubInfo != null ? mSubInfo.getPortIndex() : 0; 178 mSwitchToEuiccSubscriptionSidecar.run( 179 SubscriptionManager.INVALID_SUBSCRIPTION_ID, port, null); 180 return; 181 } 182 Log.i(TAG, "Disabling the pSIM profile."); 183 handleTogglePsimAction(); 184 break; 185 case DIALOG_TAG_ENABLE_DSDS_CONFIRMATION: 186 if (!confirmed) { 187 Log.i(TAG, "User cancel the dialog to enable DSDS."); 188 showEnableSimConfirmDialog(); 189 return; 190 } 191 if (mTelMgr.doesSwitchMultiSimConfigTriggerReboot()) { 192 Log.i(TAG, "Device does not support reboot free DSDS."); 193 showRebootConfirmDialog(); 194 return; 195 } 196 Log.i(TAG, "Enabling DSDS without rebooting."); 197 showProgressDialog( 198 getString(R.string.sim_action_enabling_sim_without_carrier_name)); 199 mEnableMultiSimSidecar.run(NUM_OF_SIMS_FOR_DSDS); 200 break; 201 case DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION: 202 if (!confirmed) { 203 Log.i(TAG, "User cancel the dialog to reboot to enable DSDS."); 204 showEnableSimConfirmDialog(); 205 return; 206 } 207 Log.i(TAG, "User confirmed reboot to enable DSDS."); 208 SimActivationNotifier.setShowSimSettingsNotification(this, true); 209 mTelMgr.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS); 210 break; 211 case DIALOG_TAG_ENABLE_SIM_CONFIRMATION_MEP: 212 if (itemPosition != -1) { 213 removedSubInfo = (mActiveSubInfos != null) ? mActiveSubInfos.get(itemPosition) 214 : null; 215 } 216 case DIALOG_TAG_ENABLE_SIM_CONFIRMATION: 217 Log.i(TAG, "User confirmed to enable the subscription."); 218 showProgressDialog( 219 getString( 220 R.string.sim_action_switch_sub_dialog_progress, 221 SubscriptionUtil.getUniqueSubscriptionDisplayName(mSubInfo, this)), 222 removedSubInfo != null ? true : false); 223 if (mIsEsimOperation) { 224 mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId(), 225 UiccSlotUtil.INVALID_PORT_ID, 226 removedSubInfo); 227 return; 228 } 229 mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID, 230 removedSubInfo); 231 break; 232 default: 233 Log.e(TAG, "Unrecognized confirmation dialog tag: " + tag); 234 break; 235 } 236 } 237 handleSwitchToEuiccSubscriptionSidecarStateChange()238 private void handleSwitchToEuiccSubscriptionSidecarStateChange() { 239 switch (mSwitchToEuiccSubscriptionSidecar.getState()) { 240 case SidecarFragment.State.SUCCESS: 241 Log.i(TAG, 242 String.format( 243 "Successfully %s the eSIM profile.", 244 mEnable ? "enable" : "disable")); 245 mSwitchToEuiccSubscriptionSidecar.reset(); 246 dismissProgressDialog(); 247 finish(); 248 break; 249 case SidecarFragment.State.ERROR: 250 Log.i(TAG, 251 String.format( 252 "Failed to %s the eSIM profile.", mEnable ? "enable" : "disable")); 253 mSwitchToEuiccSubscriptionSidecar.reset(); 254 dismissProgressDialog(); 255 showErrorDialog( 256 getString(R.string.privileged_action_disable_fail_title), 257 getString(R.string.privileged_action_disable_fail_text)); 258 break; 259 } 260 } 261 handleSwitchToRemovableSlotSidecarStateChange()262 private void handleSwitchToRemovableSlotSidecarStateChange() { 263 switch (mSwitchToRemovableSlotSidecar.getState()) { 264 case SidecarFragment.State.SUCCESS: 265 Log.i(TAG, "Successfully switched to removable slot."); 266 mSwitchToRemovableSlotSidecar.reset(); 267 handleTogglePsimAction(); 268 dismissProgressDialog(); 269 finish(); 270 break; 271 case SidecarFragment.State.ERROR: 272 Log.e(TAG, "Failed switching to removable slot."); 273 mSwitchToRemovableSlotSidecar.reset(); 274 dismissProgressDialog(); 275 showErrorDialog( 276 getString(R.string.sim_action_enable_sim_fail_title), 277 getString(R.string.sim_action_enable_sim_fail_text)); 278 break; 279 } 280 } 281 handleEnableMultiSimSidecarStateChange()282 private void handleEnableMultiSimSidecarStateChange() { 283 switch (mEnableMultiSimSidecar.getState()) { 284 case SidecarFragment.State.SUCCESS: 285 mEnableMultiSimSidecar.reset(); 286 Log.i(TAG, "Successfully switched to DSDS without reboot."); 287 handleEnableSubscriptionAfterEnablingDsds(); 288 break; 289 case SidecarFragment.State.ERROR: 290 mEnableMultiSimSidecar.reset(); 291 Log.i(TAG, "Failed to switch to DSDS without rebooting."); 292 dismissProgressDialog(); 293 showErrorDialog( 294 getString(R.string.dsds_activation_failure_title), 295 getString(R.string.dsds_activation_failure_body_msg2)); 296 break; 297 } 298 } 299 handleEnableSubscriptionAfterEnablingDsds()300 private void handleEnableSubscriptionAfterEnablingDsds() { 301 if (mIsEsimOperation) { 302 Log.i(TAG, "DSDS enabled, start to enable profile: " + mSubInfo.getSubscriptionId()); 303 // For eSIM operations, we simply switch to the selected eSIM profile. 304 mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId(), 305 UiccSlotUtil.INVALID_PORT_ID, null); 306 return; 307 } 308 309 Log.i(TAG, "DSDS enabled, start to enable pSIM profile."); 310 handleTogglePsimAction(); 311 dismissProgressDialog(); 312 finish(); 313 } 314 handleTogglePsimAction()315 private void handleTogglePsimAction() { 316 if (mSubscriptionManager.canDisablePhysicalSubscription() && mSubInfo != null) { 317 mSubscriptionManager.setUiccApplicationsEnabled(mSubInfo.getSubscriptionId(), mEnable); 318 finish(); 319 } else { 320 Log.i(TAG, "The device does not support toggling pSIM. It is enough to just " 321 + "enable the removable slot."); 322 } 323 } 324 325 /* Handles the enabling SIM action. */ showEnableSubDialog()326 private void showEnableSubDialog() { 327 Log.d(TAG, "Handle subscription enabling."); 328 if (isDsdsConditionSatisfied()) { 329 showEnableDsdsConfirmDialog(); 330 return; 331 } 332 if (!mIsEsimOperation && mTelMgr.isMultiSimEnabled() 333 && isRemovableSimEnabled()) { 334 // This case is for switching on psim when device is not multiple enable profile 335 // supported. 336 Log.i(TAG, "Toggle on pSIM, no dialog displayed."); 337 handleTogglePsimAction(); 338 finish(); 339 return; 340 } 341 showEnableSimConfirmDialog(); 342 } 343 showEnableDsdsConfirmDialog()344 private void showEnableDsdsConfirmDialog() { 345 ConfirmDialogFragment.show( 346 this, 347 ConfirmDialogFragment.OnConfirmListener.class, 348 DIALOG_TAG_ENABLE_DSDS_CONFIRMATION, 349 getString(R.string.sim_action_enable_dsds_title), 350 getString(R.string.sim_action_enable_dsds_text), 351 getString(R.string.sim_action_yes), 352 getString(R.string.sim_action_no_thanks)); 353 } 354 showRebootConfirmDialog()355 private void showRebootConfirmDialog() { 356 ConfirmDialogFragment.show( 357 this, 358 ConfirmDialogFragment.OnConfirmListener.class, 359 DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION, 360 getString(R.string.sim_action_restart_title), 361 getString(R.string.sim_action_enable_dsds_text), 362 getString(R.string.sim_action_reboot), 363 getString(R.string.sim_action_cancel)); 364 } 365 366 /* Displays the SIM toggling confirmation dialog. */ showDisableSimConfirmDialog()367 private void showDisableSimConfirmDialog() { 368 final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 369 mSubInfo, this); 370 String title = 371 mSubInfo == null || TextUtils.isEmpty(displayName) 372 ? getString( 373 R.string.privileged_action_disable_sub_dialog_title_without_carrier) 374 : getString( 375 R.string.privileged_action_disable_sub_dialog_title, displayName); 376 377 ConfirmDialogFragment.show( 378 this, 379 ConfirmDialogFragment.OnConfirmListener.class, 380 DIALOG_TAG_DISABLE_SIM_CONFIRMATION, 381 title, 382 null, 383 getString(R.string.sim_action_turn_off), 384 getString(R.string.sim_action_cancel)); 385 } 386 showEnableSimConfirmDialog()387 private void showEnableSimConfirmDialog() { 388 if (mActiveSubInfos == null || mActiveSubInfos.isEmpty()) { 389 Log.i(TAG, "No active subscriptions available."); 390 showNonSwitchSimConfirmDialog(); 391 return; 392 } 393 Log.i(TAG, "mActiveSubInfos:" + mActiveSubInfos); 394 395 boolean isSwitchingBetweenEsims = mIsEsimOperation 396 && mActiveSubInfos.stream().anyMatch(activeSubInfo -> activeSubInfo.isEmbedded()); 397 boolean isMultiSimEnabled = mTelMgr.isMultiSimEnabled(); 398 if (isMultiSimEnabled 399 && !isMultipleEnabledProfilesSupported() 400 && !isSwitchingBetweenEsims) { 401 // Showing the "no switch dialog" for below cases. 402 // DSDS mode + no MEP + 403 // (there is the active psim -> esim switch on => active (psim + esim)) 404 showNonSwitchSimConfirmDialog(); 405 return; 406 } 407 408 if (isMultiSimEnabled && isMultipleEnabledProfilesSupported()) { 409 if (mActiveSubInfos.size() < NUM_OF_SIMS_FOR_DSDS) { 410 // The sim can add into device directly, so showing the "no switch dialog". 411 // DSDS + MEP + (active sim < NUM_OF_SIMS_FOR_DSDS) 412 showNonSwitchSimConfirmDialog(); 413 } else { 414 // The all of slots have sim, it needs to show the "MEP switch dialog". 415 // DSDS + MEP + two active sims 416 showMepSwitchSimConfirmDialog(); 417 } 418 return; 419 } 420 421 // Showing the "switch dialog" for below cases. 422 // case1: SS mode + psim switch on from esim. 423 // case2: SS mode + esim switch from psim. 424 // case3: DSDS mode + No MEP + esim switch on from another esim. 425 SubscriptionInfo activeSub = 426 (isMultiSimEnabled && isSwitchingBetweenEsims) 427 ? mActiveSubInfos.stream() 428 .filter(activeSubInfo -> activeSubInfo.isEmbedded()) 429 .findFirst().get() 430 : mActiveSubInfos.get(0); 431 ConfirmDialogFragment.show( 432 this, 433 ConfirmDialogFragment.OnConfirmListener.class, 434 DIALOG_TAG_ENABLE_SIM_CONFIRMATION, 435 getSwitchSubscriptionTitle(), 436 getSwitchDialogBodyMsg(activeSub, isSwitchingBetweenEsims), 437 getSwitchDialogPosBtnText(), 438 getString(R.string.sim_action_cancel)); 439 } 440 showNonSwitchSimConfirmDialog()441 private void showNonSwitchSimConfirmDialog() { 442 ConfirmDialogFragment.show( 443 this, 444 ConfirmDialogFragment.OnConfirmListener.class, 445 DIALOG_TAG_ENABLE_SIM_CONFIRMATION, 446 getEnableSubscriptionTitle(), 447 null /* msg */, 448 getString(R.string.condition_turn_on), 449 getString(R.string.sim_action_cancel)); 450 } 451 showMepSwitchSimConfirmDialog()452 private void showMepSwitchSimConfirmDialog() { 453 Log.d(TAG, "showMepSwitchSimConfirmDialog"); 454 final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 455 mSubInfo, this); 456 String title = getString(R.string.sim_action_switch_sub_dialog_mep_title, displayName); 457 final StringBuilder switchDialogMsg = new StringBuilder(); 458 switchDialogMsg.append( 459 getString(R.string.sim_action_switch_sub_dialog_mep_text, displayName)); 460 if (isRtlMode) { 461 /* The RTL symbols must be added before and after each sentence. 462 * (Each message are all with two line break symbols) 463 */ 464 switchDialogMsg.insert(0, RTL_MARK) 465 .insert(switchDialogMsg.length(), RTL_MARK); 466 } 467 ConfirmDialogFragment.show( 468 this, 469 ConfirmDialogFragment.OnConfirmListener.class, 470 DIALOG_TAG_ENABLE_SIM_CONFIRMATION_MEP, 471 title, 472 switchDialogMsg.toString(), 473 null, 474 null, 475 getSwitchDialogBodyList()); 476 } 477 getSwitchDialogPosBtnText()478 private String getSwitchDialogPosBtnText() { 479 return mIsEsimOperation 480 ? getString( 481 R.string.sim_action_switch_sub_dialog_confirm, 482 SubscriptionUtil.getUniqueSubscriptionDisplayName(mSubInfo, this)) 483 : getString(R.string.sim_switch_button); 484 } 485 getEnableSubscriptionTitle()486 private String getEnableSubscriptionTitle() { 487 final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 488 mSubInfo, this); 489 if (mSubInfo == null || TextUtils.isEmpty(displayName)) { 490 return getString(R.string.sim_action_enable_sub_dialog_title_without_carrier_name); 491 } 492 return getString(R.string.sim_action_enable_sub_dialog_title, displayName); 493 } 494 getSwitchSubscriptionTitle()495 private String getSwitchSubscriptionTitle() { 496 if (mIsEsimOperation) { 497 return getString( 498 R.string.sim_action_switch_sub_dialog_title, 499 SubscriptionUtil.getUniqueSubscriptionDisplayName(mSubInfo, this)); 500 } 501 return getString(R.string.sim_action_switch_psim_dialog_title); 502 } 503 getSwitchDialogBodyMsg(SubscriptionInfo activeSub, boolean betweenEsim)504 private String getSwitchDialogBodyMsg(SubscriptionInfo activeSub, boolean betweenEsim) { 505 final CharSequence subInfoName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 506 mSubInfo, this); 507 final CharSequence activeSubName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 508 activeSub, this); 509 final StringBuilder switchDialogMsg = new StringBuilder(); 510 if (betweenEsim && mIsEsimOperation) { 511 switchDialogMsg.append(getString( 512 R.string.sim_action_switch_sub_dialog_text_downloaded, 513 subInfoName, 514 activeSubName)); 515 } else if (mIsEsimOperation) { 516 switchDialogMsg.append(getString( 517 R.string.sim_action_switch_sub_dialog_text, 518 subInfoName, 519 activeSubName)); 520 } else { 521 switchDialogMsg.append(getString( 522 R.string.sim_action_switch_sub_dialog_text_single_sim, 523 activeSubName)); 524 } 525 if (isRtlMode) { 526 /* There are two lines of message in the dialog, and the RTL symbols must be added 527 * before and after each sentence, so use the line break symbol to find the position. 528 * (Each message are all with two line break symbols) 529 */ 530 switchDialogMsg.insert(0, RTL_MARK) 531 .insert(switchDialogMsg.indexOf(LINE_BREAK) - LINE_BREAK_OFFSET_ONE, RTL_MARK) 532 .insert(switchDialogMsg.indexOf(LINE_BREAK) + LINE_BREAK_OFFSET_TWO, RTL_MARK) 533 .insert(switchDialogMsg.length(), RTL_MARK); 534 } 535 return switchDialogMsg.toString(); 536 } 537 getSwitchDialogBodyList()538 private ArrayList<String> getSwitchDialogBodyList() { 539 ArrayList<String> list = new ArrayList<String>(mActiveSubInfos.stream() 540 .map(subInfo -> { 541 CharSequence subInfoName = SubscriptionUtil.getUniqueSubscriptionDisplayName( 542 subInfo, this); 543 return getString( 544 R.string.sim_action_switch_sub_dialog_carrier_list_item_for_turning_off, 545 subInfoName); 546 }) 547 .collect(Collectors.toList())); 548 list.add(getString(R.string.sim_action_cancel)); 549 return list; 550 } 551 isDsdsConditionSatisfied()552 private boolean isDsdsConditionSatisfied() { 553 if (mTelMgr.isMultiSimEnabled()) { 554 Log.d(TAG, "DSDS is already enabled. Condition not satisfied."); 555 return false; 556 } 557 if (mTelMgr.isMultiSimSupported() != TelephonyManager.MULTISIM_ALLOWED) { 558 Log.d(TAG, "Hardware does not support DSDS."); 559 return false; 560 } 561 boolean isActiveSim = SubscriptionUtil.getActiveSubscriptions( 562 mSubscriptionManager).size() > 0; 563 if (isMultipleEnabledProfilesSupported() && isActiveSim) { 564 Log.d(TAG, 565 "Device supports MEP and eSIM operation and eSIM profile is enabled." 566 + " DSDS condition satisfied."); 567 return true; 568 } 569 boolean isRemovableSimEnabled = isRemovableSimEnabled(); 570 if (mIsEsimOperation && isRemovableSimEnabled) { 571 Log.d(TAG, "eSIM operation and removable SIM is enabled. DSDS condition satisfied."); 572 return true; 573 } 574 boolean isEsimProfileEnabled = 575 SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager).stream() 576 .anyMatch(SubscriptionInfo::isEmbedded); 577 if (!mIsEsimOperation && isEsimProfileEnabled) { 578 Log.d(TAG, "Removable SIM operation and eSIM profile is enabled. DSDS condition" 579 + " satisfied."); 580 return true; 581 } 582 Log.d(TAG, "DSDS condition not satisfied."); 583 return false; 584 } 585 isRemovableSimEnabled()586 private boolean isRemovableSimEnabled() { 587 return UiccSlotUtil.isRemovableSimEnabled(mTelMgr); 588 } 589 isMultipleEnabledProfilesSupported()590 private boolean isMultipleEnabledProfilesSupported() { 591 List<UiccCardInfo> cardInfos = mTelMgr.getUiccCardsInfo(); 592 if (cardInfos == null) { 593 Log.w(TAG, "UICC cards info list is empty."); 594 return false; 595 } 596 return cardInfos.stream().anyMatch( 597 cardInfo -> cardInfo.isMultipleEnabledProfilesSupported()); 598 } 599 } 600