EuiccController.java revision 8bf20cb416675744e28821f509a20ae2813ad44e
1277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/*
2277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Copyright (C) 2017 The Android Open Source Project
3277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson *
4277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Licensed under the Apache License, Version 2.0 (the "License");
5277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * you may not use this file except in compliance with the License.
6277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * You may obtain a copy of the License at
7277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson *
8277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson *      http://www.apache.org/licenses/LICENSE-2.0
9277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson *
10277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Unless required by applicable law or agreed to in writing, software
11277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * distributed under the License is distributed on an "AS IS" BASIS,
12277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * See the License for the specific language governing permissions and
14277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * limitations under the License.
15277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson */
16277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpackage com.android.internal.telephony.euicc;
17277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
18ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Liimport static android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE;
19ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
20277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.Manifest;
2196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Liimport android.Manifest.permission;
22277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.annotation.Nullable;
2308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.app.AppOpsManager;
24277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.app.PendingIntent;
25277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Context;
26277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Intent;
2708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.content.pm.PackageInfo;
28277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.pm.PackageManager;
29277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.Binder;
30953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.os.Bundle;
31277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.ServiceManager;
324f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidsonimport android.provider.Settings;
33953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.service.euicc.EuiccService;
348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
35277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.service.euicc.GetDownloadableSubscriptionMetadataResult;
36dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.service.euicc.GetEuiccProfileInfoListResult;
37dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionInfo;
38dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionManager;
39277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.TelephonyManager;
4008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.telephony.UiccAccessRule;
41277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.DownloadableSubscription;
428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.telephony.euicc.EuiccInfo;
43277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.EuiccManager;
44ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Liimport android.telephony.euicc.EuiccManager.OtaStatus;
45f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sunimport android.text.TextUtils;
46277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.util.Log;
47277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
48277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport com.android.internal.annotations.VisibleForTesting;
49dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport com.android.internal.telephony.SubscriptionController;
5096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Liimport com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
51277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
52277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.FileDescriptor;
53277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.PrintWriter;
54dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport java.util.List;
55277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.CountDownLatch;
56277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.atomic.AtomicReference;
57277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
58277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
59277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpublic class EuiccController extends IEuiccController.Stub {
60277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static final String TAG = "EuiccController";
61277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
62953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Extra set on resolution intents containing the {@link EuiccOperation}. */
63953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting
64953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    static final String EXTRA_OPERATION = "operation";
65953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
6608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    // Aliases so line lengths stay short.
6708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK;
6808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int RESOLVABLE_ERROR =
6908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR;
7031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson    private static final int ERROR =
7131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
728bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun    private static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
738bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION;
7408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
75277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static EuiccController sInstance;
76277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
77277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final Context mContext;
78277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final EuiccConnector mConnector;
79dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    private final SubscriptionManager mSubscriptionManager;
8008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final AppOpsManager mAppOpsManager;
8108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final PackageManager mPackageManager;
82277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
83277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Initialize the instance. Should only be called once. */
84277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController init(Context context) {
85277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        synchronized (EuiccController.class) {
86277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            if (sInstance == null) {
87277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                sInstance = new EuiccController(context);
88277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            } else {
89277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
90277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
91277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
92277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
93277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
94277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
95277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Get an instance. Assumes one has already been initialized with {@link #init}. */
96277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController get() {
97277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (sInstance == null) {
98277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            synchronized (EuiccController.class) {
99277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                if (sInstance == null) {
100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    throw new IllegalStateException("get() called before init()");
101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                }
102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
107277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private EuiccController(Context context) {
108277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        this(context, new EuiccConnector(context));
109277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        ServiceManager.addService("econtroller", this);
110277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
111277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
112277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @VisibleForTesting
113277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public EuiccController(Context context, EuiccConnector connector) {
114277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext = context;
115277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector = connector;
116dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mSubscriptionManager = (SubscriptionManager)
117dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
11808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
11908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mPackageManager = context.getPackageManager();
120277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
121277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
122277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
123953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * Continue an operation which failed with a user-resolvable error.
124953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     *
125953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <p>The implementation here makes a key assumption that the resolutionIntent has not been
126953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * tampered with. This is guaranteed because:
127953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <UL>
128953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created
129953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be
130953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * overridden on the PendingIntent - a caller can only add new extras.
131953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps
132953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * cannot start it directly. So the PendingIntent is the only way to start it.
133953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * </UL>
134953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     */
135953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @Override
136953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
137953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
138953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            throw new SecurityException(
139953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation");
140953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
141953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        long token = Binder.clearCallingIdentity();
142953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        try {
143953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION);
144953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            if (op == null) {
145953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                throw new IllegalArgumentException("Invalid resolution intent");
146953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            }
147953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
148953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent =
149953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    resolutionIntent.getParcelableExtra(
150953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
151953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            op.continueOperation(resolutionExtras, callbackIntent);
152953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        } finally {
153953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            Binder.restoreCallingIdentity(token);
154953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
155953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
156953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
157953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /**
158277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Return the EID.
159277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     *
160277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
161277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of
162277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * operation.
163277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
164277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
165277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public String getEid() {
166277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanReadPhoneStatePrivileged()
167277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                && !callerHasCarrierPrivilegesForActiveSubscription()) {
168277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException(
169277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    "Must have carrier privileges on active subscription to read EID");
170277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
171277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
172277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
173277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            return blockingGetEidFromEuiccService();
174277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
175277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
176277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
177277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
178277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
179ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    /**
180ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * Return the current status of OTA update.
181ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     *
182ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
183ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * that IPC should generally be fast.
184ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     */
185ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    @Override
186ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    public @OtaStatus int getOtaStatus() {
187ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        if (!callerCanWriteEmbeddedSubscriptions()) {
188ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status");
189ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        }
190ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        long token = Binder.clearCallingIdentity();
191ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        try {
192ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            return blockingGetOtaStatusFromEuiccService();
193ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        } finally {
194ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            Binder.restoreCallingIdentity(token);
195ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        }
196ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    }
197ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
19896d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
19996d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    /**
20096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * Start eUICC OTA update if current eUICC OS is not the latest one. When OTA is started or
20196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * finished, the broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} will be sent.
20296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     *
20396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * This function will only be called from phone process and isn't exposed to the other apps.
20496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     */
20596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    public void startOtaUpdatingIfNecessary() {
20696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        mConnector.startOtaIfNecessary(
20796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                new OtaStatusChangedCallback() {
20896d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    @Override
20996d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    public void onOtaStatusChanged(int status) {
21096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                        sendOtaStatusChangedBroadcast();
21196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    }
21296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
21396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    @Override
21496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    public void onEuiccServiceUnavailable() {}
21596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                });
21696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    }
21796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
218277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
219277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
2209af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
221953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        getDownloadableSubscriptionMetadata(
2229af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
223953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
224953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
225953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
2269af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
227277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
228277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata");
229277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
2309af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
231277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
232277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
23308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(
234953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    subscription, forceDeactivateSim,
2359af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    new GetMetadataCommandCallback(
2369af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, subscription, callingPackage, callbackIntent));
237277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
238277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
239277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
240277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
241277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
24208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback {
243953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final long mCallingToken;
244953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final DownloadableSubscription mSubscription;
2459af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        protected final String mCallingPackage;
24608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        protected final PendingIntent mCallbackIntent;
24708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
248953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        GetMetadataCommandCallback(
249953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                long callingToken,
250953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription,
2519af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                String callingPackage,
252953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
253953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mCallingToken = callingToken;
254953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mSubscription = subscription;
2559af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
25608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mCallbackIntent = callbackIntent;
25708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
25808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
25908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
26008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
26108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
26208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Intent extrasIntent = new Intent();
26308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final int resultCode;
264d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            switch (result.getResult()) {
26531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
26608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = OK;
26708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
2688bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                            EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
269d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getDownloadableSubscription());
27008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
27131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
27208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = RESOLVABLE_ERROR;
273953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    addResolutionIntent(extrasIntent,
274953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
2759af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
276f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
277953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            getOperationForDeactivateSim());
27808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
27931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
28031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
28108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
28208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
283d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getResult());
28408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
28508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
28608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
28708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
28808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
28908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
29008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
29108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onEuiccServiceUnavailable() {
29231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
29308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
294953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
295953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
2969af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            return EuiccOperation.forGetMetadataDeactivateSim(
2979af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    mCallingToken, mSubscription, mCallingPackage);
298953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
29908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
30008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
301277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
302277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void downloadSubscription(DownloadableSubscription subscription,
30308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) {
304953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        downloadSubscription(subscription, switchAfterDownload, callingPackage,
305953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                false /* forceDeactivateSim */, callbackIntent);
306953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
307953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
308953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscription(DownloadableSubscription subscription,
309953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
310953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent) {
31108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
31208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
31308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
314277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
315277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
31608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (callerCanWriteEmbeddedSubscriptions) {
31708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
31808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // and move straight to the profile download.
319953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                downloadSubscriptionPrivileged(token, subscription, switchAfterDownload,
320953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                        forceDeactivateSim, callingPackage, callbackIntent);
32108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
32208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
32308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the
32408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // metadata of the profile to be downloaded, so check the metadata first.
32508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(subscription,
326953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    forceDeactivateSim,
327953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
328953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            switchAfterDownload, callingPackage, forceDeactivateSim,
329953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            callbackIntent));
330277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
331277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
332277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
333277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
334277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
33508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
33608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        private final boolean mSwitchAfterDownload;
337953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        private final boolean mForceDeactivateSim;
33808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
339953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
340953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription, boolean switchAfterDownload,
341953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                String callingPackage, boolean forceDeactivateSim,
342953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
3439af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            super(callingToken, subscription, callingPackage, callbackIntent);
34408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mSwitchAfterDownload = switchAfterDownload;
345953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mForceDeactivateSim = forceDeactivateSim;
34608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
34708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
34808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
34908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
35008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
351d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
3529af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // If we need to deactivate the current SIM to even check permissions, go ahead and
3539af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // require that the user resolve the stronger permission dialog.
3549af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                Intent extrasIntent = new Intent();
3559af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
3569af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        mCallingPackage,
357f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                        false /* confirmationCodeRetried */,
3589af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        EuiccOperation.forDownloadNoPrivileges(
3599af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingToken, mSubscription, mSwitchAfterDownload,
3609af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingPackage));
3619af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
3629af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                return;
3639af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            }
3649af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson
365d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (result.getResult() != EuiccService.RESULT_OK) {
36608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // Just propagate the error as normal.
36708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                super.onGetMetadataComplete(result);
36808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
36908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
37008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
371d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            DownloadableSubscription subscription = result.getDownloadableSubscription();
372d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            UiccAccessRule[] rules = null;
373d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            List<UiccAccessRule> rulesList = subscription.getAccessRules();
374d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (rulesList != null) {
375d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
376d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            }
37708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (rules == null) {
37808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "No access rules but caller is unprivileged");
37931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
38008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
38108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
38208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
38308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final PackageInfo info;
38408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            try {
38508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                info = mPackageManager.getPackageInfo(
38608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        mCallingPackage, PackageManager.GET_SIGNATURES);
38708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            } catch (PackageManager.NameNotFoundException e) {
38808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "Calling package valid but gone");
38931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
39008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
39108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
39208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
39308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            for (int i = 0; i < rules.length; i++) {
39408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                if (rules[i].getCarrierPrivilegeStatus(info)
39508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
396dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Caller can download this profile. Now, determine whether the caller can also
397dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // manage the current profile; if so, we can perform the download silently; if
398dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // not, the user must provide consent.
3998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    if (canManageActiveSubscription(mCallingPackage)) {
4008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        downloadSubscriptionPrivileged(
4018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mCallingToken, subscription, mSwitchAfterDownload,
4028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mForceDeactivateSim, mCallingPackage, mCallbackIntent);
4038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        return;
40408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
405dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
406dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Switch might still be permitted, but the user must consent first.
407dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    Intent extrasIntent = new Intent();
408dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
4099af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
410f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
411dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                            EuiccOperation.forDownloadNoPrivileges(
4128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingToken, subscription, mSwitchAfterDownload,
4138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingPackage));
414dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
41508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    return;
41608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                }
41708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
41808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Log.e(TAG, "Caller is not permitted to download this profile");
41931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
42008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
421953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
422953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        @Override
423953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
424953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            return EuiccOperation.forDownloadDeactivateSim(
425953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage);
426953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
42708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
42808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
429953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscriptionPrivileged(final long callingToken,
430953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            DownloadableSubscription subscription, boolean switchAfterDownload,
431953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
432953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            final PendingIntent callbackIntent) {
433953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        mConnector.downloadSubscription(
434953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                subscription,
435953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                switchAfterDownload,
436953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                forceDeactivateSim,
43708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                new EuiccConnector.DownloadCommandCallback() {
43808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
43931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDownloadComplete(int result) {
44008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        Intent extrasIntent = new Intent();
44108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        final int resultCode;
44231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
44331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
44408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = OK;
4454f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // Now that a profile has been successfully downloaded, mark the
4464f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // eUICC as provisioned so it appears in settings UI as appropriate.
4474f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                Settings.Global.putInt(
4484f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        mContext.getContentResolver(),
4494f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        Settings.Global.EUICC_PROVISIONED,
4504f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        1);
4518bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                extrasIntent.putExtra(
4528bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                        EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
4538bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                        subscription);
454dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                if (!switchAfterDownload) {
455dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // Since we're not switching, nothing will trigger a
456dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // subscription list refresh on its own, so request one here.
457d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    refreshSubscriptionsAndSendResult(
458d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                            callbackIntent, resultCode, extrasIntent);
459d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    return;
460dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                }
46108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
46231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
46308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = RESOLVABLE_ERROR;
464953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                addResolutionIntent(extrasIntent,
465953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
4669af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
467f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        false /* confirmationCodeRetried */,
468953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccOperation.forDownloadDeactivateSim(
469953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingToken, subscription, switchAfterDownload,
470953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingPackage));
47108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
47280fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                            case EuiccService.RESULT_NEED_CONFIRMATION_CODE:
47380fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                resultCode = RESOLVABLE_ERROR;
474f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                boolean retried = false;
475f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                if (!TextUtils.isEmpty(subscription.getConfirmationCode())) {
476f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                    retried = true;
477f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                }
47880fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                addResolutionIntent(extrasIntent,
47980fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE,
48080fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        callingPackage,
481f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        retried /* confirmationCodeRetried */,
48280fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        EuiccOperation.forDownloadConfirmationCode(
48380fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                                callingToken, subscription, switchAfterDownload,
48480fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                                callingPackage));
48580fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                break;
48631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
48731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
48808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                extrasIntent.putExtra(
48908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
49031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
49108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
49208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        }
49308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
49408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
49508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
49608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
49708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
49808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    public void onEuiccServiceUnavailable() {
49931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
50008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
50108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                });
50208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
50308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
504dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    /**
505dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList}.
506dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     *
507dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * <p>Does not perform permission checks as this is not an exposed API and is only used within
508dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * the phone process.
509dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     */
510dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList() {
511dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final CountDownLatch latch = new CountDownLatch(1);
512dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>();
513dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mConnector.getEuiccProfileInfoList(
514dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                new EuiccConnector.GetEuiccProfileInfoListCommandCallback() {
515dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
516dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onListComplete(GetEuiccProfileInfoListResult result) {
517dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        resultRef.set(result);
518dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
519dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
520dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
521dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
522dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onEuiccServiceUnavailable() {
523dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
524dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
525dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                });
526dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        try {
527dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            latch.await();
528dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        } catch (InterruptedException e) {
529dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            Thread.currentThread().interrupt();
530dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        }
531dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        return resultRef.get();
532dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    }
533dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
5348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
5359af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson    public void getDefaultDownloadableSubscriptionList(
5369af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
5379af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        getDefaultDownloadableSubscriptionList(
5389af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                false /* forceDeactivateSim */, callingPackage, callbackIntent);
5398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void getDefaultDownloadableSubscriptionList(
5429af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
5438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
5448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
5458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list");
5468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5479af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
5488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
5498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
5508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.getDefaultDownloadableSubscriptionList(
5519af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    forceDeactivateSim, new GetDefaultListCommandCallback(
5529af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, callingPackage, callbackIntent));
5538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
5548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
5558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback {
5599af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final long mCallingToken;
5609af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final String mCallingPackage;
5619af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final PendingIntent mCallbackIntent;
5628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5639af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        GetDefaultListCommandCallback(long callingToken, String callingPackage,
5649af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                PendingIntent callbackIntent) {
5658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallingToken = callingToken;
5669af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
5678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallbackIntent = callbackIntent;
5688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
5718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result) {
5728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Intent extrasIntent = new Intent();
5738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final int resultCode;
574d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            switch (result.getResult()) {
57531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
5768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = OK;
577d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    List<DownloadableSubscription> list = result.getDownloadableSubscriptions();
578d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    if (list != null && list.size() > 0) {
579d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                        extrasIntent.putExtra(
580d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS,
581d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                                list.toArray(new DownloadableSubscription[list.size()]));
582d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    }
5838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
58431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
5858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = RESOLVABLE_ERROR;
5868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    addResolutionIntent(extrasIntent,
5878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
5889af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
589f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
5909af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            EuiccOperation.forGetDefaultListDeactivateSim(
5919af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                    mCallingToken, mCallingPackage));
5928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
59331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
59431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
5958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    extrasIntent.putExtra(
5968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
597d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getResult());
5988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
5998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
6028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
6058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onEuiccServiceUnavailable() {
60631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
6078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    /**
6118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * Return the {@link EuiccInfo}.
6128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     *
6138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
6148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * that IPC should generally be fast, and this info shouldn't be needed in the normal course of
6158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * operation.
6168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     */
6178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public EuiccInfo getEuiccInfo() {
6198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // No permissions required as EuiccInfo is not sensitive.
6208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
6218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
6228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            return blockingGetEuiccInfoFromEuiccService();
6238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
6248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
6258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void deleteSubscription(int subscriptionId, String callingPackage,
6308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
6328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
6338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
6358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
6368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
6378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
6388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId);
63931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
6418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
6448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !sub.canManageSubscription(mContext, callingPackage)) {
6458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "No permissions: " + subscriptionId);
64631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
6488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            deleteSubscriptionPrivileged(sub.getIccId(), callbackIntent);
6518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
6528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
6538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent) {
6578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.deleteSubscription(
6588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
6598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.DeleteCommandCallback() {
6608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
66131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDeleteComplete(int result) {
6628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
6638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
66431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
66531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
6668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
667d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                refreshSubscriptionsAndSendResult(
668d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                        callbackIntent, resultCode, extrasIntent);
669d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                return;
67031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
67131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
6728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
6738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
67431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
6758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
6768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
6778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
6798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
6828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
68331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
6868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void switchToSubscription(int subscriptionId, String callingPackage,
6908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscription(
6928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent);
6938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage,
6968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
6988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
6998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
7018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
7022938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson            if (callerCanWriteEmbeddedSubscriptions) {
7032938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // Assume that if a privileged caller is calling us, we don't need to prompt the
7042938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // user about changing carriers, because the caller would only be acting in response
7052938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // to user action.
7062938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                forceDeactivateSim = true;
7072938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson            }
7082938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson
7098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final String iccid;
7108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
7118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch to "no" subscription. Only the system can do this.
7128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions) {
7138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to empty subscription");
71431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = null;
7188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            } else {
7198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
7208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (sub == null) {
7218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Cannot switch to nonexistent subscription: " + subscriptionId);
72231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions
726d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                        && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
7278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to subscription: " + subscriptionId);
72831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = sub.getIccId();
7328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
7338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
7358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !canManageActiveSubscription(callingPackage)) {
7368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch needs consent.
7378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Intent extrasIntent = new Intent();
7388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                addResolutionIntent(extrasIntent,
7398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
7409af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        callingPackage,
741f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                        false /* confirmationCodeRetried */,
7428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccOperation.forSwitchNoPrivileges(
7438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                token, subscriptionId, callingPackage));
7448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
7458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
7468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
7478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            switchToSubscriptionPrivileged(token, subscriptionId, iccid, forceDeactivateSim,
7498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    callingPackage, callbackIntent);
7508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
7518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
7528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
7568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
7578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
7588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        String iccid = null;
7598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
7608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (sub != null) {
7618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            iccid = sub.getIccId();
7628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscriptionPrivileged(callingToken, subscriptionId, iccid, forceDeactivateSim,
7648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                callingPackage, callbackIntent);
7658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
7688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage,
7698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
7708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.switchToSubscription(
7718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
7728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                forceDeactivateSim,
7738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.SwitchCommandCallback() {
7748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
77531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onSwitchComplete(int result) {
7768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
7778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
77831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
77931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
7808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
7818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
78231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
7838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = RESOLVABLE_ERROR;
7848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                addResolutionIntent(extrasIntent,
7858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
7869af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
787f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        false /* confirmationCodeRetried */,
7888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccOperation.forSwitchDeactivateSim(
7898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                                callingToken, subscriptionId, callingPackage));
7908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
79131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
79231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
7938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
7948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
79531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
7968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
7978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
7988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
8008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
8038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
80431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
8078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
8108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void updateSubscriptionNickname(int subscriptionId, String nickname,
8118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
8128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
8138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
8148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to update nickname");
8158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
8178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
8188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
8198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
8208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot update nickname to nonexistent subscription: " + subscriptionId);
82131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
8238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
8248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.updateSubscriptionNickname(
8258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sub.getIccId(), nickname,
8268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    new EuiccConnector.UpdateNicknameCommandCallback() {
8278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
82831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        public void onUpdateNicknameComplete(int result) {
8298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            Intent extrasIntent = new Intent();
8308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            final int resultCode;
83131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            switch (result) {
83231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                case EuiccService.RESULT_OK:
8338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    resultCode = OK;
8348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
83531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                default:
83631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    resultCode = ERROR;
8378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    extrasIntent.putExtra(
8388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
83931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                            result);
8408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
8418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            }
8428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            sendResult(callbackIntent, resultCode, extrasIntent);
8448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
8458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
8478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        public void onEuiccServiceUnavailable() {
84831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
8508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    });
8518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
8528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
8538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
8578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void eraseSubscriptions(PendingIntent callbackIntent) {
8588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
8598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
8608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
8618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
8638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
8648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.eraseSubscriptions(new EuiccConnector.EraseCommandCallback() {
8658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
86631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                public void onEraseComplete(int result) {
8678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Intent extrasIntent = new Intent();
8688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    final int resultCode;
86931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    switch (result) {
87031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        case EuiccService.RESULT_OK:
8718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            resultCode = OK;
872d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                            refreshSubscriptionsAndSendResult(
873d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    callbackIntent, resultCode, extrasIntent);
874d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                            return;
87531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        default:
87631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            resultCode = ERROR;
8778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            extrasIntent.putExtra(
8788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
87931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    result);
8808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            break;
8818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sendResult(callbackIntent, resultCode, extrasIntent);
8848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
8858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
8878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                public void onEuiccServiceUnavailable() {
88831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
8908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            });
8918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
8928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
8938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
896a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    @Override
897a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
898a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR,
899a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                "Must have MASTER_CLEAR to retain subscriptions for factory reset");
900a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        long token = Binder.clearCallingIdentity();
901a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        try {
902a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson            mConnector.retainSubscriptions(
903a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                    new EuiccConnector.RetainSubscriptionsCommandCallback() {
904a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        @Override
905a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        public void onRetainSubscriptionsComplete(int result) {
906a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            Intent extrasIntent = new Intent();
907a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            final int resultCode;
908a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            switch (result) {
909a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                case EuiccService.RESULT_OK:
910a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    resultCode = OK;
911a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    break;
912a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                default:
913a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    resultCode = ERROR;
914a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    extrasIntent.putExtra(
915a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
916a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                            result);
917a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    break;
918a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            }
919a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
920a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            sendResult(callbackIntent, resultCode, extrasIntent);
921a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        }
922a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
923a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        @Override
924a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        public void onEuiccServiceUnavailable() {
925a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            sendResult(callbackIntent, ERROR, null /* extrasIntent */);
926a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        }
927a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                    });
928a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        } finally {
929a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson            Binder.restoreCallingIdentity(token);
930a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        }
931a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    }
932a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
933d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    /** Refresh the embedded subscription list and dispatch the given result upon completion. */
934d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
935d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    public void refreshSubscriptionsAndSendResult(
936d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson            PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
937d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson        SubscriptionController.getInstance()
938d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                .requestEmbeddedSubscriptionInfoListRefresh(
939d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                        () -> sendResult(callbackIntent, resultCode, extrasIntent));
940d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    }
9418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
942fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    /** Dispatch the given callback intent with the given result code and data. */
943fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
944fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
945277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
946277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            callbackIntent.send(mContext, resultCode, extrasIntent);
947277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (PendingIntent.CanceledException e) {
948277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            // Caller canceled the callback; do nothing.
949277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
950277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
951277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
952953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Add a resolution intent to the given extras intent. */
953953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
954953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void addResolutionIntent(Intent extrasIntent, String resolutionAction,
955f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun            String callingPackage, boolean confirmationCodeRetried, EuiccOperation op) {
956953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR);
957953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION,
958953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                resolutionAction);
9599af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage);
960f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun        intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED,
961f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                confirmationCodeRetried);
962953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EXTRA_OPERATION, op);
963953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        PendingIntent resolutionIntent = PendingIntent.getActivity(
964953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT);
965953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        extrasIntent.putExtra(
966953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
967953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
968953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
969277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
970277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
971277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
972277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        final long token = Binder.clearCallingIdentity();
973277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
974277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            mConnector.dump(fd, pw, args);
975277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
976277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
977277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
978277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
979277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
98096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    /**
98196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * Send broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} for OTA status
98296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * changed.
98396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     */
98496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
98596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    public void sendOtaStatusChangedBroadcast() {
98696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
98796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
98896d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    }
98996d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
990277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Nullable
9918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) {
9928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList();
9938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int subCount = subs.size();
9948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int i = 0; i < subCount; i++) {
9958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = subs.get(i);
9968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == sub.getSubscriptionId()) {
9978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return sub;
9988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
9998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
10008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return null;
10018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
1004277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private String blockingGetEidFromEuiccService() {
10058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
10068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<String> eidRef = new AtomicReference<>();
1007277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector.getEid(new EuiccConnector.GetEidCommandCallback() {
1008277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
1009277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onGetEidComplete(String eid) {
1010277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                eidRef.set(eid);
1011277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
1012277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
1013277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1014277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
1015277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onEuiccServiceUnavailable() {
1016277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
1017277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
1018277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        });
10198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, eidRef);
10208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
1022ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    private @OtaStatus int blockingGetOtaStatusFromEuiccService() {
1023ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        CountDownLatch latch = new CountDownLatch(1);
1024ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        AtomicReference<Integer> statusRef =
1025ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                new AtomicReference<>(EUICC_OTA_STATUS_UNAVAILABLE);
1026ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        mConnector.getOtaStatus(new EuiccConnector.GetOtaStatusCommandCallback() {
1027ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            @Override
1028ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            public void onGetOtaStatusComplete(@OtaStatus int status) {
1029ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                statusRef.set(status);
1030ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                latch.countDown();
1031ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            }
1032ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
1033ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            @Override
1034ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            public void onEuiccServiceUnavailable() {
1035ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                latch.countDown();
1036ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            }
1037ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        });
1038ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        return awaitResult(latch, statusRef);
1039ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    }
1040ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
10418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
10428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private EuiccInfo blockingGetEuiccInfoFromEuiccService() {
10438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
10448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>();
10458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.getEuiccInfo(new EuiccConnector.GetEuiccInfoCommandCallback() {
10468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
10478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) {
10488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                euiccInfoRef.set(euiccInfo);
10498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
10508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
10538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onEuiccServiceUnavailable() {
10548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
10558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        });
10578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, euiccInfoRef);
10588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) {
1061277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
1062277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            latch.await();
1063277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (InterruptedException e) {
1064277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Thread.currentThread().interrupt();
1065277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
10668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return resultRef.get();
10678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private boolean canManageActiveSubscription(String callingPackage) {
10708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
10718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
107227590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        if (subInfoList == null) {
107327590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson            return false;
107427590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        }
10758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int size = subInfoList.size();
10768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int subIndex = 0; subIndex < size; subIndex++) {
10778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo subInfo = subInfoList.get(subIndex);
1078d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun
1079d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (subInfo.isEmbedded()
1080d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
10818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return true;
10828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
10848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return false;
1085277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1086277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1087277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanReadPhoneStatePrivileged() {
1088277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
1089277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
1090277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1091277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1092277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanWriteEmbeddedSubscriptions() {
1093277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
1094277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
1095277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1096277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1097277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
1098277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC.
1099277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
1100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerHasCarrierPrivilegesForActiveSubscription() {
1101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
1102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        TelephonyManager tm =
1103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
1104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return tm.hasCarrierPrivileges();
1105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson}
1107