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 android.annotation.CallSuper; 19 import android.annotation.Nullable; 20 import android.annotation.SystemApi; 21 import android.app.Service; 22 import android.content.Intent; 23 import android.os.IBinder; 24 import android.os.RemoteException; 25 import android.telephony.euicc.DownloadableSubscription; 26 import android.telephony.euicc.EuiccInfo; 27 import android.telephony.euicc.EuiccManager.OtaStatus; 28 import android.util.ArraySet; 29 30 import java.util.concurrent.LinkedBlockingQueue; 31 import java.util.concurrent.ThreadFactory; 32 import java.util.concurrent.ThreadPoolExecutor; 33 import java.util.concurrent.TimeUnit; 34 import java.util.concurrent.atomic.AtomicInteger; 35 36 /** 37 * Service interface linking the system with an eUICC local profile assistant (LPA) application. 38 * 39 * <p>An LPA consists of two separate components (which may both be implemented in the same APK): 40 * the LPA backend, and the LPA UI or LUI. 41 * 42 * <p>To implement the LPA backend, you must extend this class and declare this service in your 43 * manifest file. The service must require the 44 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter 45 * with the {@link #EUICC_SERVICE_INTERFACE} action. It's suggested that the priority of the intent 46 * filter to be set to a non-zero value in case multiple implementations are present on the device. 47 * See the below example. Note that there will be problem if two LPAs are present and they have the 48 * same priority. 49 * Example: 50 * 51 * <pre>{@code 52 * <service android:name=".MyEuiccService" 53 * android:permission="android.permission.BIND_EUICC_SERVICE"> 54 * <intent-filter android:priority="100"> 55 * <action android:name="android.service.euicc.EuiccService" /> 56 * </intent-filter> 57 * </service> 58 * }</pre> 59 * 60 * <p>To implement the LUI, you must provide an activity for the following actions: 61 * 62 * <ul> 63 * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS} 64 * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} 65 * </ul> 66 * 67 * <p>As with the service, each activity must require the 68 * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent 69 * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero 70 * priority. 71 * 72 * @hide 73 */ 74 @SystemApi 75 public abstract class EuiccService extends Service { 76 /** Action which must be included in this service's intent filter. */ 77 public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService"; 78 79 /** Category which must be defined to all UI actions, for efficient lookup. */ 80 public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI"; 81 82 // LUI actions. These are passthroughs of the corresponding EuiccManager actions. 83 84 /** 85 * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS 86 * The difference is this one is used by system to bring up the LUI. 87 */ 88 public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = 89 "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS"; 90 /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */ 91 public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = 92 "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION"; 93 94 // LUI resolution actions. These are called by the platform to resolve errors in situations that 95 // require user interaction. 96 // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are 97 // more scoped out. 98 /** 99 * Alert the user that this action will result in an active SIM being deactivated. 100 * To implement the LUI triggered by the system, you need to define this in AndroidManifest.xml. 101 */ 102 public static final String ACTION_RESOLVE_DEACTIVATE_SIM = 103 "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM"; 104 /** 105 * Alert the user about a download/switch being done for an app that doesn't currently have 106 * carrier privileges. 107 */ 108 public static final String ACTION_RESOLVE_NO_PRIVILEGES = 109 "android.service.euicc.action.RESOLVE_NO_PRIVILEGES"; 110 111 /** Ask the user to input carrier confirmation code. */ 112 public static final String ACTION_RESOLVE_CONFIRMATION_CODE = 113 "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE"; 114 115 /** 116 * Intent extra set for resolution requests containing the package name of the calling app. 117 * This is used by the above actions including ACTION_RESOLVE_DEACTIVATE_SIM, 118 * ACTION_RESOLVE_NO_PRIVILEGES and ACTION_RESOLVE_CONFIRMATION_CODE. 119 */ 120 public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = 121 "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE"; 122 123 /** 124 * Intent extra set for resolution requests containing a boolean indicating whether to ask the 125 * user to retry another confirmation code. 126 */ 127 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = 128 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED"; 129 130 /** Result code for a successful operation. */ 131 public static final int RESULT_OK = 0; 132 /** Result code indicating that an active SIM must be deactivated to perform the operation. */ 133 public static final int RESULT_MUST_DEACTIVATE_SIM = -1; 134 /** Result code indicating that the user must input a carrier confirmation code. */ 135 public static final int RESULT_NEED_CONFIRMATION_CODE = -2; 136 // New predefined codes should have negative values. 137 138 /** Start of implementation-specific error results. */ 139 public static final int RESULT_FIRST_USER = 1; 140 141 /** 142 * List of all valid resolution actions for validation purposes. 143 * @hide 144 */ 145 public static final ArraySet<String> RESOLUTION_ACTIONS; 146 static { 147 RESOLUTION_ACTIONS = new ArraySet<>(); 148 RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM); 149 RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES); 150 RESOLUTION_ACTIONS.add(EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE); 151 } 152 153 /** 154 * Boolean extra for resolution actions indicating whether the user granted consent. 155 * This is used and set by the implementation and used in {@code EuiccOperation}. 156 */ 157 public static final String EXTRA_RESOLUTION_CONSENT = 158 "android.service.euicc.extra.RESOLUTION_CONSENT"; 159 /** 160 * String extra for resolution actions indicating the carrier confirmation code. 161 * This is used and set by the implementation and used in {@code EuiccOperation}. 162 */ 163 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = 164 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; 165 166 private final IEuiccService.Stub mStubWrapper; 167 168 private ThreadPoolExecutor mExecutor; 169 EuiccService()170 public EuiccService() { 171 mStubWrapper = new IEuiccServiceWrapper(); 172 } 173 174 @Override 175 @CallSuper onCreate()176 public void onCreate() { 177 super.onCreate(); 178 // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to 179 // an external process, but doing so means the requests are serialized by binder, which is 180 // not desired. Spin up a background thread pool to allow requests to be parallelized. 181 // TODO(b/38206971): Consider removing this if basic card-level functions like listing 182 // profiles are moved to the platform. 183 mExecutor = new ThreadPoolExecutor( 184 4 /* corePoolSize */, 185 4 /* maxPoolSize */, 186 30, TimeUnit.SECONDS, /* keepAliveTime */ 187 new LinkedBlockingQueue<>(), /* workQueue */ 188 new ThreadFactory() { 189 private final AtomicInteger mCount = new AtomicInteger(1); 190 191 @Override 192 public Thread newThread(Runnable r) { 193 return new Thread(r, "EuiccService #" + mCount.getAndIncrement()); 194 } 195 } 196 ); 197 mExecutor.allowCoreThreadTimeOut(true); 198 } 199 200 @Override 201 @CallSuper onDestroy()202 public void onDestroy() { 203 mExecutor.shutdownNow(); 204 super.onDestroy(); 205 } 206 207 /** 208 * If overriding this method, call through to the super method for any unknown actions. 209 * {@inheritDoc} 210 */ 211 @Override 212 @CallSuper onBind(Intent intent)213 public IBinder onBind(Intent intent) { 214 return mStubWrapper; 215 } 216 217 /** 218 * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} 219 * 220 * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} 221 * 222 * @see IEuiccService#startOtaIfNecessary 223 */ 224 public abstract static class OtaStatusChangedCallback { 225 /** Called when OTA status is changed. */ onOtaStatusChanged(int status)226 public abstract void onOtaStatusChanged(int status); 227 } 228 229 /** 230 * Return the EID of the eUICC. 231 * 232 * @param slotId ID of the SIM slot being queried. This is currently not populated but is here 233 * to future-proof the APIs. 234 * @return the EID. 235 * @see android.telephony.euicc.EuiccManager#getEid 236 */ 237 // TODO(b/36260308): Update doc when we have multi-SIM support. onGetEid(int slotId)238 public abstract String onGetEid(int slotId); 239 240 /** 241 * Return the status of OTA update. 242 * 243 * @param slotId ID of the SIM slot to use for the operation. This is currently not populated 244 * but is here to future-proof the APIs. 245 * @return The status of Euicc OTA update. 246 * @see android.telephony.euicc.EuiccManager#getOtaStatus 247 */ onGetOtaStatus(int slotId)248 public abstract @OtaStatus int onGetOtaStatus(int slotId); 249 250 /** 251 * Perform OTA if current OS is not the latest one. 252 * 253 * @param slotId ID of the SIM slot to use for the operation. This is currently not populated 254 * but is here to future-proof the APIs. 255 * @param statusChangedCallback Function called when OTA status changed. 256 */ onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)257 public abstract void onStartOtaIfNecessary( 258 int slotId, OtaStatusChangedCallback statusChangedCallback); 259 260 /** 261 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 262 * 263 * @param slotId ID of the SIM slot to use for the operation. 264 * @param subscription A subscription whose metadata needs to be populated. 265 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 266 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 267 * should be returned to allow the user to consent to this operation first. 268 * @return The result of the operation. 269 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 270 */ onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)271 public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 272 int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); 273 274 /** 275 * Return metadata for subscriptions which are available for download for this device. 276 * 277 * @param slotId ID of the SIM slot to use for the operation. This is currently not populated 278 * but is here to future-proof the APIs. 279 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 280 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 281 * should be returned to allow the user to consent to this operation first. 282 * @return The result of the list operation. 283 * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList 284 */ 285 public abstract GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)286 onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim); 287 288 /** 289 * Download the given subscription. 290 * 291 * @param slotId ID of the SIM slot to use for the operation. 292 * @param subscription The subscription to download. 293 * @param switchAfterDownload If true, the subscription should be enabled upon successful 294 * download. 295 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 296 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 297 * should be returned to allow the user to consent to this operation first. 298 * @return the result of the download operation. May be one of the predefined {@code RESULT_} 299 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 300 * @see android.telephony.euicc.EuiccManager#downloadSubscription 301 */ onDownloadSubscription(int slotId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)302 public abstract int onDownloadSubscription(int slotId, 303 DownloadableSubscription subscription, boolean switchAfterDownload, 304 boolean forceDeactivateSim); 305 306 /** 307 * Return a list of all @link EuiccProfileInfo}s. 308 * 309 * @param slotId ID of the SIM slot to use for the operation. 310 * @return The result of the operation. 311 * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList 312 * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList 313 */ onGetEuiccProfileInfoList(int slotId)314 public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); 315 316 /** 317 * Return info about the eUICC chip/device. 318 * 319 * @param slotId ID of the SIM slot to use for the operation. 320 * @return the {@link EuiccInfo} for the eUICC chip/device. 321 * @see android.telephony.euicc.EuiccManager#getEuiccInfo 322 */ onGetEuiccInfo(int slotId)323 public abstract EuiccInfo onGetEuiccInfo(int slotId); 324 325 /** 326 * Delete the given subscription. 327 * 328 * <p>If the subscription is currently active, it should be deactivated first (equivalent to a 329 * physical SIM being ejected). 330 * 331 * @param slotId ID of the SIM slot to use for the operation. 332 * @param iccid the ICCID of the subscription to delete. 333 * @return the result of the delete operation. May be one of the predefined {@code RESULT_} 334 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 335 * @see android.telephony.euicc.EuiccManager#deleteSubscription 336 */ onDeleteSubscription(int slotId, String iccid)337 public abstract int onDeleteSubscription(int slotId, String iccid); 338 339 /** 340 * Switch to the given subscription. 341 * 342 * @param slotId ID of the SIM slot to use for the operation. 343 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 344 * profile should be deactivated and no profile should be activated to replace it - this is 345 * equivalent to a physical SIM being ejected. 346 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 347 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 348 * should be returned to allow the user to consent to this operation first. 349 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 350 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 351 * @see android.telephony.euicc.EuiccManager#switchToSubscription 352 */ onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)353 public abstract int onSwitchToSubscription(int slotId, @Nullable String iccid, 354 boolean forceDeactivateSim); 355 356 /** 357 * Update the nickname of the given subscription. 358 * 359 * @param slotId ID of the SIM slot to use for the operation. 360 * @param iccid the ICCID of the subscription to update. 361 * @param nickname the new nickname to apply. 362 * @return the result of the update operation. May be one of the predefined {@code RESULT_} 363 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 364 * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname 365 */ onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)366 public abstract int onUpdateSubscriptionNickname(int slotId, String iccid, 367 String nickname); 368 369 /** 370 * Erase all of the subscriptions on the device. 371 * 372 * <p>This is intended to be used for device resets. As such, the reset should be performed even 373 * if an active SIM must be deactivated in order to access the eUICC. 374 * 375 * @param slotId ID of the SIM slot to use for the operation. This is currently not populated 376 * but is here to future-proof the APIs. 377 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 378 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 379 * @see android.telephony.euicc.EuiccManager#eraseSubscriptions 380 */ onEraseSubscriptions(int slotId)381 public abstract int onEraseSubscriptions(int slotId); 382 383 /** 384 * Ensure that subscriptions will be retained on the next factory reset. 385 * 386 * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to 387 * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation 388 * should persist some bit that will remain accessible after the factory reset to bypass this 389 * flow when this method is called. 390 * 391 * @param slotId ID of the SIM slot to use for the operation. This is currently not populated 392 * but is here to future-proof the APIs. 393 * @return the result of the operation. May be one of the predefined {@code RESULT_} constants 394 * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 395 */ onRetainSubscriptionsForFactoryReset(int slotId)396 public abstract int onRetainSubscriptionsForFactoryReset(int slotId); 397 398 /** 399 * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. 400 */ 401 private class IEuiccServiceWrapper extends IEuiccService.Stub { 402 @Override downloadSubscription(int slotId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, IDownloadSubscriptionCallback callback)403 public void downloadSubscription(int slotId, DownloadableSubscription subscription, 404 boolean switchAfterDownload, boolean forceDeactivateSim, 405 IDownloadSubscriptionCallback callback) { 406 mExecutor.execute(new Runnable() { 407 @Override 408 public void run() { 409 int result = EuiccService.this.onDownloadSubscription( 410 slotId, subscription, switchAfterDownload, forceDeactivateSim); 411 try { 412 callback.onComplete(result); 413 } catch (RemoteException e) { 414 // Can't communicate with the phone process; ignore. 415 } 416 } 417 }); 418 } 419 420 @Override getEid(int slotId, IGetEidCallback callback)421 public void getEid(int slotId, IGetEidCallback callback) { 422 mExecutor.execute(new Runnable() { 423 @Override 424 public void run() { 425 String eid = EuiccService.this.onGetEid(slotId); 426 try { 427 callback.onSuccess(eid); 428 } catch (RemoteException e) { 429 // Can't communicate with the phone process; ignore. 430 } 431 } 432 }); 433 } 434 435 @Override startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)436 public void startOtaIfNecessary( 437 int slotId, IOtaStatusChangedCallback statusChangedCallback) { 438 mExecutor.execute(new Runnable() { 439 @Override 440 public void run() { 441 EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { 442 @Override 443 public void onOtaStatusChanged(int status) { 444 try { 445 statusChangedCallback.onOtaStatusChanged(status); 446 } catch (RemoteException e) { 447 // Can't communicate with the phone process; ignore. 448 } 449 } 450 }); 451 } 452 }); 453 } 454 455 @Override getOtaStatus(int slotId, IGetOtaStatusCallback callback)456 public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { 457 mExecutor.execute(new Runnable() { 458 @Override 459 public void run() { 460 int status = EuiccService.this.onGetOtaStatus(slotId); 461 try { 462 callback.onSuccess(status); 463 } catch (RemoteException e) { 464 // Can't communicate with the phone process; ignore. 465 } 466 } 467 }); 468 } 469 470 @Override getDownloadableSubscriptionMetadata(int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)471 public void getDownloadableSubscriptionMetadata(int slotId, 472 DownloadableSubscription subscription, 473 boolean forceDeactivateSim, 474 IGetDownloadableSubscriptionMetadataCallback callback) { 475 mExecutor.execute(new Runnable() { 476 @Override 477 public void run() { 478 GetDownloadableSubscriptionMetadataResult result = 479 EuiccService.this.onGetDownloadableSubscriptionMetadata( 480 slotId, subscription, forceDeactivateSim); 481 try { 482 callback.onComplete(result); 483 } catch (RemoteException e) { 484 // Can't communicate with the phone process; ignore. 485 } 486 } 487 }); 488 } 489 490 @Override getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)491 public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, 492 IGetDefaultDownloadableSubscriptionListCallback callback) { 493 mExecutor.execute(new Runnable() { 494 @Override 495 public void run() { 496 GetDefaultDownloadableSubscriptionListResult result = 497 EuiccService.this.onGetDefaultDownloadableSubscriptionList( 498 slotId, forceDeactivateSim); 499 try { 500 callback.onComplete(result); 501 } catch (RemoteException e) { 502 // Can't communicate with the phone process; ignore. 503 } 504 } 505 }); 506 } 507 508 @Override getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)509 public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { 510 mExecutor.execute(new Runnable() { 511 @Override 512 public void run() { 513 GetEuiccProfileInfoListResult result = 514 EuiccService.this.onGetEuiccProfileInfoList(slotId); 515 try { 516 callback.onComplete(result); 517 } catch (RemoteException e) { 518 // Can't communicate with the phone process; ignore. 519 } 520 } 521 }); 522 } 523 524 @Override getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)525 public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) { 526 mExecutor.execute(new Runnable() { 527 @Override 528 public void run() { 529 EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId); 530 try { 531 callback.onSuccess(euiccInfo); 532 } catch (RemoteException e) { 533 // Can't communicate with the phone process; ignore. 534 } 535 } 536 }); 537 538 } 539 540 @Override deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)541 public void deleteSubscription(int slotId, String iccid, 542 IDeleteSubscriptionCallback callback) { 543 mExecutor.execute(new Runnable() { 544 @Override 545 public void run() { 546 int result = EuiccService.this.onDeleteSubscription(slotId, iccid); 547 try { 548 callback.onComplete(result); 549 } catch (RemoteException e) { 550 // Can't communicate with the phone process; ignore. 551 } 552 } 553 }); 554 } 555 556 @Override switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback)557 public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, 558 ISwitchToSubscriptionCallback callback) { 559 mExecutor.execute(new Runnable() { 560 @Override 561 public void run() { 562 int result = 563 EuiccService.this.onSwitchToSubscription( 564 slotId, iccid, forceDeactivateSim); 565 try { 566 callback.onComplete(result); 567 } catch (RemoteException e) { 568 // Can't communicate with the phone process; ignore. 569 } 570 } 571 }); 572 } 573 574 @Override updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)575 public void updateSubscriptionNickname(int slotId, String iccid, String nickname, 576 IUpdateSubscriptionNicknameCallback callback) { 577 mExecutor.execute(new Runnable() { 578 @Override 579 public void run() { 580 int result = 581 EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname); 582 try { 583 callback.onComplete(result); 584 } catch (RemoteException e) { 585 // Can't communicate with the phone process; ignore. 586 } 587 } 588 }); 589 } 590 591 @Override eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)592 public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) { 593 mExecutor.execute(new Runnable() { 594 @Override 595 public void run() { 596 int result = EuiccService.this.onEraseSubscriptions(slotId); 597 try { 598 callback.onComplete(result); 599 } catch (RemoteException e) { 600 // Can't communicate with the phone process; ignore. 601 } 602 } 603 }); 604 } 605 606 @Override retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)607 public void retainSubscriptionsForFactoryReset(int slotId, 608 IRetainSubscriptionsForFactoryResetCallback callback) { 609 mExecutor.execute(new Runnable() { 610 @Override 611 public void run() { 612 int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); 613 try { 614 callback.onComplete(result); 615 } catch (RemoteException e) { 616 // Can't communicate with the phone process; ignore. 617 } 618 } 619 }); 620 } 621 } 622 } 623