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 * Bundle key for the {@code resolvedBundle} passed to {@link #onDownloadSubscription( 271 * int, int, DownloadableSubscription, boolean, boolean, Bundle)}. The value is a 272 * {@link String} for the package name of the app calling the 273 * {@link EuiccManager#downloadSubscription(int, DownloadableSubscription, PendingIntent)} API. 274 * This is to be used by LPA to determine the app that is requesting the download. 275 * 276 * @hide 277 */ 278 public static final String EXTRA_PACKAGE_NAME = "android.service.euicc.extra.PACKAGE_NAME"; 279 280 /** 281 * Intent extra set for resolution requests containing an int indicating the current card Id. 282 */ 283 public static final String EXTRA_RESOLUTION_CARD_ID = 284 "android.service.euicc.extra.RESOLUTION_CARD_ID"; 285 286 /** 287 * Intent extra set for resolution requests containing an int indicating the subscription id 288 * to be enabled. 289 */ 290 public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = 291 "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID"; 292 293 /** 294 * Intent extra set for resolution requests containing an int indicating the current port index. 295 */ 296 public static final String EXTRA_RESOLUTION_PORT_INDEX = 297 "android.service.euicc.extra.RESOLUTION_PORT_INDEX"; 298 299 /** 300 * Intent extra set for resolution requests containing a bool indicating whether to use the 301 * given port index. For example, if {@link #switchToSubscription(int, PendingIntent)} is 302 * called, then no portIndex has been provided by the caller, and this extra will be false. 303 */ 304 public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = 305 "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX"; 306 307 /** @hide */ 308 @Retention(RetentionPolicy.SOURCE) 309 @IntDef(prefix = { "RESULT_" }, value = { 310 RESULT_OK, 311 RESULT_MUST_DEACTIVATE_SIM, 312 RESULT_RESOLVABLE_ERRORS, 313 RESULT_NEED_CONFIRMATION_CODE, 314 RESULT_FIRST_USER, 315 }) 316 public @interface Result {} 317 318 /** Result code for a successful operation. */ 319 public static final int RESULT_OK = 0; 320 /** Result code indicating that an active SIM must be deactivated to perform the operation. */ 321 public static final int RESULT_MUST_DEACTIVATE_SIM = -1; 322 /** Result code indicating that the user must resolve resolvable errors. */ 323 public static final int RESULT_RESOLVABLE_ERRORS = -2; 324 /** 325 * Result code indicating that the user must input a carrier confirmation code. 326 * 327 * @deprecated From Q, the resolvable errors happened in the download step are presented as 328 * bit map in {@link #EXTRA_RESOLVABLE_ERRORS}. The corresponding result would be 329 * {@link #RESULT_RESOLVABLE_ERRORS}. 330 */ 331 @Deprecated 332 public static final int RESULT_NEED_CONFIRMATION_CODE = -2; 333 // New predefined codes should have negative values. 334 335 /** Start of implementation-specific error results. */ 336 public static final int RESULT_FIRST_USER = 1; 337 338 /** 339 * Boolean extra for resolution actions indicating whether the user granted consent. 340 * This is used and set by the implementation and used in {@code EuiccOperation}. 341 */ 342 public static final String EXTRA_RESOLUTION_CONSENT = 343 "android.service.euicc.extra.RESOLUTION_CONSENT"; 344 /** 345 * String extra for resolution actions indicating the carrier confirmation code. 346 * This is used and set by the implementation and used in {@code EuiccOperation}. 347 */ 348 public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = 349 "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE"; 350 /** 351 * String extra for resolution actions indicating whether the user allows policy rules. 352 * This is used and set by the implementation and used in {@code EuiccOperation}. 353 */ 354 public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = 355 "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES"; 356 357 private final IEuiccService.Stub mStubWrapper; 358 359 private ThreadPoolExecutor mExecutor; 360 EuiccService()361 public EuiccService() { 362 mStubWrapper = new IEuiccServiceWrapper(); 363 } 364 365 /** 366 * Given a SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2), encode it to 367 * the format described in 368 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 369 * 370 * @param subjectCode SubjectCode[5.2.6.1] from GSMA (SGP.22 v2.2) 371 * @param reasonCode ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) 372 * @return encoded error code described in 373 * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} 374 * @throws NumberFormatException when the Subject/Reason code contains non digits 375 * @throws IllegalArgumentException when Subject/Reason code is null/empty 376 * @throws UnsupportedOperationException when sections has more than four layers (e.g 5.8.1.2) 377 * or when an number is bigger than 15 378 */ encodeSmdxSubjectAndReasonCode(@ullable String subjectCode, @Nullable String reasonCode)379 public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode, 380 @Nullable String reasonCode) { 381 final int maxSupportedSection = 3; 382 final int maxSupportedDigit = 15; 383 final int bitsPerSection = 4; 384 385 if (TextUtils.isEmpty(subjectCode) || TextUtils.isEmpty(reasonCode)) { 386 throw new IllegalArgumentException("SubjectCode/ReasonCode is empty"); 387 } 388 389 final String[] subjectCodeToken = subjectCode.split("\\."); 390 final String[] reasonCodeToken = reasonCode.split("\\."); 391 392 if (subjectCodeToken.length > maxSupportedSection 393 || reasonCodeToken.length > maxSupportedSection) { 394 throw new UnsupportedOperationException("Only three nested layer is supported."); 395 } 396 397 int result = EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE; 398 399 // Pad the 0s needed for subject code 400 result = result << (maxSupportedSection - subjectCodeToken.length) * bitsPerSection; 401 402 for (String digitString : subjectCodeToken) { 403 int num = Integer.parseInt(digitString); 404 if (num > maxSupportedDigit) { 405 throw new UnsupportedOperationException("SubjectCode exceeds " + maxSupportedDigit); 406 } 407 result = (result << bitsPerSection) + num; 408 } 409 410 // Pad the 0s needed for reason code 411 result = result << (maxSupportedSection - reasonCodeToken.length) * bitsPerSection; 412 for (String digitString : reasonCodeToken) { 413 int num = Integer.parseInt(digitString); 414 if (num > maxSupportedDigit) { 415 throw new UnsupportedOperationException("ReasonCode exceeds " + maxSupportedDigit); 416 } 417 result = (result << bitsPerSection) + num; 418 } 419 420 return result; 421 } 422 423 @Override 424 @CallSuper onCreate()425 public void onCreate() { 426 super.onCreate(); 427 // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to 428 // an external process, but doing so means the requests are serialized by binder, which is 429 // not desired. Spin up a background thread pool to allow requests to be parallelized. 430 // TODO(b/38206971): Consider removing this if basic card-level functions like listing 431 // profiles are moved to the platform. 432 mExecutor = new ThreadPoolExecutor( 433 4 /* corePoolSize */, 434 4 /* maxPoolSize */, 435 30, TimeUnit.SECONDS, /* keepAliveTime */ 436 new LinkedBlockingQueue<>(), /* workQueue */ 437 new ThreadFactory() { 438 private final AtomicInteger mCount = new AtomicInteger(1); 439 440 @Override 441 public Thread newThread(Runnable r) { 442 return new Thread(r, "EuiccService #" + mCount.getAndIncrement()); 443 } 444 } 445 ); 446 mExecutor.allowCoreThreadTimeOut(true); 447 } 448 449 @Override 450 @CallSuper onDestroy()451 public void onDestroy() { 452 mExecutor.shutdownNow(); 453 super.onDestroy(); 454 } 455 456 /** 457 * If overriding this method, call through to the super method for any unknown actions. 458 * {@inheritDoc} 459 */ 460 @Override 461 @CallSuper onBind(Intent intent)462 public IBinder onBind(Intent intent) { 463 return mStubWrapper; 464 } 465 466 /** 467 * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} 468 * 469 * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} 470 * 471 * @see IEuiccService#startOtaIfNecessary 472 */ 473 public abstract static class OtaStatusChangedCallback { 474 /** Called when OTA status is changed. */ onOtaStatusChanged(int status)475 public abstract void onOtaStatusChanged(int status); 476 } 477 478 /** 479 * Return the EID of the eUICC. 480 * 481 * @param slotId ID of the SIM slot being queried. 482 * @return the EID. 483 * @see android.telephony.euicc.EuiccManager#getEid 484 */ 485 // TODO(b/36260308): Update doc when we have multi-SIM support. onGetEid(int slotId)486 public abstract String onGetEid(int slotId); 487 488 /** 489 * Return the status of OTA update. 490 * 491 * @param slotId ID of the SIM slot to use for the operation. 492 * @return The status of Euicc OTA update. 493 * @see android.telephony.euicc.EuiccManager#getOtaStatus 494 */ onGetOtaStatus(int slotId)495 public abstract @OtaStatus int onGetOtaStatus(int slotId); 496 497 /** 498 * Perform OTA if current OS is not the latest one. 499 * 500 * @param slotId ID of the SIM slot to use for the operation. 501 * @param statusChangedCallback Function called when OTA status changed. 502 */ onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)503 public abstract void onStartOtaIfNecessary( 504 int slotId, OtaStatusChangedCallback statusChangedCallback); 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 subscription A subscription whose metadata needs to be populated. 511 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 512 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 513 * should be returned to allow the user to consent to this operation first. 514 * @return The result of the operation. 515 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 516 */ onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)517 public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 518 int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); 519 520 /** 521 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 522 * 523 * @param slotId ID of the SIM slot to use for the operation. 524 * @param portIndex Index of the port from the slot. portIndex is used if the eUICC must 525 * be activated to perform the operation. 526 * @param subscription A subscription whose metadata needs to be populated. 527 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 528 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 529 * should be returned to allow the user to consent to this operation first. 530 * @return The result of the operation. 531 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 532 */ 533 @NonNull onGetDownloadableSubscriptionMetadata( int slotId, int portIndex, @NonNull DownloadableSubscription subscription, boolean forceDeactivateSim)534 public GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 535 int slotId, int portIndex, @NonNull DownloadableSubscription subscription, 536 boolean forceDeactivateSim) { 537 // stub implementation, LPA needs to implement this 538 throw new UnsupportedOperationException( 539 "LPA must override onGetDownloadableSubscriptionMetadata"); 540 } 541 542 /** 543 * Return metadata for subscriptions which are available for download for this device. 544 * 545 * @param slotId ID of the SIM slot to use for the operation. 546 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 547 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 548 * should be returned to allow the user to consent to this operation first. 549 * @return The result of the list operation. 550 * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList 551 */ 552 public abstract GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)553 onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim); 554 555 /** 556 * Download the given subscription. 557 * 558 * @param slotId ID of the SIM slot to use for the operation. 559 * @param subscription The subscription to download. 560 * @param switchAfterDownload If true, the subscription should be enabled upon successful 561 * download. 562 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 563 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 564 * should be returned to allow the user to consent to this operation first. 565 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 566 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 567 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 568 * the user allows profile policy rules or not. 569 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 570 * bit map, and original the card Id. The result code may be one of the predefined 571 * {@code RESULT_} constants or any implementation-specific code starting with 572 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 573 * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, 574 * this method does nothing and returns null by default. 575 * @see android.telephony.euicc.EuiccManager#downloadSubscription 576 * @deprecated prefer {@link #onDownloadSubscription(int, int, 577 * DownloadableSubscription, boolean, boolean, Bundle)} 578 */ 579 @Deprecated onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @Nullable Bundle resolvedBundle)580 public DownloadSubscriptionResult onDownloadSubscription(int slotId, 581 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 582 boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { 583 return null; 584 } 585 586 /** 587 * Download the given subscription. 588 * 589 * @param slotIndex Index of the SIM slot to use for the operation. 590 * @param portIndex Index of the port from the slot. portIndex is used when 591 * switchAfterDownload is set to {@code true}, otherwise download is port agnostic. 592 * @param subscription The subscription to download. 593 * @param switchAfterDownload If true, the subscription should be enabled upon successful 594 * download. 595 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 596 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 597 * should be returned to allow the user to consent to this operation first. 598 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 599 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 600 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 601 * the user allows profile policy rules or not. 602 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 603 * bit map, and original the card Id. The result code may be one of the predefined 604 * {@code RESULT_} constants or any implementation-specific code starting with 605 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 606 * defined in {@code RESOLVABLE_ERROR_}. 607 * @see android.telephony.euicc.EuiccManager#downloadSubscription 608 */ 609 @NonNull onDownloadSubscription(int slotIndex, int portIndex, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @NonNull Bundle resolvedBundle)610 public DownloadSubscriptionResult onDownloadSubscription(int slotIndex, int portIndex, 611 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 612 boolean forceDeactivateSim, @NonNull Bundle resolvedBundle) { 613 // stub implementation, LPA needs to implement this 614 throw new UnsupportedOperationException("LPA must override onDownloadSubscription"); 615 } 616 617 /** 618 * Download the given subscription. 619 * 620 * @param slotId ID of the SIM slot to use for the operation. 621 * @param subscription The subscription to download. 622 * @param switchAfterDownload If true, the subscription should be enabled upon successful 623 * download. 624 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 625 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 626 * should be returned to allow the user to consent to this operation first. 627 * @return the result of the download operation. May be one of the predefined {@code RESULT_} 628 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 629 * @see android.telephony.euicc.EuiccManager#downloadSubscription 630 * 631 * @deprecated From Q, a subclass should use and override the above 632 * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The 633 * default return value for this one is Integer.MIN_VALUE. 634 */ onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)635 @Deprecated public @Result int onDownloadSubscription(int slotId, 636 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 637 boolean forceDeactivateSim) { 638 return Integer.MIN_VALUE; 639 } 640 641 /** 642 * Return a list of all @link EuiccProfileInfo}s. 643 * 644 * @param slotId ID of the SIM slot to use for the operation. 645 * @return The result of the operation. 646 * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList 647 * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList 648 */ onGetEuiccProfileInfoList(int slotId)649 public abstract @NonNull GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); 650 651 /** 652 * Return info about the eUICC chip/device. 653 * 654 * @param slotId ID of the SIM slot to use for the operation. 655 * @return the {@link EuiccInfo} for the eUICC chip/device. 656 * @see android.telephony.euicc.EuiccManager#getEuiccInfo 657 */ onGetEuiccInfo(int slotId)658 public abstract @NonNull EuiccInfo onGetEuiccInfo(int slotId); 659 660 /** 661 * Delete the given subscription. 662 * 663 * <p>If the subscription is currently active, it should be deactivated first (equivalent to a 664 * physical SIM being ejected). 665 * 666 * @param slotId ID of the SIM slot to use for the operation. 667 * @param iccid the ICCID of the subscription to delete. 668 * @return the result of the delete operation. May be one of the predefined {@code RESULT_} 669 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 670 * @see android.telephony.euicc.EuiccManager#deleteSubscription 671 */ onDeleteSubscription(int slotId, String iccid)672 public abstract @Result int onDeleteSubscription(int slotId, String iccid); 673 674 /** 675 * Switch to the given subscription. 676 * 677 * @param slotId ID of the SIM slot to use for the operation. 678 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 679 * profile should be deactivated and no profile should be activated to replace it - this is 680 * equivalent to a physical SIM being ejected. 681 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 682 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 683 * should be returned to allow the user to consent to this operation first. 684 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 685 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 686 * @see android.telephony.euicc.EuiccManager#switchToSubscription 687 * 688 * @deprecated prefer {@link #onSwitchToSubscriptionWithPort(int, int, String, boolean)} 689 */ onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)690 @Deprecated public abstract @Result int onSwitchToSubscription(int slotId, 691 @Nullable String iccid, boolean forceDeactivateSim); 692 693 /** 694 * Switch to the given subscription. 695 * 696 * @param slotId ID of the SIM slot to use for the operation. 697 * @param portIndex which port on the eUICC to use 698 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 699 * profile should be deactivated and no profile should be activated to replace it - this is 700 * equivalent to a physical SIM being ejected. 701 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 702 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 703 * should be returned to allow the user to consent to this operation first. 704 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 705 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 706 * @see android.telephony.euicc.EuiccManager#switchToSubscription 707 */ onSwitchToSubscriptionWithPort(int slotId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim)708 public @Result int onSwitchToSubscriptionWithPort(int slotId, int portIndex, 709 @Nullable String iccid, boolean forceDeactivateSim) { 710 // stub implementation, LPA needs to implement this 711 throw new UnsupportedOperationException("LPA must override onSwitchToSubscriptionWithPort"); 712 } 713 714 /** 715 * Update the nickname of the given subscription. 716 * 717 * @param slotId ID of the SIM slot to use for the operation. 718 * @param iccid the ICCID of the subscription to update. 719 * @param nickname the new nickname to apply. 720 * @return the result of the update 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#updateSubscriptionNickname 723 */ onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)724 public abstract int onUpdateSubscriptionNickname(int slotId, String iccid, 725 String nickname); 726 727 /** 728 * Erase all operational subscriptions on the device. 729 * 730 * <p>This is intended to be used for device resets. As such, the reset should be performed even 731 * if an active SIM must be deactivated in order to access the eUICC. 732 * 733 * @param slotId ID of the SIM slot to use for the operation. 734 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 735 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 736 * @see android.telephony.euicc.EuiccManager#eraseSubscriptions 737 * 738 * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase 739 * and use {@link #onEraseSubscriptions(int, int)} instead 740 */ 741 @Deprecated onEraseSubscriptions(int slotId)742 public abstract int onEraseSubscriptions(int slotId); 743 744 /** 745 * Erase specific subscriptions on the device. 746 * 747 * <p>This is intended to be used for device resets. As such, the reset should be performed even 748 * if an active SIM must be deactivated in order to access the eUICC. 749 * 750 * @param slotIndex index of the SIM slot to use for the operation. 751 * @param options flag for specific group of subscriptions to erase 752 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 753 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 754 * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions 755 */ onEraseSubscriptions(int slotIndex, @ResetOption int options)756 public int onEraseSubscriptions(int slotIndex, @ResetOption int options) { 757 throw new UnsupportedOperationException( 758 "This method must be overridden to enable the ResetOption parameter"); 759 } 760 761 /** 762 * Ensure that subscriptions will be retained on the next factory reset. 763 * 764 * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to 765 * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation 766 * should persist some bit that will remain accessible after the factory reset to bypass this 767 * flow when this method is called. 768 * 769 * @param slotId ID of the SIM slot to use for the operation. 770 * @return the result of the operation. May be one of the predefined {@code RESULT_} constants 771 * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 772 */ onRetainSubscriptionsForFactoryReset(int slotId)773 public abstract int onRetainSubscriptionsForFactoryReset(int slotId); 774 775 /** 776 * Return the available memory in bytes of the eUICC. 777 * 778 * @param slotId ID of the SIM slot being queried. 779 * @return the available memory in bytes. 780 * @see android.telephony.euicc.EuiccManager#getAvailableMemoryInBytes 781 */ 782 @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY) onGetAvailableMemoryInBytes(int slotId)783 public long onGetAvailableMemoryInBytes(int slotId) { 784 // stub implementation, LPA needs to implement this 785 throw new UnsupportedOperationException("The connected LPA does not implement" 786 + "EuiccService#onGetAvailableMemoryInBytes(int)"); 787 } 788 789 /** 790 * Dump to a provided printWriter. 791 */ dump(@onNull PrintWriter printWriter)792 public void dump(@NonNull PrintWriter printWriter) { 793 printWriter.println("The connected LPA does not implement EuiccService#dump()"); 794 } 795 796 /** 797 * Result code to string 798 * 799 * @param result The result code. 800 * @return The result code in string format. 801 * 802 * @hide 803 */ resultToString(@esult int result)804 public static String resultToString(@Result int result) { 805 switch (result) { 806 case RESULT_OK: return "OK"; 807 case RESULT_MUST_DEACTIVATE_SIM : return "MUST_DEACTIVATE_SIM"; 808 case RESULT_RESOLVABLE_ERRORS: return "RESOLVABLE_ERRORS"; 809 case RESULT_FIRST_USER: return "FIRST_USER"; 810 default: 811 return "UNKNOWN(" + result + ")"; 812 } 813 } 814 815 /** 816 * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. 817 */ 818 private class IEuiccServiceWrapper extends IEuiccService.Stub { 819 @Override downloadSubscription(int slotId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, IDownloadSubscriptionCallback callback)820 public void downloadSubscription(int slotId, int portIndex, 821 DownloadableSubscription subscription, 822 boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, 823 IDownloadSubscriptionCallback callback) { 824 mExecutor.execute(new Runnable() { 825 @Override 826 public void run() { 827 DownloadSubscriptionResult result; 828 try { 829 result = EuiccService.this.onDownloadSubscription( 830 slotId, portIndex, subscription, switchAfterDownload, 831 forceDeactivateSim, resolvedBundle); 832 } catch (UnsupportedOperationException | AbstractMethodError e) { 833 Log.w(TAG, "The new onDownloadSubscription(int, int, " 834 + "DownloadableSubscription, boolean, boolean, Bundle) is not " 835 + "implemented. Fall back to the old one.", e); 836 result = EuiccService.this.onDownloadSubscription( 837 slotId, subscription, switchAfterDownload, 838 forceDeactivateSim, resolvedBundle); 839 } 840 try { 841 callback.onComplete(result); 842 } catch (RemoteException e) { 843 // Can't communicate with the phone process; ignore. 844 } 845 } 846 }); 847 } 848 849 @Override getEid(int slotId, IGetEidCallback callback)850 public void getEid(int slotId, IGetEidCallback callback) { 851 mExecutor.execute(new Runnable() { 852 @Override 853 public void run() { 854 String eid = EuiccService.this.onGetEid(slotId); 855 try { 856 callback.onSuccess(eid); 857 } catch (RemoteException e) { 858 // Can't communicate with the phone process; ignore. 859 } 860 } 861 }); 862 } 863 864 @Override 865 @FlaggedApi(Flags.FLAG_ESIM_AVAILABLE_MEMORY) getAvailableMemoryInBytes( int slotId, IGetAvailableMemoryInBytesCallback callback)866 public void getAvailableMemoryInBytes( 867 int slotId, IGetAvailableMemoryInBytesCallback callback) { 868 mExecutor.execute( 869 () -> { 870 long availableMemoryInBytes = EuiccManager.EUICC_MEMORY_FIELD_UNAVAILABLE; 871 String unsupportedOperationMessage = ""; 872 try { 873 availableMemoryInBytes = 874 EuiccService.this.onGetAvailableMemoryInBytes(slotId); 875 } catch (UnsupportedOperationException e) { 876 unsupportedOperationMessage = e.getMessage(); 877 } 878 879 try { 880 if (!unsupportedOperationMessage.isEmpty()) { 881 callback.onUnsupportedOperationException( 882 unsupportedOperationMessage); 883 } else { 884 callback.onSuccess(availableMemoryInBytes); 885 } 886 } catch (RemoteException e) { 887 // Can't communicate with the phone process; ignore. 888 } 889 }); 890 } 891 892 @Override startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)893 public void startOtaIfNecessary( 894 int slotId, IOtaStatusChangedCallback statusChangedCallback) { 895 mExecutor.execute(new Runnable() { 896 @Override 897 public void run() { 898 EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { 899 @Override 900 public void onOtaStatusChanged(int status) { 901 try { 902 statusChangedCallback.onOtaStatusChanged(status); 903 } catch (RemoteException e) { 904 // Can't communicate with the phone process; ignore. 905 } 906 } 907 }); 908 } 909 }); 910 } 911 912 @Override getOtaStatus(int slotId, IGetOtaStatusCallback callback)913 public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { 914 mExecutor.execute(new Runnable() { 915 @Override 916 public void run() { 917 int status = EuiccService.this.onGetOtaStatus(slotId); 918 try { 919 callback.onSuccess(status); 920 } catch (RemoteException e) { 921 // Can't communicate with the phone process; ignore. 922 } 923 } 924 }); 925 } 926 927 @Override getDownloadableSubscriptionMetadata(int slotId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)928 public void getDownloadableSubscriptionMetadata(int slotId, int portIndex, 929 DownloadableSubscription subscription, 930 boolean switchAfterDownload, boolean forceDeactivateSim, 931 IGetDownloadableSubscriptionMetadataCallback callback) { 932 mExecutor.execute(new Runnable() { 933 @Override 934 public void run() { 935 GetDownloadableSubscriptionMetadataResult result; 936 if (switchAfterDownload) { 937 try { 938 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 939 slotId, portIndex, subscription, forceDeactivateSim); 940 } catch (UnsupportedOperationException | AbstractMethodError e) { 941 Log.w(TAG, "The new onGetDownloadableSubscriptionMetadata(int, int, " 942 + "DownloadableSubscription, boolean) is not implemented." 943 + " Fall back to the old one.", e); 944 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 945 slotId, subscription, forceDeactivateSim); 946 } 947 } else { 948 // When switchAfterDownload is false, this operation is port agnostic. 949 // Call API without portIndex. 950 result = EuiccService.this.onGetDownloadableSubscriptionMetadata( 951 slotId, subscription, forceDeactivateSim); 952 } 953 try { 954 callback.onComplete(result); 955 } catch (RemoteException e) { 956 // Can't communicate with the phone process; ignore. 957 } 958 } 959 }); 960 } 961 962 @Override getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)963 public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, 964 IGetDefaultDownloadableSubscriptionListCallback callback) { 965 mExecutor.execute(new Runnable() { 966 @Override 967 public void run() { 968 GetDefaultDownloadableSubscriptionListResult result = 969 EuiccService.this.onGetDefaultDownloadableSubscriptionList( 970 slotId, forceDeactivateSim); 971 try { 972 callback.onComplete(result); 973 } catch (RemoteException e) { 974 // Can't communicate with the phone process; ignore. 975 } 976 } 977 }); 978 } 979 980 @Override getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)981 public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { 982 mExecutor.execute(new Runnable() { 983 @Override 984 public void run() { 985 GetEuiccProfileInfoListResult result = 986 EuiccService.this.onGetEuiccProfileInfoList(slotId); 987 try { 988 callback.onComplete(result); 989 } catch (RemoteException e) { 990 // Can't communicate with the phone process; ignore. 991 } 992 } 993 }); 994 } 995 996 @Override getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)997 public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) { 998 mExecutor.execute(new Runnable() { 999 @Override 1000 public void run() { 1001 EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId); 1002 try { 1003 callback.onSuccess(euiccInfo); 1004 } catch (RemoteException e) { 1005 // Can't communicate with the phone process; ignore. 1006 } 1007 } 1008 }); 1009 1010 } 1011 1012 @Override deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)1013 public void deleteSubscription(int slotId, String iccid, 1014 IDeleteSubscriptionCallback callback) { 1015 mExecutor.execute(new Runnable() { 1016 @Override 1017 public void run() { 1018 int result = EuiccService.this.onDeleteSubscription(slotId, iccid); 1019 try { 1020 callback.onComplete(result); 1021 } catch (RemoteException e) { 1022 // Can't communicate with the phone process; ignore. 1023 } 1024 } 1025 }); 1026 } 1027 @Override switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, boolean usePortIndex)1028 public void switchToSubscription(int slotId, int portIndex, String iccid, 1029 boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback, 1030 boolean usePortIndex) { 1031 mExecutor.execute(new Runnable() { 1032 @Override 1033 public void run() { 1034 int result = 0; 1035 if (usePortIndex) { 1036 result = EuiccService.this.onSwitchToSubscriptionWithPort( 1037 slotId, portIndex, iccid, forceDeactivateSim); 1038 } else { 1039 result = EuiccService.this.onSwitchToSubscription( 1040 slotId, iccid, forceDeactivateSim); 1041 } 1042 try { 1043 callback.onComplete(result); 1044 } catch (RemoteException e) { 1045 // Can't communicate with the phone process; ignore. 1046 } 1047 } 1048 }); 1049 } 1050 1051 @Override updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)1052 public void updateSubscriptionNickname(int slotId, String iccid, String nickname, 1053 IUpdateSubscriptionNicknameCallback callback) { 1054 mExecutor.execute(new Runnable() { 1055 @Override 1056 public void run() { 1057 int result = 1058 EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname); 1059 try { 1060 callback.onComplete(result); 1061 } catch (RemoteException e) { 1062 // Can't communicate with the phone process; ignore. 1063 } 1064 } 1065 }); 1066 } 1067 1068 @Override eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)1069 public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) { 1070 mExecutor.execute(new Runnable() { 1071 @Override 1072 public void run() { 1073 int result = EuiccService.this.onEraseSubscriptions(slotId); 1074 try { 1075 callback.onComplete(result); 1076 } catch (RemoteException e) { 1077 // Can't communicate with the phone process; ignore. 1078 } 1079 } 1080 }); 1081 } 1082 1083 @Override eraseSubscriptionsWithOptions( int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback)1084 public void eraseSubscriptionsWithOptions( 1085 int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) { 1086 mExecutor.execute(new Runnable() { 1087 @Override 1088 public void run() { 1089 int result = EuiccService.this.onEraseSubscriptions(slotIndex, options); 1090 try { 1091 callback.onComplete(result); 1092 } catch (RemoteException e) { 1093 // Can't communicate with the phone process; ignore. 1094 } 1095 } 1096 }); 1097 } 1098 1099 @Override retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)1100 public void retainSubscriptionsForFactoryReset(int slotId, 1101 IRetainSubscriptionsForFactoryResetCallback callback) { 1102 mExecutor.execute(new Runnable() { 1103 @Override 1104 public void run() { 1105 int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); 1106 try { 1107 callback.onComplete(result); 1108 } catch (RemoteException e) { 1109 // Can't communicate with the phone process; ignore. 1110 } 1111 } 1112 }); 1113 } 1114 1115 @Override dump(IEuiccServiceDumpResultCallback callback)1116 public void dump(IEuiccServiceDumpResultCallback callback) throws RemoteException { 1117 mExecutor.execute(new Runnable() { 1118 @Override 1119 public void run() { 1120 try { 1121 final StringWriter sw = new StringWriter(); 1122 final PrintWriter pw = new PrintWriter(sw); 1123 EuiccService.this.dump(pw); 1124 callback.onComplete(sw.toString()); 1125 } catch (RemoteException e) { 1126 // Can't communicate with the phone process; ignore. 1127 } 1128 } 1129 }); 1130 } 1131 } 1132 } 1133