• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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