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;
270d9f586153114c5df6407d7919117f49593fa149Qingxi Liimport android.content.pm.ComponentInfo;
2808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.content.pm.PackageInfo;
29277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.pm.PackageManager;
30277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.Binder;
31953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.os.Bundle;
32277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.ServiceManager;
334f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidsonimport android.provider.Settings;
34953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.service.euicc.EuiccService;
358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
36277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.service.euicc.GetDownloadableSubscriptionMetadataResult;
37dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.service.euicc.GetEuiccProfileInfoListResult;
38dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionInfo;
39dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionManager;
40277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.TelephonyManager;
4108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.telephony.UiccAccessRule;
42277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.DownloadableSubscription;
438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.telephony.euicc.EuiccInfo;
44277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.EuiccManager;
45ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Liimport android.telephony.euicc.EuiccManager.OtaStatus;
46f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sunimport android.text.TextUtils;
47277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.util.Log;
48277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
49277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport com.android.internal.annotations.VisibleForTesting;
50dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport com.android.internal.telephony.SubscriptionController;
5196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Liimport com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
52277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
53277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.FileDescriptor;
54277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.PrintWriter;
55dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport java.util.List;
56277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.CountDownLatch;
57277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.atomic.AtomicReference;
58277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
59277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
60277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpublic class EuiccController extends IEuiccController.Stub {
61277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static final String TAG = "EuiccController";
62277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
63953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Extra set on resolution intents containing the {@link EuiccOperation}. */
64953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting
65953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    static final String EXTRA_OPERATION = "operation";
66953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
6708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    // Aliases so line lengths stay short.
6808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK;
6908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int RESOLVABLE_ERROR =
7008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR;
7131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson    private static final int ERROR =
7231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
738bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun    private static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
748bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION;
7508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
76277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static EuiccController sInstance;
77277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
78277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final Context mContext;
79277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final EuiccConnector mConnector;
80dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    private final SubscriptionManager mSubscriptionManager;
8108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final AppOpsManager mAppOpsManager;
8208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final PackageManager mPackageManager;
83277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
84277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Initialize the instance. Should only be called once. */
85277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController init(Context context) {
86277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        synchronized (EuiccController.class) {
87277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            if (sInstance == null) {
88277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                sInstance = new EuiccController(context);
89277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            } else {
90277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
91277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
92277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
93277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
94277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
95277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
96277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Get an instance. Assumes one has already been initialized with {@link #init}. */
97277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController get() {
98277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (sInstance == null) {
99277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            synchronized (EuiccController.class) {
100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                if (sInstance == null) {
101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    throw new IllegalStateException("get() called before init()");
102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                }
103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
107277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
108277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private EuiccController(Context context) {
109277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        this(context, new EuiccConnector(context));
110277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        ServiceManager.addService("econtroller", this);
111277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
112277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
113277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @VisibleForTesting
114277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public EuiccController(Context context, EuiccConnector connector) {
115277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext = context;
116277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector = connector;
117dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mSubscriptionManager = (SubscriptionManager)
118dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
11908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
12008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mPackageManager = context.getPackageManager();
121277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
122277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
123277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
124953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * Continue an operation which failed with a user-resolvable error.
125953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     *
126953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <p>The implementation here makes a key assumption that the resolutionIntent has not been
127953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * tampered with. This is guaranteed because:
128953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <UL>
129953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created
130953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be
131953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * overridden on the PendingIntent - a caller can only add new extras.
132953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps
133953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * cannot start it directly. So the PendingIntent is the only way to start it.
134953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * </UL>
135953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     */
136953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @Override
137953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
138953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
139953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            throw new SecurityException(
140953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation");
141953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
142953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        long token = Binder.clearCallingIdentity();
143953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        try {
144953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION);
145953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            if (op == null) {
146953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                throw new IllegalArgumentException("Invalid resolution intent");
147953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            }
148953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
149953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent =
150953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    resolutionIntent.getParcelableExtra(
151953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
152953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            op.continueOperation(resolutionExtras, callbackIntent);
153953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        } finally {
154953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            Binder.restoreCallingIdentity(token);
155953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
156953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
157953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
158953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /**
159277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Return the EID.
160277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     *
161277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
162277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of
163277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * operation.
164277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
165277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
166277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public String getEid() {
167277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanReadPhoneStatePrivileged()
168277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                && !callerHasCarrierPrivilegesForActiveSubscription()) {
169277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException(
170277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    "Must have carrier privileges on active subscription to read EID");
171277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
172277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
173277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
174277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            return blockingGetEidFromEuiccService();
175277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
176277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
177277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
178277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
179277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
180ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    /**
181ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * Return the current status of OTA update.
182ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     *
183ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
184ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     * that IPC should generally be fast.
185ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li     */
186ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    @Override
187ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    public @OtaStatus int getOtaStatus() {
188ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        if (!callerCanWriteEmbeddedSubscriptions()) {
189ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status");
190ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        }
191ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        long token = Binder.clearCallingIdentity();
192ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        try {
193ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            return blockingGetOtaStatusFromEuiccService();
194ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        } finally {
195ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            Binder.restoreCallingIdentity(token);
196ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        }
197ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    }
198ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
19996d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
20096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    /**
20196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * Start eUICC OTA update if current eUICC OS is not the latest one. When OTA is started or
20296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * finished, the broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} will be sent.
20396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     *
20496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * This function will only be called from phone process and isn't exposed to the other apps.
20596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     */
20696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    public void startOtaUpdatingIfNecessary() {
20796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        mConnector.startOtaIfNecessary(
20896d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                new OtaStatusChangedCallback() {
20996d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    @Override
21096d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    public void onOtaStatusChanged(int status) {
21196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                        sendOtaStatusChangedBroadcast();
21296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    }
21396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
21496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    @Override
21596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                    public void onEuiccServiceUnavailable() {}
21696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li                });
21796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    }
21896d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
219277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
220277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
2219af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
222953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        getDownloadableSubscriptionMetadata(
2239af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
224953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
225953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
226953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
2279af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
228277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
229277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata");
230277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
2319af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
232277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
233277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
23408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(
235953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    subscription, forceDeactivateSim,
2369af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    new GetMetadataCommandCallback(
2379af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, subscription, callingPackage, callbackIntent));
238277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
239277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
240277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
241277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
242277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
24308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback {
244953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final long mCallingToken;
245953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final DownloadableSubscription mSubscription;
2469af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        protected final String mCallingPackage;
24708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        protected final PendingIntent mCallbackIntent;
24808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
249953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        GetMetadataCommandCallback(
250953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                long callingToken,
251953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription,
2529af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                String callingPackage,
253953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
254953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mCallingToken = callingToken;
255953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mSubscription = subscription;
2569af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
25708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mCallbackIntent = callbackIntent;
25808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
25908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
26008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
26108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
26208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
26308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Intent extrasIntent = new Intent();
26408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final int resultCode;
265d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            switch (result.getResult()) {
26631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
26708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = OK;
26808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
2698bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                            EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
270d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getDownloadableSubscription());
27108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
27231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
27308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = RESOLVABLE_ERROR;
274953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    addResolutionIntent(extrasIntent,
275953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
2769af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
277f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
278953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            getOperationForDeactivateSim());
27908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
28031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
28131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
28208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
28308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
284d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getResult());
28508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
28608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
28708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
28808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
28908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
29008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
29108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
29208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onEuiccServiceUnavailable() {
29331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
29408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
295953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
296953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
2979af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            return EuiccOperation.forGetMetadataDeactivateSim(
2989af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    mCallingToken, mSubscription, mCallingPackage);
299953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
30008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
30108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
302277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
303277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void downloadSubscription(DownloadableSubscription subscription,
30408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) {
305953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        downloadSubscription(subscription, switchAfterDownload, callingPackage,
306953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                false /* forceDeactivateSim */, callbackIntent);
307953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
308953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
309953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscription(DownloadableSubscription subscription,
310953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
311953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent) {
31208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
31308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
31408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
315277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
316277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
31708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (callerCanWriteEmbeddedSubscriptions) {
31808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
31908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // and move straight to the profile download.
320953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                downloadSubscriptionPrivileged(token, subscription, switchAfterDownload,
321953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                        forceDeactivateSim, callingPackage, callbackIntent);
32208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
32308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
32408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the
32508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // metadata of the profile to be downloaded, so check the metadata first.
32608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(subscription,
327953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    forceDeactivateSim,
328953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
329953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            switchAfterDownload, callingPackage, forceDeactivateSim,
330953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            callbackIntent));
331277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
332277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
333277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
334277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
335277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
33608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
33708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        private final boolean mSwitchAfterDownload;
338953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        private final boolean mForceDeactivateSim;
33908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
340953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
341953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription, boolean switchAfterDownload,
342953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                String callingPackage, boolean forceDeactivateSim,
343953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
3449af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            super(callingToken, subscription, callingPackage, callbackIntent);
34508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mSwitchAfterDownload = switchAfterDownload;
346953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mForceDeactivateSim = forceDeactivateSim;
34708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
34808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
34908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
35008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
35108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
352d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (result.getResult() == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
3539af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // If we need to deactivate the current SIM to even check permissions, go ahead and
3549af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // require that the user resolve the stronger permission dialog.
3559af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                Intent extrasIntent = new Intent();
3569af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
3579af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        mCallingPackage,
358f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                        false /* confirmationCodeRetried */,
3599af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        EuiccOperation.forDownloadNoPrivileges(
3609af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingToken, mSubscription, mSwitchAfterDownload,
3619af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingPackage));
3629af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
3639af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                return;
3649af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            }
3659af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson
366d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (result.getResult() != EuiccService.RESULT_OK) {
36708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // Just propagate the error as normal.
36808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                super.onGetMetadataComplete(result);
36908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
37008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
37108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
372d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            DownloadableSubscription subscription = result.getDownloadableSubscription();
373d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            UiccAccessRule[] rules = null;
374d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            List<UiccAccessRule> rulesList = subscription.getAccessRules();
375d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (rulesList != null) {
376d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                rules = rulesList.toArray(new UiccAccessRule[rulesList.size()]);
377d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            }
37808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (rules == null) {
37908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "No access rules but caller is unprivileged");
38031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
38108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
38208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
38308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
38408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final PackageInfo info;
38508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            try {
38608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                info = mPackageManager.getPackageInfo(
38708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        mCallingPackage, PackageManager.GET_SIGNATURES);
38808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            } catch (PackageManager.NameNotFoundException e) {
38908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "Calling package valid but gone");
39031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
39108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
39208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
39308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
39408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            for (int i = 0; i < rules.length; i++) {
39508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                if (rules[i].getCarrierPrivilegeStatus(info)
39608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
397dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Caller can download this profile. Now, determine whether the caller can also
398dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // manage the current profile; if so, we can perform the download silently; if
399dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // not, the user must provide consent.
4008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    if (canManageActiveSubscription(mCallingPackage)) {
4018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        downloadSubscriptionPrivileged(
4028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mCallingToken, subscription, mSwitchAfterDownload,
4038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mForceDeactivateSim, mCallingPackage, mCallbackIntent);
4048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        return;
40508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
406dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
407dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Switch might still be permitted, but the user must consent first.
408dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    Intent extrasIntent = new Intent();
409dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
4109af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
411f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
412dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                            EuiccOperation.forDownloadNoPrivileges(
4138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingToken, subscription, mSwitchAfterDownload,
4148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingPackage));
415dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
41608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    return;
41708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                }
41808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
41908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Log.e(TAG, "Caller is not permitted to download this profile");
42031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
42108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
422953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
423953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        @Override
424953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
425953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            return EuiccOperation.forDownloadDeactivateSim(
426953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage);
427953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
42808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
42908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
430953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscriptionPrivileged(final long callingToken,
431953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            DownloadableSubscription subscription, boolean switchAfterDownload,
432953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
433953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            final PendingIntent callbackIntent) {
434953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        mConnector.downloadSubscription(
435953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                subscription,
436953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                switchAfterDownload,
437953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                forceDeactivateSim,
43808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                new EuiccConnector.DownloadCommandCallback() {
43908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
44031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDownloadComplete(int result) {
44108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        Intent extrasIntent = new Intent();
44208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        final int resultCode;
44331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
44431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
44508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = OK;
4464f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // Now that a profile has been successfully downloaded, mark the
4474f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // eUICC as provisioned so it appears in settings UI as appropriate.
4484f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                Settings.Global.putInt(
4494f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        mContext.getContentResolver(),
4504f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        Settings.Global.EUICC_PROVISIONED,
4514f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        1);
4528bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                extrasIntent.putExtra(
4538bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                        EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
4548bf20cb416675744e28821f509a20ae2813ad44eHolly Jiuyu Sun                                        subscription);
455dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                if (!switchAfterDownload) {
456dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // Since we're not switching, nothing will trigger a
457dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // subscription list refresh on its own, so request one here.
458d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    refreshSubscriptionsAndSendResult(
459d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                            callbackIntent, resultCode, extrasIntent);
460d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    return;
461dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                }
46208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
46331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
46408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = RESOLVABLE_ERROR;
465953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                addResolutionIntent(extrasIntent,
466953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
4679af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
468f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        false /* confirmationCodeRetried */,
469953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccOperation.forDownloadDeactivateSim(
470953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingToken, subscription, switchAfterDownload,
471953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingPackage));
47208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
47380fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                            case EuiccService.RESULT_NEED_CONFIRMATION_CODE:
47480fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                resultCode = RESOLVABLE_ERROR;
475f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                boolean retried = false;
476f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                if (!TextUtils.isEmpty(subscription.getConfirmationCode())) {
477f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                    retried = true;
478f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                }
47980fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                addResolutionIntent(extrasIntent,
48080fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE,
48180fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        callingPackage,
482f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        retried /* confirmationCodeRetried */,
48380fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                        EuiccOperation.forDownloadConfirmationCode(
48480fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                                callingToken, subscription, switchAfterDownload,
48580fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                                callingPackage));
48680fc6417014d6a884b009557fd7d19861a1087abHolly Jiuyu Sun                                break;
48731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
48831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
48908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                extrasIntent.putExtra(
49008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
49131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
49208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
49308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        }
49408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
49508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
49608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
49708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
49808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
49908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    public void onEuiccServiceUnavailable() {
50031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
50108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
50208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                });
50308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
50408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
505dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    /**
506dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList}.
507dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     *
508dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * <p>Does not perform permission checks as this is not an exposed API and is only used within
509dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * the phone process.
510dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     */
511dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList() {
512dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final CountDownLatch latch = new CountDownLatch(1);
513dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>();
514dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mConnector.getEuiccProfileInfoList(
515dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                new EuiccConnector.GetEuiccProfileInfoListCommandCallback() {
516dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
517dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onListComplete(GetEuiccProfileInfoListResult result) {
518dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        resultRef.set(result);
519dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
520dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
521dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
522dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
523dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onEuiccServiceUnavailable() {
524dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
525dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
526dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                });
527dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        try {
528dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            latch.await();
529dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        } catch (InterruptedException e) {
530dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            Thread.currentThread().interrupt();
531dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        }
532dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        return resultRef.get();
533dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    }
534dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
5358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
5369af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson    public void getDefaultDownloadableSubscriptionList(
5379af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
5389af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        getDefaultDownloadableSubscriptionList(
5399af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                false /* forceDeactivateSim */, callingPackage, callbackIntent);
5408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void getDefaultDownloadableSubscriptionList(
5439af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
5448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
5458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
5468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list");
5478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5489af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
5498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
5508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
5518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.getDefaultDownloadableSubscriptionList(
5529af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    forceDeactivateSim, new GetDefaultListCommandCallback(
5539af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, callingPackage, callbackIntent));
5548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
5558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
5568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback {
5609af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final long mCallingToken;
5619af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final String mCallingPackage;
5629af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final PendingIntent mCallbackIntent;
5638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5649af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        GetDefaultListCommandCallback(long callingToken, String callingPackage,
5659af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                PendingIntent callbackIntent) {
5668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallingToken = callingToken;
5679af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
5688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallbackIntent = callbackIntent;
5698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
5728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result) {
5738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Intent extrasIntent = new Intent();
5748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final int resultCode;
575d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            switch (result.getResult()) {
57631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
5778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = OK;
578d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    List<DownloadableSubscription> list = result.getDownloadableSubscriptions();
579d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    if (list != null && list.size() > 0) {
580d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                        extrasIntent.putExtra(
581d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS,
582d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                                list.toArray(new DownloadableSubscription[list.size()]));
583d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    }
5848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
58531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
5868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = RESOLVABLE_ERROR;
5878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    addResolutionIntent(extrasIntent,
5888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
5899af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
590f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                            false /* confirmationCodeRetried */,
5919af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            EuiccOperation.forGetDefaultListDeactivateSim(
5929af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                    mCallingToken, mCallingPackage));
5938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
59431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
59531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
5968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    extrasIntent.putExtra(
5978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
598d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                            result.getResult());
5998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
6008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
6038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
6068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onEuiccServiceUnavailable() {
60731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
6088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    /**
6128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * Return the {@link EuiccInfo}.
6138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     *
6148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
6158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * that IPC should generally be fast, and this info shouldn't be needed in the normal course of
6168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * operation.
6178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     */
6188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public EuiccInfo getEuiccInfo() {
6208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // No permissions required as EuiccInfo is not sensitive.
6218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
6228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
6238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            return blockingGetEuiccInfoFromEuiccService();
6248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
6258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
6268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void deleteSubscription(int subscriptionId, String callingPackage,
6318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
6338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
6348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
6368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
6378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
6388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
6398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId);
64031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
6428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
6458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !sub.canManageSubscription(mContext, callingPackage)) {
6468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "No permissions: " + subscriptionId);
64731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
6498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            deleteSubscriptionPrivileged(sub.getIccId(), callbackIntent);
6528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
6538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
6548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent) {
6588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.deleteSubscription(
6598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
6608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.DeleteCommandCallback() {
6618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
66231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDeleteComplete(int result) {
6638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
6648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
66531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
66631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
6678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
668d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                refreshSubscriptionsAndSendResult(
669d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                        callbackIntent, resultCode, extrasIntent);
670d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                return;
67131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
67231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
6738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
6748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
67531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
6768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
6778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
6788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
6808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
6838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
68431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
6878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void switchToSubscription(int subscriptionId, String callingPackage,
6918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscription(
6938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent);
6948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage,
6978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
6998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
7008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
7028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
7032938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson            if (callerCanWriteEmbeddedSubscriptions) {
7042938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // Assume that if a privileged caller is calling us, we don't need to prompt the
7052938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // user about changing carriers, because the caller would only be acting in response
7062938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                // to user action.
7072938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson                forceDeactivateSim = true;
7082938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson            }
7092938f11d0b1e409089828c0247a5b79f3550a35aJeff Davidson
7108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final String iccid;
7118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
7128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch to "no" subscription. Only the system can do this.
7138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions) {
7148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to empty subscription");
71531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = null;
7198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            } else {
7208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
7218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (sub == null) {
7228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Cannot switch to nonexistent subscription: " + subscriptionId);
72331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions
727d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                        && !mSubscriptionManager.canManageSubscription(sub, callingPackage)) {
7288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to subscription: " + subscriptionId);
72931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
7318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = sub.getIccId();
7338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
7348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
7368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !canManageActiveSubscription(callingPackage)) {
7378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch needs consent.
7388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Intent extrasIntent = new Intent();
7398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                addResolutionIntent(extrasIntent,
7408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
7419af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        callingPackage,
742f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                        false /* confirmationCodeRetried */,
7438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccOperation.forSwitchNoPrivileges(
7448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                token, subscriptionId, callingPackage));
7458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
7468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
7478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
7488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            switchToSubscriptionPrivileged(token, subscriptionId, iccid, forceDeactivateSim,
7508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    callingPackage, callbackIntent);
7518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
7528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
7538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
7578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
7588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
7598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        String iccid = null;
7608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
7618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (sub != null) {
7628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            iccid = sub.getIccId();
7638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscriptionPrivileged(callingToken, subscriptionId, iccid, forceDeactivateSim,
7658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                callingPackage, callbackIntent);
7668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
7698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage,
7708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
7718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.switchToSubscription(
7728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
7738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                forceDeactivateSim,
7748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.SwitchCommandCallback() {
7758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
77631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onSwitchComplete(int result) {
7778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
7788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
77931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
78031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
7818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
7828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
78331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
7848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = RESOLVABLE_ERROR;
7858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                addResolutionIntent(extrasIntent,
7868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
7879af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
788f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                                        false /* confirmationCodeRetried */,
7898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccOperation.forSwitchDeactivateSim(
7908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                                callingToken, subscriptionId, callingPackage));
7918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
79231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
79331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
7948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
7958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
79631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
7978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
7988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
7998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
8018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
8048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
80531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
8088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
8118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void updateSubscriptionNickname(int subscriptionId, String nickname,
8128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
8138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
8148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
8158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to update nickname");
8168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
8188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
8198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
8208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
8218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot update nickname to nonexistent subscription: " + subscriptionId);
82231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
8248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
8258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.updateSubscriptionNickname(
8268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sub.getIccId(), nickname,
8278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    new EuiccConnector.UpdateNicknameCommandCallback() {
8288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
82931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        public void onUpdateNicknameComplete(int result) {
8308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            Intent extrasIntent = new Intent();
8318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            final int resultCode;
83231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            switch (result) {
83331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                case EuiccService.RESULT_OK:
8348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    resultCode = OK;
8358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
83631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                default:
83731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    resultCode = ERROR;
8388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    extrasIntent.putExtra(
8398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
84031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                            result);
8418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
8428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            }
8438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            sendResult(callbackIntent, resultCode, extrasIntent);
8458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
8468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
8488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        public void onEuiccServiceUnavailable() {
84931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
8518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    });
8528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
8538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
8548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
8588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void eraseSubscriptions(PendingIntent callbackIntent) {
8598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
8608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
8618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
8628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
8648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
8658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.eraseSubscriptions(new EuiccConnector.EraseCommandCallback() {
8668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
86731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                public void onEraseComplete(int result) {
8688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Intent extrasIntent = new Intent();
8698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    final int resultCode;
87031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    switch (result) {
87131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        case EuiccService.RESULT_OK:
8728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            resultCode = OK;
873d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                            refreshSubscriptionsAndSendResult(
874d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                                    callbackIntent, resultCode, extrasIntent);
875d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                            return;
87631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        default:
87731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            resultCode = ERROR;
8788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            extrasIntent.putExtra(
8798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
88031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    result);
8818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            break;
8828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
8838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sendResult(callbackIntent, resultCode, extrasIntent);
8858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
8868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
8888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                public void onEuiccServiceUnavailable() {
88931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
8918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            });
8928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
8938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
8948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
897a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    @Override
898a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
899a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR,
900a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                "Must have MASTER_CLEAR to retain subscriptions for factory reset");
901a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        long token = Binder.clearCallingIdentity();
902a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        try {
903a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson            mConnector.retainSubscriptions(
904a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                    new EuiccConnector.RetainSubscriptionsCommandCallback() {
905a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        @Override
906a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        public void onRetainSubscriptionsComplete(int result) {
907a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            Intent extrasIntent = new Intent();
908a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            final int resultCode;
909a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            switch (result) {
910a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                case EuiccService.RESULT_OK:
911a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    resultCode = OK;
912a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    break;
913a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                default:
914a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    resultCode = ERROR;
915a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    extrasIntent.putExtra(
916a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
917a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                            result);
918a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                                    break;
919a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            }
920a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
921a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            sendResult(callbackIntent, resultCode, extrasIntent);
922a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        }
923a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
924a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        @Override
925a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        public void onEuiccServiceUnavailable() {
926a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                            sendResult(callbackIntent, ERROR, null /* extrasIntent */);
927a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                        }
928a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson                    });
929a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        } finally {
930a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson            Binder.restoreCallingIdentity(token);
931a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson        }
932a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson    }
933a9c50823e758d35bac39cf2a7e674fcaf957fd4bJeff Davidson
934d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    /** Refresh the embedded subscription list and dispatch the given result upon completion. */
935d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
936d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    public void refreshSubscriptionsAndSendResult(
937d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson            PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
938d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson        SubscriptionController.getInstance()
939d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                .requestEmbeddedSubscriptionInfoListRefresh(
940d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson                        () -> sendResult(callbackIntent, resultCode, extrasIntent));
941d728841b17b19ab8268a426051f51f64a6913142Jeff Davidson    }
9428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
943fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    /** Dispatch the given callback intent with the given result code and data. */
944fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
945fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
946277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
947277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            callbackIntent.send(mContext, resultCode, extrasIntent);
948277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (PendingIntent.CanceledException e) {
949277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            // Caller canceled the callback; do nothing.
950277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
951277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
952277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
953953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Add a resolution intent to the given extras intent. */
954953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
955953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void addResolutionIntent(Intent extrasIntent, String resolutionAction,
956f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun            String callingPackage, boolean confirmationCodeRetried, EuiccOperation op) {
957953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR);
958953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION,
959953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                resolutionAction);
9609af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage);
961f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun        intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED,
962f2e6e134218a3302a8889ceef73d0f7ccfbddb56Holly Jiuyu Sun                confirmationCodeRetried);
963953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EXTRA_OPERATION, op);
964953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        PendingIntent resolutionIntent = PendingIntent.getActivity(
965953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT);
966953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        extrasIntent.putExtra(
967953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
968953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
969953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
970277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
971277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
972277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
973277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        final long token = Binder.clearCallingIdentity();
974277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
975277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            mConnector.dump(fd, pw, args);
976277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
977277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
978277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
979277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
980277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
98196d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    /**
98296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * Send broadcast {@link EuiccManager#ACTION_OTA_STATUS_CHANGED} for OTA status
98396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     * changed.
98496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li     */
98596d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
98696d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    public void sendOtaStatusChangedBroadcast() {
98796d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
9880d9f586153114c5df6407d7919117f49593fa149Qingxi Li        ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager());
9890d9f586153114c5df6407d7919117f49593fa149Qingxi Li        if (bestComponent != null) {
9900d9f586153114c5df6407d7919117f49593fa149Qingxi Li            intent.setPackage(bestComponent.packageName);
9910d9f586153114c5df6407d7919117f49593fa149Qingxi Li        }
99296d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li        mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
99396d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li    }
99496d4dfe105bae38079c1ad834e5840365f2b9cc6Qingxi Li
995277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Nullable
9968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) {
9978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList();
9988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int subCount = subs.size();
9998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int i = 0; i < subCount; i++) {
10008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = subs.get(i);
10018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == sub.getSubscriptionId()) {
10028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return sub;
10038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
10058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return null;
10068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
1009277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private String blockingGetEidFromEuiccService() {
10108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
10118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<String> eidRef = new AtomicReference<>();
1012277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector.getEid(new EuiccConnector.GetEidCommandCallback() {
1013277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
1014277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onGetEidComplete(String eid) {
1015277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                eidRef.set(eid);
1016277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
1017277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
1018277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1019277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
1020277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onEuiccServiceUnavailable() {
1021277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
1022277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
1023277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        });
10248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, eidRef);
10258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
1027ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    private @OtaStatus int blockingGetOtaStatusFromEuiccService() {
1028ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        CountDownLatch latch = new CountDownLatch(1);
1029ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        AtomicReference<Integer> statusRef =
1030ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                new AtomicReference<>(EUICC_OTA_STATUS_UNAVAILABLE);
1031ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        mConnector.getOtaStatus(new EuiccConnector.GetOtaStatusCommandCallback() {
1032ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            @Override
1033ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            public void onGetOtaStatusComplete(@OtaStatus int status) {
1034ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                statusRef.set(status);
1035ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                latch.countDown();
1036ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            }
1037ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
1038ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            @Override
1039ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            public void onEuiccServiceUnavailable() {
1040ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li                latch.countDown();
1041ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li            }
1042ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        });
1043ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li        return awaitResult(latch, statusRef);
1044ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li    }
1045ebbbe7bdbf2c6226913480bbd83a88cd0460a86aQingxi Li
10468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
10478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private EuiccInfo blockingGetEuiccInfoFromEuiccService() {
10488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
10498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>();
10508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.getEuiccInfo(new EuiccConnector.GetEuiccInfoCommandCallback() {
10518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
10528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) {
10538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                euiccInfoRef.set(euiccInfo);
10548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
10558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
10588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onEuiccServiceUnavailable() {
10598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
10608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        });
10628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, euiccInfoRef);
10638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) {
1066277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
1067277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            latch.await();
1068277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (InterruptedException e) {
1069277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Thread.currentThread().interrupt();
1070277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
10718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return resultRef.get();
10728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
10738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
10748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private boolean canManageActiveSubscription(String callingPackage) {
10758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
10768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
107727590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        if (subInfoList == null) {
107827590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson            return false;
107927590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        }
10808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int size = subInfoList.size();
10818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int subIndex = 0; subIndex < size; subIndex++) {
10828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo subInfo = subInfoList.get(subIndex);
1083d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun
1084d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun            if (subInfo.isEmbedded()
1085d828468595f5483da81732d7e321c8204b0fa2b7Jiuyu Sun                    && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) {
10868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return true;
10878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
10888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
10898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return false;
1090277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1091277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1092277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanReadPhoneStatePrivileged() {
1093277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
1094277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
1095277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1096277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1097277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanWriteEmbeddedSubscriptions() {
1098277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
1099277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
1100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
1102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
1103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC.
1104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
1105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerHasCarrierPrivilegesForActiveSubscription() {
1106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
1107277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        TelephonyManager tm =
1108277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
1109277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return tm.hasCarrierPrivileges();
1110277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
1111277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson}
1112