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