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