1 /* 2 * Copyright (C) 2017 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 android.service.euicc; 17 18 import static android.telephony.euicc.EuiccCardManager.ResetOption; 19 20 import android.Manifest; 21 import android.annotation.CallSuper; 22 import android.annotation.FlaggedApi; 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.RequiresPermission; 27 import android.annotation.SdkConstant; 28 import android.annotation.SystemApi; 29 import android.app.PendingIntent; 30 import android.app.Service; 31 import android.content.Intent; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 import android.telephony.euicc.DownloadableSubscription; 36 import android.telephony.euicc.EuiccInfo; 37 import android.telephony.euicc.EuiccManager; 38 import android.telephony.euicc.EuiccManager.OtaStatus; 39 import android.text.TextUtils; 40 import android.util.Log; 41 42 import com.android.internal.telephony.flags.Flags; 43 44 import java.io.PrintWriter; 45 import java.io.StringWriter; 46 import java.lang.annotation.Retention; 47 import java.lang.annotation.RetentionPolicy; 48 import java.util.concurrent.LinkedBlockingQueue; 49 import java.util.concurrent.ThreadFactory; 50 import java.util.concurrent.ThreadPoolExecutor; 51 import java.util.concurrent.TimeUnit; 52 import java.util.concurrent.atomic.AtomicInteger; 53 54 /** 55 * Service interface linking the system with an eUICC local profile assistant (LPA) application. 56 * 57 * <p>An LPA consists of two separate components (which may both be implemented in the same APK): 58 * the LPA backend, and the LPA UI or LUI. 59 * 60 * <p>To implement the LPA backend, you must extend this class and declare this service in your 61 * manifest file. The service must require the 62 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter 63 * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent 64 * filter to be set to a non-zero value in case multiple implementations are present on the device. 65 * See the below example. Note that there will be problem if two LPAs are present and they have the 66 * same priority. 67 * Example: 68 * 69 * <pre>{@code 70 * <service android:name=".MyEuiccService" 71 * android:permission="android.permission.BIND_EUICC_SERVICE"> 72 * <intent-filter android:priority="100"> 73 * <action android:name="android.service.euicc.EuiccService" /> 74 * </intent-filter> 75 * </service> 76 * }</pre> 77 * 78 * <p>To implement the LUI, you must provide an activity for the following actions: 79 * 80 * <ul> 81 * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS} 82 * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} 83 * </ul> 84 * 85 * <p>As with the service, each activity must require the 86 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent 87 * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero 88 * priority. 89 * 90 * <p>Old implementations of EuiccService may support passing in slot IDs equal to 91 * {@link android.telephony.SubscriptionManager#INVALID_SIM_SLOT_INDEX}, which allows the LPA to 92 * decide which eUICC to target when there are multiple eUICCs. This behavior is not supported in 93 * Android Q or later. 94 * 95 * @hide 96 */ 97 @SystemApi 98 public abstract class EuiccService extends Service { 99 private static final String TAG = "EuiccService"; 100 101 /** Action which must be included in this service's intent filter. */ 102 public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; 103 104 /** Category which must be defined to all UI actions, for efficient lookup. */ 105 public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI"; 106 107 // LUI actions. These are passthroughs of the corresponding EuiccManager actions. 108 109 /** 110 * Action used to bind the carrier app and get the activation code from the carrier app. This 111 * activation code will be used to download the eSIM profile during eSIM activation flow. 112 */ 113 public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = 114 "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE"; 115 116 /** 117 * Intent action sent by the LPA to launch a carrier app Activity for eSIM activation, e.g. a 118 * carrier login screen. Carrier apps wishing to support this activation method must implement 119 * an Activity that responds to this intent action. Upon completion, the Activity must return 120 * one of the following results to the LPA: 121 * 122 * <p>{@code Activity.RESULT_CANCELED}: The LPA should treat this as an back button and abort 123 * the activation flow. 124 * <p>{@code Activity.RESULT_OK}: The LPA should try to get an activation code from the carrier 125 * app by binding to the carrier app service implementing 126 * {@link #ACTION_BIND_CARRIER_PROVISIONING_SERVICE}. 127 * <p>{@code Activity.RESULT_OK} with 128 * {@link android.telephony.euicc.EuiccManager#EXTRA_USE_QR_SCANNER} set to true: The LPA should 129 * start a QR scanner for the user to scan an eSIM profile QR code. 130 * <p>For other results: The LPA should treat this as an error. 131 **/ 132 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 133 public static final String ACTION_START_CARRIER_ACTIVATION = 134 "android.service.euicc.action.START_CARRIER_ACTIVATION"; 135 136 /** 137 * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS 138 * The difference is this one is used by system to bring up the LUI. 139 */ 140 @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) 141 public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = 142 "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; 143 144 /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */ 145 @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) 146 public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = 147 "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; 148 149 /** @see android.telephony.euicc.EuiccManager#ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS */ 150 @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) 151 public static final String ACTION_TRANSFER_EMBEDDED_SUBSCRIPTIONS = 152 "android.service.euicc.action.TRANSFER_EMBEDDED_SUBSCRIPTIONS"; 153 154 /** @see android.telephony.euicc.EuiccManager#ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION */ 155 @RequiresPermission(Manifest.permission.BIND_EUICC_SERVICE) 156 public static final String ACTION_CONVERT_TO_EMBEDDED_SUBSCRIPTION = 157 "android.service.euicc.action.CONVERT_TO_EMBEDDED_SUBSCRIPTION"; 158 159 /** 160 * @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED. This is 161 * a protected intent that can only be sent by the system, and requires the 162 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 163 */ 164 public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = 165 "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED"; 166 167 /** 168 * @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED. This is 169 * a protected intent that can only be sent by the system, and requires the 170 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 171 */ 172 public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = 173 "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED"; 174 175 /** 176 * @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED. This is 177 * a protected intent that can only be sent by the system, and requires the 178 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 179 */ 180 public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = 181 "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED"; 182 183 /** 184 * @see android.telephony.euicc.EuiccManager#ACTION_START_EUICC_ACTIVATION. This is 185 * a protected intent that can only be sent by the system, and requires the 186 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. 187 */ 188 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 189 public static final String ACTION_START_EUICC_ACTIVATION = 190 "android.service.euicc.action.START_EUICC_ACTIVATION"; 191 192 // LUI resolution actions. These are called by the platform to resolve errors in situations that 193 // require user interaction. 194 // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are 195 // more scoped out. 196 /** 197 * Alert the user that this action will result in an active SIM being deactivated. 198 * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml. 199 */ 200 public static final String ACTION_RESOLVE_DEACTIVATE_SIM = 201 "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; 202 /** 203 * Alert the user about a download/switch being done for an app that doesn't currently have 204 * carrier privileges. 205 */ 206 public static final String ACTION_RESOLVE_NO_PRIVILEGES = 207 "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; 208 209 /** 210 * Ask the user to input carrier confirmation code. 211 * 212 * @deprecated From Q, the resolvable errors happened in the download step are presented as 213 * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding action would be 214 * {@link #ACTION_RESOLVE_RESOLVABLE_ERRORS}. 215 */ 216 @Deprecated 217 public static final String ACTION_RESOLVE_CONFIRMATION_CODE = 218 "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; 219 220 /** Ask the user to resolve all the resolvable errors. */ 221 public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = 222 "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS"; 223 224 /** @hide */ 225 @Retention(RetentionPolicy.SOURCE) 226 @IntDef(flag = true, prefix = { "RESOLVABLE_ERROR_" }, value = { 227 RESOLVABLE_ERROR_CONFIRMATION_CODE, 228 RESOLVABLE_ERROR_POLICY_RULES, 229 }) 230 public @interface ResolvableError {} 231 232 /** 233 * Possible value for the bit map of resolvable errors indicating the download process needs 234 * the user to input confirmation code. 235 */ 236 public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1 << 0; 237 /** 238 * Possible value for the bit map of resolvable errors indicating the download process needs 239 * the user's consent to allow profile policy rules. 240 */ 241 public static final int RESOLVABLE_ERROR_POLICY_RULES = 1 << 1; 242 243 /** 244 * Intent extra set for resolution requests containing the package name of the calling app. 245 * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM, 246 * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_RESOLVABLE_ERRORS. 247 */ 248 public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = 249 "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; 250 251 /** 252 * Intent extra set for resolution requests containing the list of resolvable errors to be 253 * resolved. Each resolvable error is an integer. Its possible values include: 254 * <UL> 255 * <LI>{@link #RESOLVABLE_ERROR_CONFIRMATION_CODE} 256 * <LI>{@link #RESOLVABLE_ERROR_POLICY_RULES} 257 * </UL> 258 */ 259 public static final String EXTRA_RESOLVABLE_ERRORS = 260 "android.service.euicc.extra.RESOLVABLE_ERRORS"; 261 262 /** 263 * Intent extra set for resolution requests containing a boolean indicating whether to ask the 264 * user to retry another confirmation code. 265 */ 266 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = 267 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; 268 269 /** 270 * Intent extra set for resolution requests containing an int indicating the current card Id. 271 */ 272 public static final String EXTRA_RESOLUTION_CARD_ID = 273 "android.service.euicc.extra.RESOLUTION_CARD_ID"; 274 275 /** 276 * Intent extra set for resolution requests containing an int indicating the subscription id 277 * to be enabled. 278 */ 279 public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = 280 "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID"; 281 282 /** 283 * Intent extra set for resolution requests containing an int indicating the current port index. 284 */ 285 public static final String EXTRA_RESOLUTION_PORT_INDEX = 286 "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; 287 288 /** 289 * Intent extra set for resolution requests containing a bool indicating whether to use the 290 * given port index. For example, if {@link #switchToSubscription(int, PendingIntent)} is 291 * called, then no portIndex has been provided by the caller, and this extra will be false. 292 */ 293 public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = 294 "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX"; 295 296 /** @hide */ 297 @Retention(RetentionPolicy.SOURCE) 298 @IntDef(prefix = { "RESULT_" }, value = { 299 RESULT_OK, 300 RESULT_MUST_DEACTIVATE_SIM, 301 RESULT_RESOLVABLE_ERRORS, 302 RESULT_NEED_CONFIRMATION_CODE, 303 RESULT_FIRST_USER, 304 }) 305 public @interface Result {} 306 307 /** Result code for a successful operation. */ 308 public static final int RESULT_OK = 0; 309 /** Result code indicating that an active SIM must be deactivated to perform the operation. */ 310 public static final int RESULT_MUST_DEACTIVATE_SIM = -1; 311 /** Result code indicating that the user must resolve resolvable errors. */ 312 public static final int RESULT_RESOLVABLE_ERRORS = -2; 313 /** 314 * Result code indicating that the user must input a carrier confirmation code. 315 * 316 * @deprecated From Q, the resolvable errors happened in the download step are presented as 317 * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding result would be 318 * {@link #RESULT_RESOLVABLE_ERRORS}. 319 */ 320 @Deprecated 321 public static final int RESULT_NEED_CONFIRMATION_CODE = -2; 322 // New predefined codes should have negative values. 323 324 /** Start of implementation-specific error results. */ 325 public static final int RESULT_FIRST_USER = 1; 326 327 /** 328 * Boolean extra for resolution actions indicating whether the user granted consent. 329 * This is used and set by the implementation and used in {@code EuiccOperation}. 330 */ 331 public static final String EXTRA_RESOLUTION_CONSENT = 332 "android.service.euicc.extra.RESOLUTION_CONSENT"; 333 /** 334 * String extra for resolution actions indicating the carrier confirmation code. 335 * This is used and set by the implementation and used in {@code EuiccOperation}. 336 */ 337 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = 338 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; 339 /** 340 * String extra for resolution actions indicating whether the user allows policy rules. 341 * This is used and set by the implementation and used in {@code EuiccOperation}. 342 */ 343 public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = 344 "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES"; 345 346 private final IEuiccService.Stub mStubWrapper; 347 348 private ThreadPoolExecutor mExecutor; 349 EuiccService()350 public EuiccService() { 351 mStubWrapper = new IEuiccServiceWrapper(); 352 } 353 354 /** 355 * Given a SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2), encode it to 356 * the format described in 357 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 358 * 359 * @param subjectCode SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2) 360 * @param reasonCode ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) 361 * @return encoded error code described in 362 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 363 * @throws NumberFormatException when the Subject/Reason code contains non digits 364 * @throws IllegalArgumentException when Subject/Reason code is null/empty 365 * @throws UnsupportedOperationException when sections has more than four layers (e.g 5.8.1.2) 366 * or when an number is bigger than 15 367 */ encodeSmdxSubjectAndReasonCode(@ullable String subjectCode, @Nullable String reasonCode)368 public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode, 369 @Nullable String reasonCode) { 370 final int maxSupportedSection = 3; 371 final int maxSupportedDigit = 15; 372 final int bitsPerSection = 4; 373 374 if (TextUtils.isEmpty(subjectCode) || TextUtils.isEmpty(reasonCode)) { 375 throw new IllegalArgumentException("SubjectCode/ReasonCode is empty"); 376 } 377 378 final String[] subjectCodeToken = subjectCode.split("\\."); 379 final String[] reasonCodeToken = reasonCode.split("\\."); 380 381 if (subjectCodeToken.length > maxSupportedSection 382 || reasonCodeToken.length > maxSupportedSection) { 383 throw new UnsupportedOperationException("Only three nested layer is supported."); 384 } 385 386 int result = EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE; 387 388 // Pad the 0s needed for subject code 389 result = result << (maxSupportedSection - subjectCodeToken.length) * bitsPerSection; 390 391 for (String digitString : subjectCodeToken) { 392 int num = Integer.parseInt(digitString); 393 if (num > maxSupportedDigit) { 394 throw new UnsupportedOperationException("SubjectCode exceeds " + maxSupportedDigit); 395 } 396 result = (result << bitsPerSection) + num; 397 } 398 399 // Pad the 0s needed for reason code 400 result = result << (maxSupportedSection - reasonCodeToken.length) * bitsPerSection; 401 for (String digitString : reasonCodeToken) { 402 int num = Integer.parseInt(digitString); 403 if (num > maxSupportedDigit) { 404 throw new UnsupportedOperationException("ReasonCode exceeds " + maxSupportedDigit); 405 } 406 result = (result << bitsPerSection) + num; 407 } 408 409 return result; 410 } 411 412 @Override 413 @CallSuper onCreate()414 public void onCreate() { 415 super.onCreate(); 416 // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to 417 // an external process, but doing so means the requests are serialized by binder, which is 418 // not desired. Spin up a background thread pool to allow requests to be parallelized. 419 // TODO(b/38206971): Consider removing this if basic card-level functions like listing 420 // profiles are moved to the platform. 421 mExecutor = new ThreadPoolExecutor( 422 4 /* corePoolSize */, 423 4 /* maxPoolSize */, 424 30, TimeUnit.SECONDS, /* keepAliveTime */ 425 new LinkedBlockingQueue<>(), /* workQueue */ 426 new ThreadFactory() { 427 private final AtomicInteger mCount = new AtomicInteger(1); 428 429 @Override 430 public Thread newThread(Runnable r) { 431 return new Thread(r, "EuiccService #" + mCount.getAndIncrement()); 432 } 433 } 434 ); 435 mExecutor.allowCoreThreadTimeOut(true); 436 } 437 438 @Override 439 @CallSuper onDestroy()440 public void onDestroy() { 441 mExecutor.shutdownNow(); 442 super.onDestroy(); 443 } 444 445 /** 446 * If overriding this method, call through to the super method for any unknown actions. 447 * {@inheritDoc} 448 */ 449 @Override 450 @CallSuper onBind(Intent intent)451 public IBinder onBind(Intent intent) { 452 return mStubWrapper; 453 } 454 455 /** 456 * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} 457 * 458 * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} 459 * 460 * @see IEuiccService#startOtaIfNecessary 461 */ 462 public abstract static class OtaStatusChangedCallback { 463 /** Called when OTA status is changed. */ onOtaStatusChanged(int status)464 public abstract void onOtaStatusChanged(int status); 465 } 466 467 /** 468 * Return the EID of the eUICC. 469 * 470 * @param slotId ID of the SIM slot being queried. 471 * @return the EID. 472 * @see android.telephony.euicc.EuiccManager#getEid 473 */ 474 // TODO(b/36260308): Update doc when we have multi-SIM support. onGetEid(int slotId)475 public abstract String onGetEid(int slotId); 476 477 /** 478 * Return the status of OTA update. 479 * 480 * @param slotId ID of the SIM slot to use for the operation. 481 * @return The status of Euicc OTA update. 482 * @see android.telephony.euicc.EuiccManager#getOtaStatus 483 */ onGetOtaStatus(int slotId)484 public abstract @OtaStatus int onGetOtaStatus(int slotId); 485 486 /** 487 * Perform OTA if current OS is not the latest one. 488 * 489 * @param slotId ID of the SIM slot to use for the operation. 490 * @param statusChangedCallback Function called when OTA status changed. 491 */ onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)492 public abstract void onStartOtaIfNecessary( 493 int slotId, OtaStatusChangedCallback statusChangedCallback); 494 495 /** 496 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 497 * 498 * @param slotId ID of the SIM slot to use for the operation. 499 * @param subscription A subscription whose metadata needs to be populated. 500 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 501 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 502 * should be returned to allow the user to consent to this operation first. 503 * @return The result of the operation. 504 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 505 */ onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)506 public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 507 int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); 508 509 /** 510 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 511 * 512 * @param slotId ID of the SIM slot to use for the operation. 513 * @param portIndex Index of the port from the slot. portIndex is used if the eUICC must 514 * be activated to perform the operation. 515 * @param subscription A subscription whose metadata needs to be populated. 516 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 517 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 518 * should be returned to allow the user to consent to this operation first. 519 * @return The result of the operation. 520 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 521 */ 522 @NonNull onGetDownloadableSubscriptionMetadata( int slotId, int portIndex, @NonNull DownloadableSubscription subscription, boolean forceDeactivateSim)523 public GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 524 int slotId, int portIndex, @NonNull DownloadableSubscription subscription, 525 boolean forceDeactivateSim) { 526 // stub implementation, LPA needs to implement this 527 throw new UnsupportedOperationException( 528 "LPA must override onGetDownloadableSubscriptionMetadata"); 529 } 530 531 /** 532 * Return metadata for subscriptions which are available for download for this device. 533 * 534 * @param slotId ID of the SIM slot to use for the operation. 535 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 536 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 537 * should be returned to allow the user to consent to this operation first. 538 * @return The result of the list operation. 539 * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList 540 */ 541 public abstract GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)542 onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim); 543 544 /** 545 * Download the given subscription. 546 * 547 * @param slotId ID of the SIM slot to use for the operation. 548 * @param subscription The subscription to download. 549 * @param switchAfterDownload If true, the subscription should be enabled upon successful 550 * download. 551 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 552 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 553 * should be returned to allow the user to consent to this operation first. 554 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 555 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 556 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 557 * the user allows profile policy rules or not. 558 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 559 * bit map, and original the card Id. The result code may be one of the predefined 560 * {@code RESULT_} constants or any implementation-specific code starting with 561 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 562 * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, 563 * this method does nothing and returns null by default. 564 * @see android.telephony.euicc.EuiccManager#downloadSubscription 565 * @deprecated prefer {@link #onDownloadSubscription(int, int, 566 * DownloadableSubscription, boolean, boolean, Bundle)} 567 */ 568 @Deprecated onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @Nullable Bundle resolvedBundle)569 public DownloadSubscriptionResult onDownloadSubscription(int slotId, 570 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 571 boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { 572 return null; 573 } 574 575 /** 576 * Download the given subscription. 577 * 578 * @param slotIndex Index of the SIM slot to use for the operation. 579 * @param portIndex Index of the port from the slot. portIndex is used when 580 * switchAfterDownload is set to {@code true}, otherwise download is port agnostic. 581 * @param subscription The subscription to download. 582 * @param switchAfterDownload If true, the subscription should be enabled upon successful 583 * download. 584 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 585 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 586 * should be returned to allow the user to consent to this operation first. 587 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 588 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 589 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 590 * the user allows profile policy rules or not. 591 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 592 * bit map, and original the card Id. The result code may be one of the predefined 593 * {@code RESULT_} constants or any implementation-specific code starting with 594 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 595 * defined in {@code RESOLVABLE_ERROR_}. 596 * @see android.telephony.euicc.EuiccManager#downloadSubscription 597 */ 598 @NonNull onDownloadSubscription(int slotIndex, int portIndex, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @NonNull Bundle resolvedBundle)599 public DownloadSubscriptionResult onDownloadSubscription(int slotIndex, int portIndex, 600 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 601 boolean forceDeactivateSim, @NonNull Bundle resolvedBundle) { 602 // stub implementation, LPA needs to implement this 603 throw new UnsupportedOperationException("LPA must override onDownloadSubscription"); 604 } 605 606 /** 607 * Download the given subscription. 608 * 609 * @param slotId ID of the SIM slot to use for the operation. 610 * @param subscription The subscription to download. 611 * @param switchAfterDownload If true, the subscription should be enabled upon successful 612 * download. 613 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 614 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 615 * should be returned to allow the user to consent to this operation first. 616 * @return the result of the download operation. May be one of the predefined {@code RESULT_} 617 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 618 * @see android.telephony.euicc.EuiccManager#downloadSubscription 619 * 620 * @deprecated From Q, a subclass should use and override the above 621 * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The 622 * default return value for this one is Integer.MIN_VALUE. 623 */ onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)624 @Deprecated public @Result int onDownloadSubscription(int slotId, 625 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 626 boolean forceDeactivateSim) { 627 return Integer.MIN_VALUE; 628 } 629 630 /** 631 * Return a list of all @link EuiccProfileInfo}s. 632 * 633 * @param slotId ID of the SIM slot to use for the operation. 634 * @return The result of the operation. 635 * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList 636 * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList 637 */ onGetEuiccProfileInfoList(int slotId)638 public abstract @NonNull GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); 639 640 /** 641 * Return info about the eUICC chip/device. 642 * 643 * @param slotId ID of the SIM slot to use for the operation. 644 * @return the {@link EuiccInfo} for the eUICC chip/device. 645 * @see android.telephony.euicc.EuiccManager#getEuiccInfo 646 */ onGetEuiccInfo(int slotId)647 public abstract @NonNull EuiccInfo onGetEuiccInfo(int slotId); 648 649 /** 650 * Delete the given subscription. 651 * 652 * <p>If the subscription is currently active, it should be deactivated first (equivalent to a 653 * physical SIM being ejected). 654 * 655 * @param slotId ID of the SIM slot to use for the operation. 656 * @param iccid the ICCID of the subscription to delete. 657 * @return the result of the delete operation. May be one of the predefined {@code RESULT_} 658 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 659 * @see android.telephony.euicc.EuiccManager#deleteSubscription 660 */ onDeleteSubscription(int slotId, String iccid)661 public abstract @Result int onDeleteSubscription(int slotId, String iccid); 662 663 /** 664 * Switch to the given subscription. 665 * 666 * @param slotId ID of the SIM slot to use for the operation. 667 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 668 * profile should be deactivated and no profile should be activated to replace it - this is 669 * equivalent to a physical SIM being ejected. 670 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 671 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 672 * should be returned to allow the user to consent to this operation first. 673 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 674 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 675 * @see android.telephony.euicc.EuiccManager#switchToSubscription 676 * 677 * @deprecated prefer {@link #onSwitchToSubscriptionWithPort(int, int, String, boolean)} 678 */ onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)679 @Deprecated public abstract @Result int onSwitchToSubscription(int slotId, 680 @Nullable String iccid, boolean forceDeactivateSim); 681 682 /** 683 * Switch to the given subscription. 684 * 685 * @param slotId ID of the SIM slot to use for the operation. 686 * @param portIndex which port on the eUICC to use 687 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 688 * profile should be deactivated and no profile should be activated to replace it - this is 689 * equivalent to a physical SIM being ejected. 690 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 691 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 692 * should be returned to allow the user to consent to this operation first. 693 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 694 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 695 * @see android.telephony.euicc.EuiccManager#switchToSubscription 696 */ onSwitchToSubscriptionWithPort(int slotId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim)697 public @Result int onSwitchToSubscriptionWithPort(int slotId, int portIndex, 698 @Nullable String iccid, boolean forceDeactivateSim) { 699 // stub implementation, LPA needs to implement this 700 throw new UnsupportedOperationException("LPA must override onSwitchToSubscriptionWithPort"); 701 } 702 703 /** 704 * Update the nickname of the given subscription. 705 * 706 * @param slotId ID of the SIM slot to use for the operation. 707 * @param iccid the ICCID of the subscription to update. 708 * @param nickname the new nickname to apply. 709 * @return the result of the update operation. May be one of the predefined {@code RESULT_} 710 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 711 * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname 712 */ onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)713 public abstract int onUpdateSubscriptionNickname(int slotId, String iccid, 714 String nickname); 715 716 /** 717 * Erase all operational subscriptions on the device. 718 * 719 * <p>This is intended to be used for device resets. As such, the reset should be performed even 720 * if an active SIM must be deactivated in order to access the eUICC. 721 * 722 * @param slotId ID of the SIM slot to use for the operation. 723 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 724 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 725 * @see android.telephony.euicc.EuiccManager#eraseSubscriptions 726 * 727 * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase 728 * and use {@link #onEraseSubscriptions(int, int)} instead 729 */ 730 @Deprecated onEraseSubscriptions(int slotId)731 public abstract int onEraseSubscriptions(int slotId); 732 733 /** 734 * Erase specific subscriptions on the device. 735 * 736 * <p>This is intended to be used for device resets. As such, the reset should be performed even 737 * if an active SIM must be deactivated in order to access the eUICC. 738 * 739 * @param slotIndex index of the SIM slot to use for the operation. 740 * @param options flag for specific group of subscriptions to erase 741 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 742 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 743 * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions 744 */ onEraseSubscriptions(int slotIndex, @ResetOption int options)745 public int onEraseSubscriptions(int slotIndex, @ResetOption int options) { 746 throw new UnsupportedOperationException( 747 "This method must be overridden to enable the ResetOption parameter"); 748 } 749 750 /** 751 * Ensure that subscriptions will be retained on the next factory reset. 752 * 753 * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to 754 * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation 755 * should persist some bit that will remain accessible after the factory reset to bypass this 756 * flow when this method is called. 757 * 758 * @param slotId ID of the SIM slot to use for the operation. 759 * @return the result of the operation. May be one of the predefined {@code RESULT_} constants 760 * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 761 */ onRetainSubscriptionsForFactoryReset(int slotId)762 public abstract int onRetainSubscriptionsForFactoryReset(int slotId); 763 764 /** 765 * Return the available memory in bytes of the eUICC. 766 * 767 * @param slotId ID of the SIM slot being queried. 768 * @return the available memory in bytes. 769 * @see android.telephony.euicc.EuiccManager#getAvailableMemoryInBytes 770 */ 771 @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY) onGetAvailableMemoryInBytes(int slotId)772 public long onGetAvailableMemoryInBytes(int slotId) { 773 // stub implementation, LPA needs to implement this 774 throw new UnsupportedOperationException("The connected LPA does not implement" 775 + "EuiccService#onGetAvailableMemoryInBytes(int)"); 776 } 777 778 /** 779 * Dump to a provided printWriter. 780 */ dump(@onNull PrintWriter printWriter)781 public void dump(@NonNull PrintWriter printWriter) { 782 printWriter.println("The connected LPA does not implement EuiccService#dump()"); 783 } 784 785 /** 786 * Result code to string 787 * 788 * @param result The result code. 789 * @return The result code in string format. 790 * 791 * @hide 792 */ resultToString(@esult int result)793 public static String resultToString(@Result int result) { 794 switch (result) { 795 case RESULT_OK: return "OK"; 796 case RESULT_MUST_DEACTIVATE_SIM : return "MUST_DEACTIVATE_SIM"; 797 case RESULT_RESOLVABLE_ERRORS: return "RESOLVABLE_ERRORS"; 798 case RESULT_FIRST_USER: return "FIRST_USER"; 799 default: 800 return "UNKNOWN(" + result + ")"; 801 } 802 } 803 804 /** 805 * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. 806 */ 807 private class IEuiccServiceWrapper extends IEuiccService.Stub { 808 @Override downloadSubscription(int slotId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, IDownloadSubscriptionCallback callback)809 public void downloadSubscription(int slotId, int portIndex, 810 DownloadableSubscription subscription, 811 boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, 812 IDownloadSubscriptionCallback callback) { 813 mExecutor.execute(new Runnable() { 814 @Override 815 public void run() { 816 DownloadSubscriptionResult result; 817 try { 818 result = EuiccService.this.onDownloadSubscription( 819 slotId, portIndex, subscription, switchAfterDownload, 820 forceDeactivateSim, resolvedBundle); 821 } catch (UnsupportedOperationException | AbstractMethodError e) { 822 Log.w(TAG, "The new onDownloadSubscription(int, int, " 823 + "DownloadableSubscription, boolean, boolean, Bundle) is not " 824 + "implemented. Fall back to the old one.", e); 825 result = EuiccService.this.onDownloadSubscription( 826 slotId, subscription, switchAfterDownload, 827 forceDeactivateSim, resolvedBundle); 828 } 829 try { 830 callback.onComplete(result); 831 } catch (RemoteException e) { 832 // Can't communicate with the phone process; ignore. 833 } 834 } 835 }); 836 } 837 838 @Override getEid(int slotId, IGetEidCallback callback)839 public void getEid(int slotId, IGetEidCallback callback) { 840 mExecutor.execute(new Runnable() { 841 @Override 842 public void run() { 843 String eid = EuiccService.this.onGetEid(slotId); 844 try { 845 callback.onSuccess(eid); 846 } catch (RemoteException e) { 847 // Can't communicate with the phone process; ignore. 848 } 849 } 850 }); 851 } 852 853 @Override 854 @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY) getAvailableMemoryInBytes( int slotId, IGetAvailableMemoryInBytesCallback callback)855 public void getAvailableMemoryInBytes( 856 int slotId, IGetAvailableMemoryInBytesCallback callback) { 857 mExecutor.execute( 858 () -> { 859 long availableMemoryInBytes = EuiccManager.EUICC_MEMORY_FIELD_UNAVAILABLE; 860 String unsupportedOperationMessage = ""; 861 try { 862 availableMemoryInBytes = 863 EuiccService.this.onGetAvailableMemoryInBytes(slotId); 864 } catch (UnsupportedOperationException e) { 865 unsupportedOperationMessage = e.getMessage(); 866 } 867 868 try { 869 if (!unsupportedOperationMessage.isEmpty()) { 870 callback.onUnsupportedOperationException( 871 unsupportedOperationMessage); 872 } else { 873 callback.onSuccess(availableMemoryInBytes); 874 } 875 } catch (RemoteException e) { 876 // Can't communicate with the phone process; ignore. 877 } 878 }); 879 } 880 881 @Override startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)882 public void startOtaIfNecessary( 883 int slotId, IOtaStatusChangedCallback statusChangedCallback) { 884 mExecutor.execute(new Runnable() { 885 @Override 886 public void run() { 887 EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { 888 @Override 889 public void onOtaStatusChanged(int status) { 890 try { 891 statusChangedCallback.onOtaStatusChanged(status); 892 } catch (RemoteException e) { 893 // Can't communicate with the phone process; ignore. 894 } 895 } 896 }); 897 } 898 }); 899 } 900 901 @Override getOtaStatus(int slotId, IGetOtaStatusCallback callback)902 public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { 903 mExecutor.execute(new Runnable() { 904 @Override 905 public void run() { 906 int status = EuiccService.this.onGetOtaStatus(slotId); 907 try { 908 callback.onSuccess(status); 909 } catch (RemoteException e) { 910 // Can't communicate with the phone process; ignore. 911 } 912 } 913 }); 914 } 915 916 @Override getDownloadableSubscriptionMetadata(int slotId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)917 public void getDownloadableSubscriptionMetadata(int slotId, int portIndex, 918 DownloadableSubscription subscription, 919 boolean switchAfterDownload, boolean forceDeactivateSim, 920 IGetDownloadableSubscriptionMetadataCallback callback) { 921 mExecutor.execute(new Runnable() { 922 @Override 923 public void run() { 924 GetDownloadableSubscriptionMetadataResult result; 925 if (switchAfterDownload) { 926 try { 927 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 928 slotId, portIndex, subscription, forceDeactivateSim); 929 } catch (UnsupportedOperationException | AbstractMethodError e) { 930 Log.w(TAG, "The new onGetDownloadableSubscriptionMetadata(int, int, " 931 + "DownloadableSubscription, boolean) is not implemented." 932 + " Fall back to the old one.", e); 933 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 934 slotId, subscription, forceDeactivateSim); 935 } 936 } else { 937 // When switchAfterDownload is false, this operation is port agnostic. 938 // Call API without portIndex. 939 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 940 slotId, subscription, forceDeactivateSim); 941 } 942 try { 943 callback.onComplete(result); 944 } catch (RemoteException e) { 945 // Can't communicate with the phone process; ignore. 946 } 947 } 948 }); 949 } 950 951 @Override getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)952 public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, 953 IGetDefaultDownloadableSubscriptionListCallback callback) { 954 mExecutor.execute(new Runnable() { 955 @Override 956 public void run() { 957 GetDefaultDownloadableSubscriptionListResult result = 958 EuiccService.this.onGetDefaultDownloadableSubscriptionList( 959 slotId, forceDeactivateSim); 960 try { 961 callback.onComplete(result); 962 } catch (RemoteException e) { 963 // Can't communicate with the phone process; ignore. 964 } 965 } 966 }); 967 } 968 969 @Override getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)970 public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { 971 mExecutor.execute(new Runnable() { 972 @Override 973 public void run() { 974 GetEuiccProfileInfoListResult result = 975 EuiccService.this.onGetEuiccProfileInfoList(slotId); 976 try { 977 callback.onComplete(result); 978 } catch (RemoteException e) { 979 // Can't communicate with the phone process; ignore. 980 } 981 } 982 }); 983 } 984 985 @Override getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)986 public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) { 987 mExecutor.execute(new Runnable() { 988 @Override 989 public void run() { 990 EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId); 991 try { 992 callback.onSuccess(euiccInfo); 993 } catch (RemoteException e) { 994 // Can't communicate with the phone process; ignore. 995 } 996 } 997 }); 998 999 } 1000 1001 @Override deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)1002 public void deleteSubscription(int slotId, String iccid, 1003 IDeleteSubscriptionCallback callback) { 1004 mExecutor.execute(new Runnable() { 1005 @Override 1006 public void run() { 1007 int result = EuiccService.this.onDeleteSubscription(slotId, iccid); 1008 try { 1009 callback.onComplete(result); 1010 } catch (RemoteException e) { 1011 // Can't communicate with the phone process; ignore. 1012 } 1013 } 1014 }); 1015 } 1016 @Override switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, boolean usePortIndex)1017 public void switchToSubscription(int slotId, int portIndex, String iccid, 1018 boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, 1019 boolean usePortIndex) { 1020 mExecutor.execute(new Runnable() { 1021 @Override 1022 public void run() { 1023 int result = 0; 1024 if (usePortIndex) { 1025 result = EuiccService.this.onSwitchToSubscriptionWithPort( 1026 slotId, portIndex, iccid, forceDeactivateSim); 1027 } else { 1028 result = EuiccService.this.onSwitchToSubscription( 1029 slotId, iccid, forceDeactivateSim); 1030 } 1031 try { 1032 callback.onComplete(result); 1033 } catch (RemoteException e) { 1034 // Can't communicate with the phone process; ignore. 1035 } 1036 } 1037 }); 1038 } 1039 1040 @Override updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)1041 public void updateSubscriptionNickname(int slotId, String iccid, String nickname, 1042 IUpdateSubscriptionNicknameCallback callback) { 1043 mExecutor.execute(new Runnable() { 1044 @Override 1045 public void run() { 1046 int result = 1047 EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname); 1048 try { 1049 callback.onComplete(result); 1050 } catch (RemoteException e) { 1051 // Can't communicate with the phone process; ignore. 1052 } 1053 } 1054 }); 1055 } 1056 1057 @Override eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)1058 public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) { 1059 mExecutor.execute(new Runnable() { 1060 @Override 1061 public void run() { 1062 int result = EuiccService.this.onEraseSubscriptions(slotId); 1063 try { 1064 callback.onComplete(result); 1065 } catch (RemoteException e) { 1066 // Can't communicate with the phone process; ignore. 1067 } 1068 } 1069 }); 1070 } 1071 1072 @Override eraseSubscriptionsWithOptions( int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback)1073 public void eraseSubscriptionsWithOptions( 1074 int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) { 1075 mExecutor.execute(new Runnable() { 1076 @Override 1077 public void run() { 1078 int result = EuiccService.this.onEraseSubscriptions(slotIndex, options); 1079 try { 1080 callback.onComplete(result); 1081 } catch (RemoteException e) { 1082 // Can't communicate with the phone process; ignore. 1083 } 1084 } 1085 }); 1086 } 1087 1088 @Override retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)1089 public void retainSubscriptionsForFactoryReset(int slotId, 1090 IRetainSubscriptionsForFactoryResetCallback callback) { 1091 mExecutor.execute(new Runnable() { 1092 @Override 1093 public void run() { 1094 int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); 1095 try { 1096 callback.onComplete(result); 1097 } catch (RemoteException e) { 1098 // Can't communicate with the phone process; ignore. 1099 } 1100 } 1101 }); 1102 } 1103 1104 @Override dump(IEuiccServiceDumpResultCallback callback)1105 public void dump(IEuiccServiceDumpResultCallback callback) throws RemoteException { 1106 mExecutor.execute(new Runnable() { 1107 @Override 1108 public void run() { 1109 try { 1110 final StringWriter sw = new StringWriter(); 1111 final PrintWriter pw = new PrintWriter(sw); 1112 EuiccService.this.dump(pw); 1113 callback.onComplete(sw.toString()); 1114 } catch (RemoteException e) { 1115 // Can't communicate with the phone process; ignore. 1116 } 1117 } 1118 }); 1119 } 1120 } 1121 } 1122