EuiccController.java revision 9af6424827eb9e023e037dd5aefd229235aceddb
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
18277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.Manifest;
19277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.annotation.Nullable;
2008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.app.AppOpsManager;
21277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.app.PendingIntent;
22277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Context;
23277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Intent;
2408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.content.pm.PackageInfo;
25277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.pm.PackageManager;
26277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.Binder;
27953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.os.Bundle;
28277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.ServiceManager;
294f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidsonimport android.provider.Settings;
30953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidsonimport android.service.euicc.EuiccService;
318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
32277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.service.euicc.GetDownloadableSubscriptionMetadataResult;
33dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.service.euicc.GetEuiccProfileInfoListResult;
34dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionInfo;
35dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport android.telephony.SubscriptionManager;
36277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.TelephonyManager;
3708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.telephony.UiccAccessRule;
38277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.DownloadableSubscription;
398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidsonimport android.telephony.euicc.EuiccInfo;
40277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.EuiccManager;
41277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.util.Log;
42277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
43277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport com.android.internal.annotations.VisibleForTesting;
44dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport com.android.internal.telephony.SubscriptionController;
45277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
46277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.FileDescriptor;
47277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.PrintWriter;
48dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidsonimport java.util.List;
49277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.CountDownLatch;
50277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.atomic.AtomicReference;
51277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
52277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */
53277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpublic class EuiccController extends IEuiccController.Stub {
54277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static final String TAG = "EuiccController";
55277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
56953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Extra set on resolution intents containing the {@link EuiccOperation}. */
57953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting
58953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    static final String EXTRA_OPERATION = "operation";
59953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
6008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    // Aliases so line lengths stay short.
6108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK;
6208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private static final int RESOLVABLE_ERROR =
6308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR;
6431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson    private static final int ERROR =
6531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
6608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
67277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private static EuiccController sInstance;
68277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
69277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final Context mContext;
70277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private final EuiccConnector mConnector;
71dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    private final SubscriptionManager mSubscriptionManager;
7208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final AppOpsManager mAppOpsManager;
7308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    private final PackageManager mPackageManager;
74277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
75277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Initialize the instance. Should only be called once. */
76277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController init(Context context) {
77277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        synchronized (EuiccController.class) {
78277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            if (sInstance == null) {
79277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                sInstance = new EuiccController(context);
80277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            } else {
81277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance);
82277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
83277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
84277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
85277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
86277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
87277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /** Get an instance. Assumes one has already been initialized with {@link #init}. */
88277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public static EuiccController get() {
89277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (sInstance == null) {
90277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            synchronized (EuiccController.class) {
91277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                if (sInstance == null) {
92277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    throw new IllegalStateException("get() called before init()");
93277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                }
94277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
95277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
96277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return sInstance;
97277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
98277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
99277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private EuiccController(Context context) {
100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        this(context, new EuiccConnector(context));
101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        ServiceManager.addService("econtroller", this);
102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @VisibleForTesting
105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public EuiccController(Context context, EuiccConnector connector) {
106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext = context;
107277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector = connector;
108dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mSubscriptionManager = (SubscriptionManager)
109dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
11008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
11108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mPackageManager = context.getPackageManager();
112277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
113277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
114277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
115953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * Continue an operation which failed with a user-resolvable error.
116953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     *
117953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <p>The implementation here makes a key assumption that the resolutionIntent has not been
118953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * tampered with. This is guaranteed because:
119953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <UL>
120953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created
121953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be
122953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * overridden on the PendingIntent - a caller can only add new extras.
123953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps
124953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * cannot start it directly. So the PendingIntent is the only way to start it.
125953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     * </UL>
126953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson     */
127953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @Override
128953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
129953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
130953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            throw new SecurityException(
131953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation");
132953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
133953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        long token = Binder.clearCallingIdentity();
134953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        try {
135953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION);
136953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            if (op == null) {
137953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                throw new IllegalArgumentException("Invalid resolution intent");
138953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            }
139953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
140953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent =
141953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    resolutionIntent.getParcelableExtra(
142953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
143953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            op.continueOperation(resolutionExtras, callbackIntent);
144953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        } finally {
145953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            Binder.restoreCallingIdentity(token);
146953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
147953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
148953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
149953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /**
150277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Return the EID.
151277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     *
152277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
153277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of
154277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * operation.
155277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
156277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
157277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public String getEid() {
158277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanReadPhoneStatePrivileged()
159277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                && !callerHasCarrierPrivilegesForActiveSubscription()) {
160277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException(
161277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                    "Must have carrier privileges on active subscription to read EID");
162277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
163277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
164277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
165277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            return blockingGetEidFromEuiccService();
166277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
167277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
168277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
169277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
170277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
171277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
172277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
1739af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
174953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        getDownloadableSubscriptionMetadata(
1759af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent);
176953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
177953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
178953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
1799af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
180277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
181277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata");
182277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
1839af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
184277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
185277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
18608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(
187953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    subscription, forceDeactivateSim,
1889af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    new GetMetadataCommandCallback(
1899af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, subscription, callingPackage, callbackIntent));
190277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
191277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
192277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
193277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
194277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
19508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback {
196953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final long mCallingToken;
197953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected final DownloadableSubscription mSubscription;
1989af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        protected final String mCallingPackage;
19908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        protected final PendingIntent mCallbackIntent;
20008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
201953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        GetMetadataCommandCallback(
202953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                long callingToken,
203953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription,
2049af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                String callingPackage,
205953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
206953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mCallingToken = callingToken;
207953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mSubscription = subscription;
2089af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
20908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mCallbackIntent = callbackIntent;
21008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
21108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
21208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
21308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
21408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
21508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Intent extrasIntent = new Intent();
21608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final int resultCode;
21708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            switch (result.result) {
21831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
21908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = OK;
22008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
22108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION,
22208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                            result.subscription);
22308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
22431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
22508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    resultCode = RESOLVABLE_ERROR;
226953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    addResolutionIntent(extrasIntent,
227953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
2289af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
229953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            getOperationForDeactivateSim());
23008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
23131e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
23231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
23308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    extrasIntent.putExtra(
23408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
23531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            result.result);
23608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    break;
23708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
23808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
23908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
24008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
24108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
24208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
24308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onEuiccServiceUnavailable() {
24431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
24508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
246953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
247953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
2489af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            return EuiccOperation.forGetMetadataDeactivateSim(
2499af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    mCallingToken, mSubscription, mCallingPackage);
250953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
25108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
25208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
253277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
254277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void downloadSubscription(DownloadableSubscription subscription,
25508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) {
256953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        downloadSubscription(subscription, switchAfterDownload, callingPackage,
257953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                false /* forceDeactivateSim */, callbackIntent);
258953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
259953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
260953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscription(DownloadableSubscription subscription,
261953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim,
262953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            PendingIntent callbackIntent) {
26308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
26408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
26508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
266277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        long token = Binder.clearCallingIdentity();
267277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
26808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (callerCanWriteEmbeddedSubscriptions) {
26908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks
27008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // and move straight to the profile download.
271953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                downloadSubscriptionPrivileged(token, subscription, switchAfterDownload,
272953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                        forceDeactivateSim, callingPackage, callbackIntent);
27308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
27408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
27508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the
27608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            // metadata of the profile to be downloaded, so check the metadata first.
27708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mConnector.getDownloadableSubscriptionMetadata(subscription,
278953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    forceDeactivateSim,
279953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    new DownloadSubscriptionGetMetadataCommandCallback(token, subscription,
280953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            switchAfterDownload, callingPackage, forceDeactivateSim,
281953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                            callbackIntent));
282277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
283277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
284277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
285277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
286277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
28708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback {
28808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        private final boolean mSwitchAfterDownload;
289953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        private final boolean mForceDeactivateSim;
29008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
291953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        DownloadSubscriptionGetMetadataCommandCallback(long callingToken,
292953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                DownloadableSubscription subscription, boolean switchAfterDownload,
293953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                String callingPackage, boolean forceDeactivateSim,
294953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                PendingIntent callbackIntent) {
2959af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            super(callingToken, subscription, callingPackage, callbackIntent);
29608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            mSwitchAfterDownload = switchAfterDownload;
297953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            mForceDeactivateSim = forceDeactivateSim;
29808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
29908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
30008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        @Override
30108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        public void onGetMetadataComplete(
30208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                GetDownloadableSubscriptionMetadataResult result) {
3039af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            if (result.result == EuiccService.RESULT_MUST_DEACTIVATE_SIM) {
3049af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // If we need to deactivate the current SIM to even check permissions, go ahead and
3059af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                // require that the user resolve the stronger permission dialog.
3069af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                Intent extrasIntent = new Intent();
3079af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
3089af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        mCallingPackage,
3099af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        EuiccOperation.forDownloadNoPrivileges(
3109af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingToken, mSubscription, mSwitchAfterDownload,
3119af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                mCallingPackage));
3129af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
3139af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                return;
3149af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            }
3159af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson
31631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            if (result.result != EuiccService.RESULT_OK) {
31708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                // Just propagate the error as normal.
31808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                super.onGetMetadataComplete(result);
31908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
32008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
32108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
32208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            DownloadableSubscription subscription = result.subscription;
32308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            UiccAccessRule[] rules = subscription.getAccessRules();
32408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            if (rules == null) {
32508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "No access rules but caller is unprivileged");
32631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
32708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
32808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
32908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
33008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            final PackageInfo info;
33108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            try {
33208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                info = mPackageManager.getPackageInfo(
33308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        mCallingPackage, PackageManager.GET_SIGNATURES);
33408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            } catch (PackageManager.NameNotFoundException e) {
33508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                Log.e(TAG, "Calling package valid but gone");
33631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
33708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                return;
33808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
33908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
34008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            for (int i = 0; i < rules.length; i++) {
34108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                if (rules[i].getCarrierPrivilegeStatus(info)
34208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
343dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Caller can download this profile. Now, determine whether the caller can also
344dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // manage the current profile; if so, we can perform the download silently; if
345dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // not, the user must provide consent.
3468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    if (canManageActiveSubscription(mCallingPackage)) {
3478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        downloadSubscriptionPrivileged(
3488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mCallingToken, subscription, mSwitchAfterDownload,
3498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                mForceDeactivateSim, mCallingPackage, mCallbackIntent);
3508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        return;
35108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
352dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
353dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    // Switch might still be permitted, but the user must consent first.
354dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    Intent extrasIntent = new Intent();
355dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
3569af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
357dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                            EuiccOperation.forDownloadNoPrivileges(
3588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingToken, subscription, mSwitchAfterDownload,
3598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    mCallingPackage));
360dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent);
36108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    return;
36208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                }
36308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            }
36408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson            Log.e(TAG, "Caller is not permitted to download this profile");
36531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
36608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson        }
367953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
368953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        @Override
369953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        protected EuiccOperation getOperationForDeactivateSim() {
370953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            return EuiccOperation.forDownloadDeactivateSim(
371953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                    mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage);
372953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        }
37308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
37408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
375953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    void downloadSubscriptionPrivileged(final long callingToken,
376953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            DownloadableSubscription subscription, boolean switchAfterDownload,
377953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
378953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson            final PendingIntent callbackIntent) {
379953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        mConnector.downloadSubscription(
380953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                subscription,
381953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                switchAfterDownload,
382953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                forceDeactivateSim,
38308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                new EuiccConnector.DownloadCommandCallback() {
38408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
38531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDownloadComplete(int result) {
38608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        Intent extrasIntent = new Intent();
38708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        final int resultCode;
38831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
38931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
39008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = OK;
3914f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // Now that a profile has been successfully downloaded, mark the
3924f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                // eUICC as provisioned so it appears in settings UI as appropriate.
3934f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                Settings.Global.putInt(
3944f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        mContext.getContentResolver(),
3954f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        Settings.Global.EUICC_PROVISIONED,
3964f62c3ddcc69bc8217e4794c73d38945e97380eeJeff Davidson                                        1);
397dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                if (!switchAfterDownload) {
398dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // Since we're not switching, nothing will trigger a
399dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    // subscription list refresh on its own, so request one here.
400dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                    SubscriptionController.getInstance()
401dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                            .requestEmbeddedSubscriptionInfoListRefresh();
402dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                                }
40308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
40431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
40508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                resultCode = RESOLVABLE_ERROR;
406953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                addResolutionIntent(extrasIntent,
407953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
4089af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
409953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                        EuiccOperation.forDownloadDeactivateSim(
410953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingToken, subscription, switchAfterDownload,
411953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                                                callingPackage));
41208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
41331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
41431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
41508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                extrasIntent.putExtra(
41608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
41731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
41808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                                break;
41908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        }
42008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
42108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
42208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
42308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
42408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    @Override
42508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    public void onEuiccServiceUnavailable() {
42631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
42708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                    }
42808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson                });
42908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson    }
43008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson
431dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    /**
432dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList}.
433dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     *
434dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * <p>Does not perform permission checks as this is not an exposed API and is only used within
435dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     * the phone process.
436dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson     */
437dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList() {
438dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final CountDownLatch latch = new CountDownLatch(1);
439dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>();
440dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        mConnector.getEuiccProfileInfoList(
441dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                new EuiccConnector.GetEuiccProfileInfoListCommandCallback() {
442dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
443dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onListComplete(GetEuiccProfileInfoListResult result) {
444dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        resultRef.set(result);
445dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
446dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
447dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
448dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    @Override
449dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    public void onEuiccServiceUnavailable() {
450dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                        latch.countDown();
451dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                    }
452dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson                });
453dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        try {
454dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            latch.await();
455dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        } catch (InterruptedException e) {
456dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson            Thread.currentThread().interrupt();
457dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        }
458dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson        return resultRef.get();
459dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson    }
460dce529f00c52bedf4377ee5f7ae1b284fe6452beJeff Davidson
4618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
4629af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson    public void getDefaultDownloadableSubscriptionList(
4639af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, PendingIntent callbackIntent) {
4649af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        getDefaultDownloadableSubscriptionList(
4659af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                false /* forceDeactivateSim */, callingPackage, callbackIntent);
4668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
4678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
4688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void getDefaultDownloadableSubscriptionList(
4699af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) {
4708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
4718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
4728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list");
4738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
4749af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
4758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
4768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
4778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.getDefaultDownloadableSubscriptionList(
4789af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                    forceDeactivateSim, new GetDefaultListCommandCallback(
4799af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            token, callingPackage, callbackIntent));
4808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
4818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
4828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
4838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
4848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
4858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback {
4869af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final long mCallingToken;
4879af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final String mCallingPackage;
4889af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        final PendingIntent mCallbackIntent;
4898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
4909af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        GetDefaultListCommandCallback(long callingToken, String callingPackage,
4919af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                PendingIntent callbackIntent) {
4928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallingToken = callingToken;
4939af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            mCallingPackage = callingPackage;
4948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mCallbackIntent = callbackIntent;
4958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
4968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
4978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
4988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result) {
4998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Intent extrasIntent = new Intent();
5008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final int resultCode;
5018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            switch (result.result) {
50231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_OK:
5038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = OK;
5048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    extrasIntent.putExtra(
5058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS,
5068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            result.subscriptions);
5078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
50831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
5098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    resultCode = RESOLVABLE_ERROR;
5108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    addResolutionIntent(extrasIntent,
5118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
5129af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            mCallingPackage,
5139af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                            EuiccOperation.forGetDefaultListDeactivateSim(
5149af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                    mCallingToken, mCallingPackage));
5158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
51631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                default:
51731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    resultCode = ERROR;
5188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    extrasIntent.putExtra(
5198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
52031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            result.result);
5218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    break;
5228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
5238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            sendResult(mCallbackIntent, resultCode, extrasIntent);
5258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        @Override
5288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        public void onEuiccServiceUnavailable() {
52931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson            sendResult(mCallbackIntent, ERROR, null /* extrasIntent */);
5308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    /**
5348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * Return the {@link EuiccInfo}.
5358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     *
5368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
5378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * that IPC should generally be fast, and this info shouldn't be needed in the normal course of
5388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     * operation.
5398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson     */
5408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
5418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public EuiccInfo getEuiccInfo() {
5428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // No permissions required as EuiccInfo is not sensitive.
5438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
5448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
5458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            return blockingGetEuiccInfoFromEuiccService();
5468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
5478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
5488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
5528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void deleteSubscription(int subscriptionId, String callingPackage,
5538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
5548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
5558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
5568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
5588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
5598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
5608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
5618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId);
56231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
5638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
5648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
5658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
5678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !sub.canManageSubscription(mContext, callingPackage)) {
5688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "No permissions: " + subscriptionId);
56931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
5708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
5718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
5728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            deleteSubscriptionPrivileged(sub.getIccId(), callbackIntent);
5748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
5758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
5768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
5778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
5788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
5798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent) {
5808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.deleteSubscription(
5818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
5828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.DeleteCommandCallback() {
5838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
58431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onDeleteComplete(int result) {
5858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
5868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
58731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
58831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
5898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
5908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                SubscriptionController.getInstance()
5918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        .requestEmbeddedSubscriptionInfoListRefresh();
5928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
59331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
59431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
5958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
5968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
59731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
5988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
5998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
6008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
6028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
6058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
60631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
6088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
6098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
6128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void switchToSubscription(int subscriptionId, String callingPackage,
6138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscription(
6158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent);
6168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage,
6198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
6208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
6218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
6228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
6248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
6258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final String iccid;
6268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
6278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch to "no" subscription. Only the system can do this.
6288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions) {
6298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to empty subscription");
63031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
6328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
6338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = null;
6348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            } else {
6358f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
6368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (sub == null) {
6378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Cannot switch to nonexistent subscription: " + subscriptionId);
63831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
6408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
6418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                if (!callerCanWriteEmbeddedSubscriptions
6428f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        && !sub.canManageSubscription(mContext, callingPackage)) {
6438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Log.e(TAG, "Not permitted to switch to subscription: " + subscriptionId);
64431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
6458f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    return;
6468f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
6478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid = sub.getIccId();
6488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (!callerCanWriteEmbeddedSubscriptions
6518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    && !canManageActiveSubscription(callingPackage)) {
6528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                // Switch needs consent.
6538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Intent extrasIntent = new Intent();
6548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                addResolutionIntent(extrasIntent,
6558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccService.ACTION_RESOLVE_NO_PRIVILEGES,
6569af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                        callingPackage,
6578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        EuiccOperation.forSwitchNoPrivileges(
6588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                token, subscriptionId, callingPackage));
6598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent);
6608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
6618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
6628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            switchToSubscriptionPrivileged(token, subscriptionId, iccid, forceDeactivateSim,
6648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    callingPackage, callbackIntent);
6658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
6668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
6678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
6718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            boolean forceDeactivateSim, final String callingPackage,
6728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
6738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        String iccid = null;
6748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
6758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (sub != null) {
6768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            iccid = sub.getIccId();
6778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
6788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        switchToSubscriptionPrivileged(callingToken, subscriptionId, iccid, forceDeactivateSim,
6798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                callingPackage, callbackIntent);
6808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
6818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
6828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId,
6838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage,
6848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            final PendingIntent callbackIntent) {
6858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.switchToSubscription(
6868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                iccid,
6878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                forceDeactivateSim,
6888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                new EuiccConnector.SwitchCommandCallback() {
6898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
69031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    public void onSwitchComplete(int result) {
6918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        Intent extrasIntent = new Intent();
6928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        final int resultCode;
69331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        switch (result) {
69431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_OK:
6958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = OK;
6968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
69731e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            case EuiccService.RESULT_MUST_DEACTIVATE_SIM:
6988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                resultCode = RESOLVABLE_ERROR;
6998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                addResolutionIntent(extrasIntent,
7008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM,
7019af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson                                        callingPackage,
7028f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccOperation.forSwitchDeactivateSim(
7038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                                callingToken, subscriptionId, callingPackage));
7048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
70531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            default:
70631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                resultCode = ERROR;
7078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                extrasIntent.putExtra(
7088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                        EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
70931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                        result);
7108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                break;
7118f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
7128f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        sendResult(callbackIntent, resultCode, extrasIntent);
7148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
7158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    @Override
7178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    public void onEuiccServiceUnavailable() {
71831e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
7208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                });
7218f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7228f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7238f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
7248f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void updateSubscriptionNickname(int subscriptionId, String nickname,
7258f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            PendingIntent callbackIntent) {
7268f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
7278f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
7288f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to update nickname");
7298f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7308f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
7318f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
7328f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId);
7338f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (sub == null) {
7348f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                Log.e(TAG, "Cannot update nickname to nonexistent subscription: " + subscriptionId);
73531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7368f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return;
7378f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
7388f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.updateSubscriptionNickname(
7398f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sub.getIccId(), nickname,
7408f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    new EuiccConnector.UpdateNicknameCommandCallback() {
7418f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
74231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        public void onUpdateNicknameComplete(int result) {
7438f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            Intent extrasIntent = new Intent();
7448f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            final int resultCode;
74531e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            switch (result) {
74631e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                case EuiccService.RESULT_OK:
7478f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    resultCode = OK;
7488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
74931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                default:
75031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    resultCode = ERROR;
7518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    extrasIntent.putExtra(
7528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                            EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
75331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                            result);
7548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    break;
7558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            }
7568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            sendResult(callbackIntent, resultCode, extrasIntent);
7588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
7598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        @Override
7618f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        public void onEuiccServiceUnavailable() {
76231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            sendResult(callbackIntent, ERROR, null /* extrasIntent */);
7638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                        }
7648f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    });
7658f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
7668f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
7678f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7688f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
7698f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7708f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Override
7718f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    public void eraseSubscriptions(PendingIntent callbackIntent) {
7728f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        if (!callerCanWriteEmbeddedSubscriptions()) {
7738f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            throw new SecurityException(
7748f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions");
7758f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
7768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        long token = Binder.clearCallingIdentity();
7778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        try {
7788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            mConnector.eraseSubscriptions(new EuiccConnector.EraseCommandCallback() {
7798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
78031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                public void onEraseComplete(int result) {
7818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    Intent extrasIntent = new Intent();
7828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    final int resultCode;
78331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    switch (result) {
78431e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        case EuiccService.RESULT_OK:
7858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            resultCode = OK;
786fe80f4088f1e04dd809d44547811279f26f47b28Jeff Davidson                            SubscriptionController.getInstance()
787fe80f4088f1e04dd809d44547811279f26f47b28Jeff Davidson                                    .requestEmbeddedSubscriptionInfoListRefresh();
7888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            break;
78931e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                        default:
79031e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                            resultCode = ERROR;
7918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            extrasIntent.putExtra(
7928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
79331e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                                    result);
7948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                            break;
7958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    }
7968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
7978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                    sendResult(callbackIntent, resultCode, extrasIntent);
7988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
7998f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8008f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                @Override
8018f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                public void onEuiccServiceUnavailable() {
80231e69b5efbc9b9a39183acce93a4c1b2e73b3006Jeff Davidson                    sendResult(callbackIntent, ERROR, null /* extrasIntent */);
8038f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                }
8048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            });
8058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        } finally {
8068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            Binder.restoreCallingIdentity(token);
8078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8108f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
811fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    /** Dispatch the given callback intent with the given result code and data. */
812fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
813fc59bf75ccaaa45fcf8b9895f219a01955b75413Jeff Davidson    public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) {
814277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
815277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            callbackIntent.send(mContext, resultCode, extrasIntent);
816277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (PendingIntent.CanceledException e) {
817277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            // Caller canceled the callback; do nothing.
818277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
819277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
820277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
821953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    /** Add a resolution intent to the given extras intent. */
822953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
823953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    public void addResolutionIntent(Intent extrasIntent, String resolutionAction,
8249af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson            String callingPackage, EuiccOperation op) {
825953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR);
826953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION,
827953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                resolutionAction);
8289af6424827eb9e023e037dd5aefd229235aceddbJeff Davidson        intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage);
829953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        intent.putExtra(EXTRA_OPERATION, op);
830953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        PendingIntent resolutionIntent = PendingIntent.getActivity(
831953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT);
832953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson        extrasIntent.putExtra(
833953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
834953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson    }
835953d76b6865b1f76c6fadbbd69898fe064b6c157Jeff Davidson
836277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Override
837277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
838277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
839277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        final long token = Binder.clearCallingIdentity();
840277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
841277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            mConnector.dump(fd, pw, args);
842277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } finally {
843277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Binder.restoreCallingIdentity(token);
844277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
845277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
846277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
847277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    @Nullable
8488f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) {
8498f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList();
8508f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int subCount = subs.size();
8518f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int i = 0; i < subCount; i++) {
8528f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo sub = subs.get(i);
8538f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subscriptionId == sub.getSubscriptionId()) {
8548f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return sub;
8558f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
8568f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
8578f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return null;
8588f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8598f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8608f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
861277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private String blockingGetEidFromEuiccService() {
8628f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
8638f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<String> eidRef = new AtomicReference<>();
864277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        mConnector.getEid(new EuiccConnector.GetEidCommandCallback() {
865277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
866277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onGetEidComplete(String eid) {
867277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                eidRef.set(eid);
868277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
869277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
870277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
871277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            @Override
872277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            public void onEuiccServiceUnavailable() {
873277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                latch.countDown();
874277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            }
875277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        });
8768f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, eidRef);
8778f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8788f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8798f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    @Nullable
8808f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private EuiccInfo blockingGetEuiccInfoFromEuiccService() {
8818f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        CountDownLatch latch = new CountDownLatch(1);
8828f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>();
8838f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        mConnector.getEuiccInfo(new EuiccConnector.GetEuiccInfoCommandCallback() {
8848f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
8858f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) {
8868f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                euiccInfoRef.set(euiccInfo);
8878f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
8888f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
8898f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8908f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            @Override
8918f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            public void onEuiccServiceUnavailable() {
8928f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                latch.countDown();
8938f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
8948f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        });
8958f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return awaitResult(latch, euiccInfoRef);
8968f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
8978f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
8988f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) {
899277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        try {
900277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            latch.await();
901277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        } catch (InterruptedException e) {
902277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson            Thread.currentThread().interrupt();
903277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        }
9048f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return resultRef.get();
9058f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    }
9068f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson
9078f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson    private boolean canManageActiveSubscription(String callingPackage) {
9088f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
9098f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
91027590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        if (subInfoList == null) {
91127590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson            return false;
91227590b4156bff85bcd8b68536216526d2dd029c7Jeff Davidson        }
9138f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        int size = subInfoList.size();
9148f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        for (int subIndex = 0; subIndex < size; subIndex++) {
9158f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            SubscriptionInfo subInfo = subInfoList.get(subIndex);
9168f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            if (subInfo.isEmbedded() && subInfo.canManageSubscription(mContext, callingPackage)) {
9178f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson                return true;
9188f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson            }
9198f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        }
9208f32416b4c5f5657e7ccf3a1ee031598a0203fd9Jeff Davidson        return false;
921277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
922277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
923277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanReadPhoneStatePrivileged() {
924277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
925277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
926277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
927277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
928277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerCanWriteEmbeddedSubscriptions() {
929277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
930277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                == PackageManager.PERMISSION_GRANTED;
931277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
932277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson
933277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    /**
934277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC.
935277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson     */
936277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    private boolean callerHasCarrierPrivilegesForActiveSubscription() {
937277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices.
938277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        TelephonyManager tm =
939277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
940277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson        return tm.hasCarrierPrivileges();
941277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson    }
942277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson}
943