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(@ullable String subjectCode, @Nullable String reasonCode)330 public int encodeSmdxSubjectAndReasonCode(@Nullable String subjectCode, 331 @Nullable String reasonCode) 332 throws NumberFormatException, IllegalArgumentException, UnsupportedOperationException { 333 final int maxSupportedSection = 3; 334 final int maxSupportedDigit = 15; 335 final int bitsPerSection = 4; 336 337 if (TextUtils.isEmpty(subjectCode) || TextUtils.isEmpty(reasonCode)) { 338 throw new IllegalArgumentException("SubjectCode/ReasonCode is empty"); 339 } 340 341 final String[] subjectCodeToken = subjectCode.split("\\."); 342 final String[] reasonCodeToken = reasonCode.split("\\."); 343 344 if (subjectCodeToken.length > maxSupportedSection 345 || reasonCodeToken.length > maxSupportedSection) { 346 throw new UnsupportedOperationException("Only three nested layer is supported."); 347 } 348 349 int result = EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE; 350 351 // Pad the 0s needed for subject code 352 result = result << (maxSupportedSection - subjectCodeToken.length) * bitsPerSection; 353 354 for (String digitString : subjectCodeToken) { 355 int num = Integer.parseInt(digitString); 356 if (num > maxSupportedDigit) { 357 throw new UnsupportedOperationException("SubjectCode exceeds " + maxSupportedDigit); 358 } 359 result = (result << bitsPerSection) + num; 360 } 361 362 // Pad the 0s needed for reason code 363 result = result << (maxSupportedSection - reasonCodeToken.length) * bitsPerSection; 364 for (String digitString : reasonCodeToken) { 365 int num = Integer.parseInt(digitString); 366 if (num > maxSupportedDigit) { 367 throw new UnsupportedOperationException("ReasonCode exceeds " + maxSupportedDigit); 368 } 369 result = (result << bitsPerSection) + num; 370 } 371 372 return result; 373 } 374 375 @Override 376 @CallSuper onCreate()377 public void onCreate() { 378 super.onCreate(); 379 // We use a oneway AIDL interface to avoid blocking phone process binder threads on IPCs to 380 // an external process, but doing so means the requests are serialized by binder, which is 381 // not desired. Spin up a background thread pool to allow requests to be parallelized. 382 // TODO(b/38206971): Consider removing this if basic card-level functions like listing 383 // profiles are moved to the platform. 384 mExecutor = new ThreadPoolExecutor( 385 4 /* corePoolSize */, 386 4 /* maxPoolSize */, 387 30, TimeUnit.SECONDS, /* keepAliveTime */ 388 new LinkedBlockingQueue<>(), /* workQueue */ 389 new ThreadFactory() { 390 private final AtomicInteger mCount = new AtomicInteger(1); 391 392 @Override 393 public Thread newThread(Runnable r) { 394 return new Thread(r, "EuiccService #" + mCount.getAndIncrement()); 395 } 396 } 397 ); 398 mExecutor.allowCoreThreadTimeOut(true); 399 } 400 401 @Override 402 @CallSuper onDestroy()403 public void onDestroy() { 404 mExecutor.shutdownNow(); 405 super.onDestroy(); 406 } 407 408 /** 409 * If overriding this method, call through to the super method for any unknown actions. 410 * {@inheritDoc} 411 */ 412 @Override 413 @CallSuper onBind(Intent intent)414 public IBinder onBind(Intent intent) { 415 return mStubWrapper; 416 } 417 418 /** 419 * Callback class for {@link #onStartOtaIfNecessary(int, OtaStatusChangedCallback)} 420 * 421 * The status of OTA which can be {@code android.telephony.euicc.EuiccManager#EUICC_OTA_} 422 * 423 * @see IEuiccService#startOtaIfNecessary 424 */ 425 public abstract static class OtaStatusChangedCallback { 426 /** Called when OTA status is changed. */ onOtaStatusChanged(int status)427 public abstract void onOtaStatusChanged(int status); 428 } 429 430 /** 431 * Return the EID of the eUICC. 432 * 433 * @param slotId ID of the SIM slot being queried. 434 * @return the EID. 435 * @see android.telephony.euicc.EuiccManager#getEid 436 */ 437 // TODO(b/36260308): Update doc when we have multi-SIM support. onGetEid(int slotId)438 public abstract String onGetEid(int slotId); 439 440 /** 441 * Return the status of OTA update. 442 * 443 * @param slotId ID of the SIM slot to use for the operation. 444 * @return The status of Euicc OTA update. 445 * @see android.telephony.euicc.EuiccManager#getOtaStatus 446 */ onGetOtaStatus(int slotId)447 public abstract @OtaStatus int onGetOtaStatus(int slotId); 448 449 /** 450 * Perform OTA if current OS is not the latest one. 451 * 452 * @param slotId ID of the SIM slot to use for the operation. 453 * @param statusChangedCallback Function called when OTA status changed. 454 */ onStartOtaIfNecessary( int slotId, OtaStatusChangedCallback statusChangedCallback)455 public abstract void onStartOtaIfNecessary( 456 int slotId, OtaStatusChangedCallback statusChangedCallback); 457 458 /** 459 * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription. 460 * 461 * @param slotId ID of the SIM slot to use for the operation. 462 * @param subscription A subscription whose metadata needs to be populated. 463 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 464 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 465 * should be returned to allow the user to consent to this operation first. 466 * @return The result of the operation. 467 * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata 468 */ onGetDownloadableSubscriptionMetadata( int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim)469 public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata( 470 int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim); 471 472 /** 473 * Return metadata for subscriptions which are available for download for this device. 474 * 475 * @param slotId ID of the SIM slot to use for the operation. 476 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 477 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM)} 478 * should be returned to allow the user to consent to this operation first. 479 * @return The result of the list operation. 480 * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList 481 */ 482 public abstract GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim)483 onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim); 484 485 /** 486 * Download the given subscription. 487 * 488 * @param slotId ID of the SIM slot to use for the operation. 489 * @param subscription The subscription to download. 490 * @param switchAfterDownload If true, the subscription should be enabled upon successful 491 * download. 492 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 493 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 494 * should be returned to allow the user to consent to this operation first. 495 * @param resolvedBundle The bundle containing information on resolved errors. It can contain 496 * a string of confirmation code for the key {@link #EXTRA_RESOLUTION_CONFIRMATION_CODE}, 497 * and a boolean for key {@link #EXTRA_RESOLUTION_ALLOW_POLICY_RULES} indicating whether 498 * the user allows profile policy rules or not. 499 * @return a DownloadSubscriptionResult instance including a result code, a resolvable errors 500 * bit map, and original the card Id. The result code may be one of the predefined 501 * {@code RESULT_} constants or any implementation-specific code starting with 502 * {@link #RESULT_FIRST_USER}. The resolvable error bit map can be either 0 or values 503 * defined in {@code RESOLVABLE_ERROR_}. A subclass should override this method. Otherwise, 504 * this method does nothing and returns null by default. 505 * @see android.telephony.euicc.EuiccManager#downloadSubscription 506 */ onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, @Nullable Bundle resolvedBundle)507 public DownloadSubscriptionResult onDownloadSubscription(int slotId, 508 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 509 boolean forceDeactivateSim, @Nullable Bundle resolvedBundle) { 510 return null; 511 } 512 513 /** 514 * Download the given subscription. 515 * 516 * @param slotId ID of the SIM slot to use for the operation. 517 * @param subscription The subscription to download. 518 * @param switchAfterDownload If true, the subscription should be enabled upon successful 519 * download. 520 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 521 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 522 * should be returned to allow the user to consent to this operation first. 523 * @return the result of the download operation. May be one of the predefined {@code RESULT_} 524 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 525 * @see android.telephony.euicc.EuiccManager#downloadSubscription 526 * 527 * @deprecated From Q, a subclass should use and override the above 528 * {@link #onDownloadSubscription(int, DownloadableSubscription, boolean, boolean, Bundle)}. The 529 * default return value for this one is Integer.MIN_VALUE. 530 */ onDownloadSubscription(int slotId, @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim)531 @Deprecated public @Result int onDownloadSubscription(int slotId, 532 @NonNull DownloadableSubscription subscription, boolean switchAfterDownload, 533 boolean forceDeactivateSim) { 534 return Integer.MIN_VALUE; 535 } 536 537 /** 538 * Return a list of all @link EuiccProfileInfo}s. 539 * 540 * @param slotId ID of the SIM slot to use for the operation. 541 * @return The result of the operation. 542 * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList 543 * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList 544 */ onGetEuiccProfileInfoList(int slotId)545 public abstract @NonNull GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId); 546 547 /** 548 * Return info about the eUICC chip/device. 549 * 550 * @param slotId ID of the SIM slot to use for the operation. 551 * @return the {@link EuiccInfo} for the eUICC chip/device. 552 * @see android.telephony.euicc.EuiccManager#getEuiccInfo 553 */ onGetEuiccInfo(int slotId)554 public abstract @NonNull EuiccInfo onGetEuiccInfo(int slotId); 555 556 /** 557 * Delete the given subscription. 558 * 559 * <p>If the subscription is currently active, it should be deactivated first (equivalent to a 560 * physical SIM being ejected). 561 * 562 * @param slotId ID of the SIM slot to use for the operation. 563 * @param iccid the ICCID of the subscription to delete. 564 * @return the result of the delete operation. May be one of the predefined {@code RESULT_} 565 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 566 * @see android.telephony.euicc.EuiccManager#deleteSubscription 567 */ onDeleteSubscription(int slotId, String iccid)568 public abstract @Result int onDeleteSubscription(int slotId, String iccid); 569 570 /** 571 * Switch to the given subscription. 572 * 573 * @param slotId ID of the SIM slot to use for the operation. 574 * @param iccid the ICCID of the subscription to enable. May be null, in which case the current 575 * profile should be deactivated and no profile should be activated to replace it - this is 576 * equivalent to a physical SIM being ejected. 577 * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the 578 * eUICC, perform this action automatically. Otherwise, {@link #RESULT_MUST_DEACTIVATE_SIM} 579 * should be returned to allow the user to consent to this operation first. 580 * @return the result of the switch operation. May be one of the predefined {@code RESULT_} 581 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 582 * @see android.telephony.euicc.EuiccManager#switchToSubscription 583 */ onSwitchToSubscription(int slotId, @Nullable String iccid, boolean forceDeactivateSim)584 public abstract @Result int onSwitchToSubscription(int slotId, @Nullable String iccid, 585 boolean forceDeactivateSim); 586 587 /** 588 * Update the nickname of the given subscription. 589 * 590 * @param slotId ID of the SIM slot to use for the operation. 591 * @param iccid the ICCID of the subscription to update. 592 * @param nickname the new nickname to apply. 593 * @return the result of the update operation. May be one of the predefined {@code RESULT_} 594 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 595 * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname 596 */ onUpdateSubscriptionNickname(int slotId, String iccid, String nickname)597 public abstract int onUpdateSubscriptionNickname(int slotId, String iccid, 598 String nickname); 599 600 /** 601 * Erase all operational subscriptions on the device. 602 * 603 * <p>This is intended to be used for device resets. As such, the reset should be performed even 604 * if an active SIM must be deactivated in order to access the eUICC. 605 * 606 * @param slotId ID of the SIM slot to use for the operation. 607 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 608 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 609 * @see android.telephony.euicc.EuiccManager#eraseSubscriptions 610 * 611 * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase 612 * and use {@link #onEraseSubscriptions(int, int)} instead 613 */ 614 @Deprecated onEraseSubscriptions(int slotId)615 public abstract int onEraseSubscriptions(int slotId); 616 617 /** 618 * Erase specific subscriptions on the device. 619 * 620 * <p>This is intended to be used for device resets. As such, the reset should be performed even 621 * if an active SIM must be deactivated in order to access the eUICC. 622 * 623 * @param slotIndex index of the SIM slot to use for the operation. 624 * @param options flag for specific group of subscriptions to erase 625 * @return the result of the erase operation. May be one of the predefined {@code RESULT_} 626 * constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 627 * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions 628 */ onEraseSubscriptions(int slotIndex, @ResetOption int options)629 public int onEraseSubscriptions(int slotIndex, @ResetOption int options) { 630 throw new UnsupportedOperationException( 631 "This method must be overridden to enable the ResetOption parameter"); 632 } 633 634 /** 635 * Ensure that subscriptions will be retained on the next factory reset. 636 * 637 * <p>Called directly before a factory reset. Assumes that a normal factory reset will lead to 638 * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation 639 * should persist some bit that will remain accessible after the factory reset to bypass this 640 * flow when this method is called. 641 * 642 * @param slotId ID of the SIM slot to use for the operation. 643 * @return the result of the operation. May be one of the predefined {@code RESULT_} constants 644 * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. 645 */ onRetainSubscriptionsForFactoryReset(int slotId)646 public abstract int onRetainSubscriptionsForFactoryReset(int slotId); 647 648 /** 649 * Dump to a provided printWriter. 650 */ dump(@onNull PrintWriter printWriter)651 public void dump(@NonNull PrintWriter printWriter) { 652 printWriter.println("The connected LPA does not implement EuiccService#dump()"); 653 } 654 655 /** 656 * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. 657 */ 658 private class IEuiccServiceWrapper extends IEuiccService.Stub { 659 @Override downloadSubscription(int slotId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, IDownloadSubscriptionCallback callback)660 public void downloadSubscription(int slotId, DownloadableSubscription subscription, 661 boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, 662 IDownloadSubscriptionCallback callback) { 663 mExecutor.execute(new Runnable() { 664 @Override 665 public void run() { 666 DownloadSubscriptionResult result; 667 try { 668 result = 669 EuiccService.this.onDownloadSubscription( 670 slotId, subscription, switchAfterDownload, forceDeactivateSim, 671 resolvedBundle); 672 } catch (AbstractMethodError e) { 673 Log.w(TAG, "The new onDownloadSubscription(int, " 674 + "DownloadableSubscription, boolean, boolean, Bundle) is not " 675 + "implemented. Fall back to the old one.", e); 676 int resultCode = EuiccService.this.onDownloadSubscription( 677 slotId, subscription, switchAfterDownload, forceDeactivateSim); 678 result = new DownloadSubscriptionResult(resultCode, 679 0 /* resolvableErrors */, TelephonyManager.UNSUPPORTED_CARD_ID); 680 } 681 try { 682 callback.onComplete(result); 683 } catch (RemoteException e) { 684 // Can't communicate with the phone process; ignore. 685 } 686 } 687 }); 688 } 689 690 @Override getEid(int slotId, IGetEidCallback callback)691 public void getEid(int slotId, IGetEidCallback callback) { 692 mExecutor.execute(new Runnable() { 693 @Override 694 public void run() { 695 String eid = EuiccService.this.onGetEid(slotId); 696 try { 697 callback.onSuccess(eid); 698 } catch (RemoteException e) { 699 // Can't communicate with the phone process; ignore. 700 } 701 } 702 }); 703 } 704 705 @Override startOtaIfNecessary( int slotId, IOtaStatusChangedCallback statusChangedCallback)706 public void startOtaIfNecessary( 707 int slotId, IOtaStatusChangedCallback statusChangedCallback) { 708 mExecutor.execute(new Runnable() { 709 @Override 710 public void run() { 711 EuiccService.this.onStartOtaIfNecessary(slotId, new OtaStatusChangedCallback() { 712 @Override 713 public void onOtaStatusChanged(int status) { 714 try { 715 statusChangedCallback.onOtaStatusChanged(status); 716 } catch (RemoteException e) { 717 // Can't communicate with the phone process; ignore. 718 } 719 } 720 }); 721 } 722 }); 723 } 724 725 @Override getOtaStatus(int slotId, IGetOtaStatusCallback callback)726 public void getOtaStatus(int slotId, IGetOtaStatusCallback callback) { 727 mExecutor.execute(new Runnable() { 728 @Override 729 public void run() { 730 int status = EuiccService.this.onGetOtaStatus(slotId); 731 try { 732 callback.onSuccess(status); 733 } catch (RemoteException e) { 734 // Can't communicate with the phone process; ignore. 735 } 736 } 737 }); 738 } 739 740 @Override getDownloadableSubscriptionMetadata(int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim, IGetDownloadableSubscriptionMetadataCallback callback)741 public void getDownloadableSubscriptionMetadata(int slotId, 742 DownloadableSubscription subscription, 743 boolean forceDeactivateSim, 744 IGetDownloadableSubscriptionMetadataCallback callback) { 745 mExecutor.execute(new Runnable() { 746 @Override 747 public void run() { 748 GetDownloadableSubscriptionMetadataResult result = 749 EuiccService.this.onGetDownloadableSubscriptionMetadata( 750 slotId, subscription, forceDeactivateSim); 751 try { 752 callback.onComplete(result); 753 } catch (RemoteException e) { 754 // Can't communicate with the phone process; ignore. 755 } 756 } 757 }); 758 } 759 760 @Override getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, IGetDefaultDownloadableSubscriptionListCallback callback)761 public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim, 762 IGetDefaultDownloadableSubscriptionListCallback callback) { 763 mExecutor.execute(new Runnable() { 764 @Override 765 public void run() { 766 GetDefaultDownloadableSubscriptionListResult result = 767 EuiccService.this.onGetDefaultDownloadableSubscriptionList( 768 slotId, forceDeactivateSim); 769 try { 770 callback.onComplete(result); 771 } catch (RemoteException e) { 772 // Can't communicate with the phone process; ignore. 773 } 774 } 775 }); 776 } 777 778 @Override getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback)779 public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) { 780 mExecutor.execute(new Runnable() { 781 @Override 782 public void run() { 783 GetEuiccProfileInfoListResult result = 784 EuiccService.this.onGetEuiccProfileInfoList(slotId); 785 try { 786 callback.onComplete(result); 787 } catch (RemoteException e) { 788 // Can't communicate with the phone process; ignore. 789 } 790 } 791 }); 792 } 793 794 @Override getEuiccInfo(int slotId, IGetEuiccInfoCallback callback)795 public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) { 796 mExecutor.execute(new Runnable() { 797 @Override 798 public void run() { 799 EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId); 800 try { 801 callback.onSuccess(euiccInfo); 802 } catch (RemoteException e) { 803 // Can't communicate with the phone process; ignore. 804 } 805 } 806 }); 807 808 } 809 810 @Override deleteSubscription(int slotId, String iccid, IDeleteSubscriptionCallback callback)811 public void deleteSubscription(int slotId, String iccid, 812 IDeleteSubscriptionCallback callback) { 813 mExecutor.execute(new Runnable() { 814 @Override 815 public void run() { 816 int result = EuiccService.this.onDeleteSubscription(slotId, iccid); 817 try { 818 callback.onComplete(result); 819 } catch (RemoteException e) { 820 // Can't communicate with the phone process; ignore. 821 } 822 } 823 }); 824 } 825 826 @Override switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback)827 public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim, 828 ISwitchToSubscriptionCallback callback) { 829 mExecutor.execute(new Runnable() { 830 @Override 831 public void run() { 832 int result = 833 EuiccService.this.onSwitchToSubscription( 834 slotId, iccid, forceDeactivateSim); 835 try { 836 callback.onComplete(result); 837 } catch (RemoteException e) { 838 // Can't communicate with the phone process; ignore. 839 } 840 } 841 }); 842 } 843 844 @Override updateSubscriptionNickname(int slotId, String iccid, String nickname, IUpdateSubscriptionNicknameCallback callback)845 public void updateSubscriptionNickname(int slotId, String iccid, String nickname, 846 IUpdateSubscriptionNicknameCallback callback) { 847 mExecutor.execute(new Runnable() { 848 @Override 849 public void run() { 850 int result = 851 EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname); 852 try { 853 callback.onComplete(result); 854 } catch (RemoteException e) { 855 // Can't communicate with the phone process; ignore. 856 } 857 } 858 }); 859 } 860 861 @Override eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback)862 public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) { 863 mExecutor.execute(new Runnable() { 864 @Override 865 public void run() { 866 int result = EuiccService.this.onEraseSubscriptions(slotId); 867 try { 868 callback.onComplete(result); 869 } catch (RemoteException e) { 870 // Can't communicate with the phone process; ignore. 871 } 872 } 873 }); 874 } 875 876 @Override eraseSubscriptionsWithOptions( int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback)877 public void eraseSubscriptionsWithOptions( 878 int slotIndex, @ResetOption int options, IEraseSubscriptionsCallback callback) { 879 mExecutor.execute(new Runnable() { 880 @Override 881 public void run() { 882 int result = EuiccService.this.onEraseSubscriptions(slotIndex, options); 883 try { 884 callback.onComplete(result); 885 } catch (RemoteException e) { 886 // Can't communicate with the phone process; ignore. 887 } 888 } 889 }); 890 } 891 892 @Override retainSubscriptionsForFactoryReset(int slotId, IRetainSubscriptionsForFactoryResetCallback callback)893 public void retainSubscriptionsForFactoryReset(int slotId, 894 IRetainSubscriptionsForFactoryResetCallback callback) { 895 mExecutor.execute(new Runnable() { 896 @Override 897 public void run() { 898 int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); 899 try { 900 callback.onComplete(result); 901 } catch (RemoteException e) { 902 // Can't communicate with the phone process; ignore. 903 } 904 } 905 }); 906 } 907 908 @Override dump(IEuiccServiceDumpResultCallback callback)909 public void dump(IEuiccServiceDumpResultCallback callback) throws RemoteException { 910 mExecutor.execute(new Runnable() { 911 @Override 912 public void run() { 913 try { 914 final StringWriter sw = new StringWriter(); 915 final PrintWriter pw = new PrintWriter(sw); 916 EuiccService.this.dump(pw); 917 callback.onComplete(sw.toString()); 918 } catch (RemoteException e) { 919 // Can't communicate with the phone process; ignore. 920 } 921 } 922 }); 923 } 924 } 925 } 926