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 com.android.internal.telephony.euicc;
17 
18 import android.annotation.IntDef;
19 import android.annotation.Nullable;
20 import android.app.PendingIntent;
21 import android.os.Binder;
22 import android.os.Bundle;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.service.euicc.EuiccService;
26 import android.telephony.euicc.DownloadableSubscription;
27 import android.telephony.euicc.EuiccManager;
28 import android.text.TextUtils;
29 import android.util.Log;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * Representation of an {@link EuiccController} operation which failed with a resolvable error.
38  *
39  * <p>This class tracks the operation which failed and the reason for failure. Once the error is
40  * resolved, the operation can be resumed with {@link #continueOperation}.
41  */
42 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
43 public class EuiccOperation implements Parcelable {
44     private static final String TAG = "EuiccOperation";
45 
46     public static final Creator<EuiccOperation> CREATOR = new Creator<EuiccOperation>() {
47         @Override
48         public EuiccOperation createFromParcel(Parcel in) {
49             return new EuiccOperation(in);
50         }
51 
52         @Override
53         public EuiccOperation[] newArray(int size) {
54             return new EuiccOperation[size];
55         }
56     };
57 
58     @VisibleForTesting
59     @Retention(RetentionPolicy.SOURCE)
60     @IntDef({
61             ACTION_GET_METADATA_DEACTIVATE_SIM,
62             ACTION_DOWNLOAD_DEACTIVATE_SIM,
63             ACTION_DOWNLOAD_NO_PRIVILEGES,
64             ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM,
65             ACTION_SWITCH_DEACTIVATE_SIM,
66             ACTION_SWITCH_NO_PRIVILEGES,
67             ACTION_DOWNLOAD_RESOLVABLE_ERRORS,
68     })
69     @interface Action {}
70 
71     @VisibleForTesting
72     static final int ACTION_GET_METADATA_DEACTIVATE_SIM = 1;
73     @VisibleForTesting
74     static final int ACTION_DOWNLOAD_DEACTIVATE_SIM = 2;
75     @VisibleForTesting
76     static final int ACTION_DOWNLOAD_NO_PRIVILEGES = 3;
77     @VisibleForTesting
78     static final int ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM = 4;
79     @VisibleForTesting
80     static final int ACTION_SWITCH_DEACTIVATE_SIM = 5;
81     @VisibleForTesting
82     static final int ACTION_SWITCH_NO_PRIVILEGES = 6;
83     @VisibleForTesting
84     static final int ACTION_DOWNLOAD_RESOLVABLE_ERRORS = 7;
85     /**
86      * @deprecated Use ACTION_DOWNLOAD_RESOLVABLE_ERRORS and pass the resolvable errors in bit map.
87      */
88     @VisibleForTesting
89     @Deprecated
90     static final int ACTION_DOWNLOAD_CONFIRMATION_CODE = 8;
91     /**
92      * ACTION_DOWNLOAD_CHECK_METADATA can be used for either NO_PRIVILEGES or DEACTIVATE_SIM.
93      */
94     @VisibleForTesting
95     static final int ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA = 9;
96 
97     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
98     public final @Action int mAction;
99 
100     private final long mCallingToken;
101 
102     @Nullable
103     private final DownloadableSubscription mDownloadableSubscription;
104     private final int mSubscriptionId;
105     private final boolean mSwitchAfterDownload;
106     @Nullable
107     private final String mCallingPackage;
108     @Nullable
109     private final int mResolvableErrors;
110 
111     /**
112      * {@link EuiccManager#getDownloadableSubscriptionMetadata} failed with
113      * {@link EuiccService#RESULT_MUST_DEACTIVATE_SIM}.
114      */
forGetMetadataDeactivateSim(long callingToken, DownloadableSubscription subscription, String callingPackage)115     static EuiccOperation forGetMetadataDeactivateSim(long callingToken,
116             DownloadableSubscription subscription, String callingPackage) {
117         return new EuiccOperation(ACTION_GET_METADATA_DEACTIVATE_SIM, callingToken,
118                 subscription, 0 /* subscriptionId */, false /* switchAfterDownload */,
119                 callingPackage);
120     }
121 
122     /**
123      * {@link EuiccManager#downloadSubscription} failed with a mustDeactivateSim error. Should only
124      * be used for privileged callers; for unprivileged callers, use
125      * {@link #forDownloadNoPrivileges} to avoid a double prompt.
126      */
forDownloadDeactivateSim(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)127     static EuiccOperation forDownloadDeactivateSim(long callingToken,
128             DownloadableSubscription subscription, boolean switchAfterDownload,
129             String callingPackage) {
130         return new EuiccOperation(ACTION_DOWNLOAD_DEACTIVATE_SIM, callingToken,
131                 subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
132     }
133 
134     /**
135      * {@link EuiccManager#downloadSubscription} failed because the calling app does not have
136      * permission to manage the current active subscription.
137      */
forDownloadNoPrivileges(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)138     static EuiccOperation forDownloadNoPrivileges(long callingToken,
139             DownloadableSubscription subscription, boolean switchAfterDownload,
140             String callingPackage) {
141         return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES, callingToken,
142                 subscription,  0 /* subscriptionId */, switchAfterDownload, callingPackage);
143     }
144 
145     /**
146      * {@link EuiccManager#downloadSubscription} failed because the caller can't manage the target
147      * SIM, or we cannot determine the privileges without deactivating the current SIM first.
148      */
forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)149     static EuiccOperation forDownloadNoPrivilegesOrDeactivateSimCheckMetadata(long callingToken,
150             DownloadableSubscription subscription, boolean switchAfterDownload,
151             String callingPackage) {
152         return new EuiccOperation(ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA,
153                 callingToken, subscription,  0 /* subscriptionId */,
154                 switchAfterDownload, callingPackage);
155     }
156 
157     /**
158      * {@link EuiccManager#downloadSubscription} failed with
159      * {@link EuiccService#RESULT_NEED_CONFIRMATION_CODE} error.
160      *
161      * @deprecated Use
162      * {@link #forDownloadResolvableErrors(long, DownloadableSubscription, boolean, String, int)}
163      * instead.
164      */
165     @Deprecated
forDownloadConfirmationCode(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage)166     public static EuiccOperation forDownloadConfirmationCode(long callingToken,
167             DownloadableSubscription subscription, boolean switchAfterDownload,
168             String callingPackage) {
169         return new EuiccOperation(ACTION_DOWNLOAD_CONFIRMATION_CODE, callingToken,
170             subscription, 0 /* subscriptionId */, switchAfterDownload, callingPackage);
171     }
172 
173     /**
174      * {@link EuiccManager#downloadSubscription} failed with
175      * {@link EuiccService#RESULT_RESOLVABLE_ERRORS} error.
176      */
forDownloadResolvableErrors(long callingToken, DownloadableSubscription subscription, boolean switchAfterDownload, String callingPackage, int resolvableErrors)177     static EuiccOperation forDownloadResolvableErrors(long callingToken,
178             DownloadableSubscription subscription, boolean switchAfterDownload,
179             String callingPackage, int resolvableErrors) {
180         return new EuiccOperation(ACTION_DOWNLOAD_RESOLVABLE_ERRORS, callingToken,
181                 subscription, 0 /* subscriptionId */, switchAfterDownload,
182                 callingPackage, resolvableErrors);
183     }
184 
forGetDefaultListDeactivateSim(long callingToken, String callingPackage)185     static EuiccOperation forGetDefaultListDeactivateSim(long callingToken, String callingPackage) {
186         return new EuiccOperation(ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM, callingToken,
187                 null /* downloadableSubscription */, 0 /* subscriptionId */,
188                 false /* switchAfterDownload */, callingPackage);
189     }
190 
forSwitchDeactivateSim(long callingToken, int subscriptionId, String callingPackage)191     static EuiccOperation forSwitchDeactivateSim(long callingToken, int subscriptionId,
192             String callingPackage) {
193         return new EuiccOperation(ACTION_SWITCH_DEACTIVATE_SIM, callingToken,
194                 null /* downloadableSubscription */, subscriptionId,
195                 false /* switchAfterDownload */, callingPackage);
196     }
197 
forSwitchNoPrivileges(long callingToken, int subscriptionId, String callingPackage)198     static EuiccOperation forSwitchNoPrivileges(long callingToken, int subscriptionId,
199             String callingPackage) {
200         return new EuiccOperation(ACTION_SWITCH_NO_PRIVILEGES, callingToken,
201                 null /* downloadableSubscription */, subscriptionId,
202                 false /* switchAfterDownload */, callingPackage);
203     }
204 
EuiccOperation(@ction int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage, int resolvableErrors)205     EuiccOperation(@Action int action,
206             long callingToken,
207             @Nullable DownloadableSubscription downloadableSubscription,
208             int subscriptionId,
209             boolean switchAfterDownload,
210             String callingPackage,
211             int resolvableErrors) {
212         mAction = action;
213         mCallingToken = callingToken;
214         mDownloadableSubscription = downloadableSubscription;
215         mSubscriptionId = subscriptionId;
216         mSwitchAfterDownload = switchAfterDownload;
217         mCallingPackage = callingPackage;
218         mResolvableErrors = resolvableErrors;
219     }
220 
EuiccOperation(@ction int action, long callingToken, @Nullable DownloadableSubscription downloadableSubscription, int subscriptionId, boolean switchAfterDownload, String callingPackage)221     EuiccOperation(@Action int action,
222             long callingToken,
223             @Nullable DownloadableSubscription downloadableSubscription,
224             int subscriptionId,
225             boolean switchAfterDownload,
226             String callingPackage) {
227         mAction = action;
228         mCallingToken = callingToken;
229         mDownloadableSubscription = downloadableSubscription;
230         mSubscriptionId = subscriptionId;
231         mSwitchAfterDownload = switchAfterDownload;
232         mCallingPackage = callingPackage;
233         mResolvableErrors = 0;
234     }
235 
EuiccOperation(Parcel in)236     EuiccOperation(Parcel in) {
237         mAction = in.readInt();
238         mCallingToken = in.readLong();
239         mDownloadableSubscription = in.readTypedObject(DownloadableSubscription.CREATOR);
240         mSubscriptionId = in.readInt();
241         mSwitchAfterDownload = in.readBoolean();
242         mCallingPackage = in.readString();
243         mResolvableErrors = in.readInt();
244     }
245 
246     @Override
writeToParcel(Parcel dest, int flags)247     public void writeToParcel(Parcel dest, int flags) {
248         dest.writeInt(mAction);
249         dest.writeLong(mCallingToken);
250         dest.writeTypedObject(mDownloadableSubscription, flags);
251         dest.writeInt(mSubscriptionId);
252         dest.writeBoolean(mSwitchAfterDownload);
253         dest.writeString(mCallingPackage);
254         dest.writeInt(mResolvableErrors);
255     }
256 
257     /**
258      * Resume this operation based on the results of the resolution activity.
259      *
260      * @param resolutionExtras The resolution extras as provided to
261      *     {@link EuiccManager#continueOperation}.
262      * @param callbackIntent The callback intent to trigger after the operation completes.
263      */
continueOperation(int cardId, Bundle resolutionExtras, PendingIntent callbackIntent)264     public void continueOperation(int cardId, Bundle resolutionExtras,
265             PendingIntent callbackIntent) {
266         // Restore the identity of the caller. We should err on the side of caution and redo any
267         // permission checks before continuing with the operation in case the caller state has
268         // changed. Resolution flows can re-clear the identity if required.
269         Binder.restoreCallingIdentity(mCallingToken);
270 
271         switch (mAction) {
272             case ACTION_GET_METADATA_DEACTIVATE_SIM:
273                 resolvedGetMetadataDeactivateSim(cardId,
274                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
275                         callbackIntent);
276                 break;
277             case ACTION_DOWNLOAD_DEACTIVATE_SIM:
278                 resolvedDownloadDeactivateSim(cardId,
279                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
280                         callbackIntent);
281                 break;
282             case ACTION_DOWNLOAD_NO_PRIVILEGES:
283                 resolvedDownloadNoPrivileges(cardId,
284                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
285                         callbackIntent);
286                 break;
287             case ACTION_DOWNLOAD_NO_PRIVILEGES_OR_DEACTIVATE_SIM_CHECK_METADATA:
288                 resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(cardId,
289                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
290                         callbackIntent);
291                 break;
292             case ACTION_DOWNLOAD_CONFIRMATION_CODE: // Deprecated case
293                 resolvedDownloadConfirmationCode(cardId,
294                         resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE),
295                         callbackIntent);
296                 break;
297             case ACTION_DOWNLOAD_RESOLVABLE_ERRORS:
298                 resolvedDownloadResolvableErrors(cardId, resolutionExtras, callbackIntent);
299                 break;
300             case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM:
301                 resolvedGetDefaultListDeactivateSim(cardId,
302                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
303                         callbackIntent);
304                 break;
305             case ACTION_SWITCH_DEACTIVATE_SIM:
306                 resolvedSwitchDeactivateSim(cardId,
307                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
308                         callbackIntent);
309                 break;
310             case ACTION_SWITCH_NO_PRIVILEGES:
311                 resolvedSwitchNoPrivileges(cardId,
312                         resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT),
313                         callbackIntent);
314                 break;
315             default:
316                 Log.wtf(TAG, "Unknown action: " + mAction);
317                 break;
318         }
319     }
320 
resolvedGetMetadataDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)321     private void resolvedGetMetadataDeactivateSim(int cardId, boolean consent,
322             PendingIntent callbackIntent) {
323         if (consent) {
324             // User has consented; perform the lookup, but this time, tell the LPA to deactivate any
325             // required active SIMs.
326             EuiccController.get().getDownloadableSubscriptionMetadata(
327                     cardId,
328                     mDownloadableSubscription,
329                     true /* forceDeactivateSim */,
330                     mCallingPackage,
331                     callbackIntent);
332         } else {
333             // User has not consented; fail the operation.
334             fail(callbackIntent);
335         }
336     }
337 
resolvedDownloadDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)338     private void resolvedDownloadDeactivateSim(int cardId, boolean consent,
339             PendingIntent callbackIntent) {
340         if (consent) {
341             // User has consented; perform the download, but this time, tell the LPA to deactivate
342             // any required active SIMs.
343             EuiccController.get().downloadSubscription(
344                     cardId,
345                     mDownloadableSubscription,
346                     mSwitchAfterDownload,
347                     mCallingPackage,
348                     true /* forceDeactivateSim */,
349                     null /* resolvedBundle */,
350                     callbackIntent);
351         } else {
352             // User has not consented; fail the operation.
353             fail(callbackIntent);
354         }
355     }
356 
resolvedDownloadNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent)357     private void resolvedDownloadNoPrivileges(int cardId, boolean consent,
358             PendingIntent callbackIntent) {
359         if (consent) {
360             // User has consented; perform the download with full privileges.
361             long token = Binder.clearCallingIdentity();
362             try {
363                 // Note: We turn on "forceDeactivateSim" here under the assumption that the
364                 // privilege prompt should also cover permission to deactivate an active SIM, as
365                 // the privilege prompt makes it clear that we're switching from the current
366                 // carrier.
367                 EuiccController.get().downloadSubscriptionPrivileged(
368                         cardId,
369                         token,
370                         mDownloadableSubscription,
371                         mSwitchAfterDownload,
372                         true /* forceDeactivateSim */,
373                         mCallingPackage,
374                         null /* resolvedBundle */,
375                         callbackIntent);
376             } finally {
377                 Binder.restoreCallingIdentity(token);
378             }
379         } else {
380             // User has not consented; fail the operation.
381             fail(callbackIntent);
382         }
383     }
384 
resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(int cardId, boolean consent, PendingIntent callbackIntent)385     private void resolvedDownloadNoPrivilegesOrDeactivateSimCheckMetadata(int cardId,
386             boolean consent, PendingIntent callbackIntent) {
387         if (consent) {
388             // User has consented; perform the download with full privileges.
389             long token = Binder.clearCallingIdentity();
390             try {
391                 // Note: We turn on "forceDeactivateSim" here under the assumption that the
392                 // privilege prompt should also cover permission to deactivate an active SIM, as
393                 // the privilege prompt makes it clear that we're switching from the current
394                 // carrier.
395                 EuiccController.get().downloadSubscriptionPrivilegedCheckMetadata(
396                         cardId,
397                         token,
398                         mDownloadableSubscription,
399                         mSwitchAfterDownload,
400                         true /* forceDeactivateSim */,
401                         mCallingPackage,
402                         null /* resolvedBundle */,
403                         callbackIntent);
404             } finally {
405                 Binder.restoreCallingIdentity(token);
406             }
407         } else {
408             // User has not consented; fail the operation.
409             fail(callbackIntent);
410         }
411     }
412 
413     /**
414      * @deprecated The resolvable errors in download step are solved by
415      * {@link #resolvedDownloadResolvableErrors(Bundle, PendingIntent)} from Q.
416      */
417     @Deprecated
resolvedDownloadConfirmationCode(int cardId, String confirmationCode, PendingIntent callbackIntent)418     private void resolvedDownloadConfirmationCode(int cardId, String confirmationCode,
419             PendingIntent callbackIntent) {
420         if (TextUtils.isEmpty(confirmationCode)) {
421             fail(callbackIntent);
422         } else {
423             mDownloadableSubscription.setConfirmationCode(confirmationCode);
424             EuiccController.get().downloadSubscription(
425                     cardId,
426                     mDownloadableSubscription,
427                     mSwitchAfterDownload,
428                     mCallingPackage,
429                     true /* forceDeactivateSim */,
430                     null,
431                     callbackIntent);
432         }
433     }
434 
resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, PendingIntent callbackIntent)435     private void resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle,
436             PendingIntent callbackIntent) {
437         boolean pass = true;
438         String confirmationCode = null;
439         if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_POLICY_RULES) != 0) {
440             if (!resolvedBundle.getBoolean(EuiccService.EXTRA_RESOLUTION_ALLOW_POLICY_RULES)) {
441                 pass = false;
442             }
443         }
444         if ((mResolvableErrors & EuiccService.RESOLVABLE_ERROR_CONFIRMATION_CODE) != 0) {
445             confirmationCode = resolvedBundle.getString(
446                 EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE);
447             // The check here just makes sure the entered confirmation code is non-empty. The actual
448             // check to valid the confirmation code is done by LPA on the ensuing download attemp.
449             if (TextUtils.isEmpty(confirmationCode)) {
450                 pass = false;
451             }
452         }
453 
454         if (!pass) {
455             fail(callbackIntent);
456         } else {
457             mDownloadableSubscription.setConfirmationCode(confirmationCode);
458             EuiccController.get().downloadSubscription(
459                     cardId,
460                     mDownloadableSubscription,
461                     mSwitchAfterDownload,
462                     mCallingPackage,
463                     true /* forceDeactivateSim */,
464                     resolvedBundle,
465                     callbackIntent);
466         }
467     }
468 
resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)469     private void resolvedGetDefaultListDeactivateSim(int cardId, boolean consent,
470             PendingIntent callbackIntent) {
471         if (consent) {
472             // User has consented; perform the lookup, but this time, tell the LPA to deactivate any
473             // required active SIMs.
474             EuiccController.get().getDefaultDownloadableSubscriptionList(
475                     cardId,
476                     true /* forceDeactivateSim */,
477                     mCallingPackage,
478                     callbackIntent);
479         } else {
480             // User has not consented; fail the operation.
481             fail(callbackIntent);
482         }
483     }
484 
resolvedSwitchDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent)485     private void resolvedSwitchDeactivateSim(int cardId, boolean consent,
486             PendingIntent callbackIntent) {
487         if (consent) {
488             // User has consented; perform the switch, but this time, tell the LPA to deactivate any
489             // required active SIMs.
490             EuiccController.get().switchToSubscription(
491                     cardId,
492                     mSubscriptionId,
493                     true /* forceDeactivateSim */,
494                     mCallingPackage,
495                     callbackIntent);
496         } else {
497             // User has not consented; fail the operation.
498             fail(callbackIntent);
499         }
500     }
501 
resolvedSwitchNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent)502     private void resolvedSwitchNoPrivileges(int cardId, boolean consent,
503             PendingIntent callbackIntent) {
504         if (consent) {
505             // User has consented; perform the switch with full privileges.
506             long token = Binder.clearCallingIdentity();
507             try {
508                 // Note: We turn on "forceDeactivateSim" here under the assumption that the
509                 // privilege prompt should also cover permission to deactivate an active SIM, as
510                 // the privilege prompt makes it clear that we're switching from the current
511                 // carrier. Also note that in practice, we'd need to deactivate the active SIM to
512                 // even reach this point, because we cannot fetch the metadata needed to check the
513                 // privileges without doing so.
514                 EuiccController.get().switchToSubscriptionPrivileged(
515                         cardId,
516                         token,
517                         mSubscriptionId,
518                         true /* forceDeactivateSim */,
519                         mCallingPackage,
520                         callbackIntent);
521             } finally {
522                 Binder.restoreCallingIdentity(token);
523             }
524         } else {
525             // User has not consented; fail the operation.
526             fail(callbackIntent);
527         }
528     }
529 
fail(PendingIntent callbackIntent)530     private static void fail(PendingIntent callbackIntent) {
531         EuiccController.get().sendResult(
532                 callbackIntent,
533                 EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
534                 null /* extrasIntent */);
535     }
536 
537     @Override
describeContents()538     public int describeContents() {
539         return 0;
540     }
541 }
542