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