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