Merge "Squashed merge of master-sim into master."
diff --git a/Android.mk b/Android.mk
index 08ef6f5..4fbe094 100644
--- a/Android.mk
+++ b/Android.mk
@@ -278,6 +278,10 @@
core/java/android/service/carrier/ICarrierService.aidl \
core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
core/java/android/service/carrier/ICarrierMessagingService.aidl \
+ core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl \
+ core/java/android/service/euicc/IEuiccService.aidl \
+ core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl \
+ core/java/android/service/euicc/IGetEidCallback.aidl \
core/java/android/service/gatekeeper/IGateKeeperService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
@@ -518,6 +522,7 @@
telephony/java/com/android/internal/telephony/ITelephony.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+ telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl \
wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl \
@@ -614,6 +619,8 @@
frameworks/base/telephony/java/android/telephony/IccOpenLogicalChannelResponse.aidl \
frameworks/base/telephony/java/android/telephony/NeighboringCellInfo.aidl \
frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
+ frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
+ frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/location/java/android/location/Address.aidl \
frameworks/base/location/java/android/location/Criteria.aidl \
@@ -726,6 +733,8 @@
frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
frameworks/base/core/java/android/service/carrier/CarrierIdentifier.aidl \
frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \
+ frameworks/base/core/java/android/service/euicc/DownloadResult.aidl \
+ frameworks/base/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl \
frameworks/base/core/java/android/service/notification/Adjustment.aidl \
frameworks/base/core/java/android/service/notification/Condition.aidl \
frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9b349dd..4c217de 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -118,6 +118,7 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.telephony.euicc.EuiccManager;
import android.view.autofill.AutofillManager;
import android.view.autofill.IAutoFillManager;
import android.service.persistentdata.IPersistentDataBlockService;
@@ -493,6 +494,13 @@
return new TelecomManager(ctx.getOuterContext());
}});
+ registerService(Context.EUICC_SERVICE, EuiccManager.class,
+ new CachedServiceFetcher<EuiccManager>() {
+ @Override
+ public EuiccManager createService(ContextImpl ctx) {
+ return new EuiccManager(ctx.getOuterContext());
+ }});
+
registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
new CachedServiceFetcher<UiModeManager>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dbbfe30..aa2adc7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3455,6 +3455,17 @@
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.telephony.euicc.EuiccManager} to manage the device eUICC (embedded SIM).
+ *
+ * @see #getSystemService
+ * @see android.telephony.euicc.EuiccManager
+ * TODO(b/35851809): Unhide this API.
+ * @hide
+ */
+ public static final String EUICC_SERVICE = "euicc_service";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.text.ClipboardManager} for accessing and modifying
* {@link android.content.ClipboardManager} for accessing and modifying
* the contents of the global clipboard.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 136c13b..17cb027 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1958,6 +1958,15 @@
"android.hardware.telephony.carrierlock";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * supports embedded subscriptions on eUICCs.
+ * TODO(b/35851809): Make this public.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports connecting to USB devices
* as the USB host.
diff --git a/core/java/android/service/euicc/DownloadResult.aidl b/core/java/android/service/euicc/DownloadResult.aidl
new file mode 100644
index 0000000..66ec999
--- /dev/null
+++ b/core/java/android/service/euicc/DownloadResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable DownloadResult;
diff --git a/core/java/android/service/euicc/DownloadResult.java b/core/java/android/service/euicc/DownloadResult.java
new file mode 100644
index 0000000..0aa55fb
--- /dev/null
+++ b/core/java/android/service/euicc/DownloadResult.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#downloadSubscription} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class DownloadResult implements Parcelable {
+
+ public static final Creator<DownloadResult> CREATOR = new Creator<DownloadResult>() {
+ @Override
+ public DownloadResult createFromParcel(Parcel in) {
+ return new DownloadResult(in);
+ }
+
+ @Override
+ public DownloadResult[] newArray(int size) {
+ return new DownloadResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ RESULT_MUST_DEACTIVATE_REMOVABLE_SIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+ public static final int RESULT_MUST_DEACTIVATE_REMOVABLE_SIM = 2;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private DownloadResult(int result, int detailedCode) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ }
+
+ private DownloadResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the download was successful. */
+ public static DownloadResult success() {
+ return new DownloadResult(RESULT_OK, 0);
+ }
+
+ /**
+ * Return a result indicating that the removable SIM must be deactivated to perform the
+ * operation.
+ */
+ public static DownloadResult mustDeactivateRemovableSim() {
+ return new DownloadResult(RESULT_MUST_DEACTIVATE_REMOVABLE_SIM, 0);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implemenation-defined detailed error code for debugging purposes.
+ */
+ public static DownloadResult genericError(int detailedCode) {
+ return new DownloadResult(RESULT_GENERIC_ERROR, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
new file mode 100644
index 0000000..6407507
--- /dev/null
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.CallSuper;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.euicc.DownloadableSubscription;
+
+/**
+ * Service interface linking the system with an eUICC local profile assistant (LPA) application.
+ *
+ * <p>An LPA consists of two separate components (which may both be implemented in the same APK):
+ * the LPA backend, and the LPA UI or LUI.
+ *
+ * <p>To implement the LPA backend, you must extend this class and declare this service in your
+ * manifest file. The service must require the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission and include an intent filter
+ * with the {@link #EUICC_SERVICE_INTERFACE} action. The priority of the intent filter must be set
+ * to a non-zero value in case multiple implementations are present on the device. For example:
+ *
+ * <pre>{@code
+ * <service android:name=".MyEuiccService"
+ * android:permission="android.permission.BIND_EUICC_SERVICE">
+ * <intent-filter android:priority="100">
+ * <action android:name="android.service.euicc.EuiccService" />
+ * </intent-filter>
+ * </service>
+ * }</pre>
+ *
+ * <p>To implement the LUI, you must provide an activity for the following actions:
+ *
+ * <ul>
+ * <li>{@link #ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS}
+ * <li>{@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION}
+ * </ul>
+ *
+ * <p>As with the service, each activity must require the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission. Each should have an intent
+ * filter with the appropriate action, the {@link #CATEGORY_EUICC_UI} category, and a non-zero
+ * priority.
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ * @hide
+ */
+public abstract class EuiccService extends Service {
+ /** Action which must be included in this service's intent filter. */
+ public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
+
+ /** Category which must be defined to all UI actions, for efficient lookup. */
+ public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
+
+ // LUI actions. These are passthroughs of the corresponding EuiccManager actions.
+
+ /** @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS */
+ public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
+ "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+ /** @see android.telephony.euicc.EuiccManager#ACTION_PROVISION_EMBEDDED_SUBSCRIPTION */
+ public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
+ "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+
+ private final IEuiccService.Stub mStubWrapper;
+
+ public EuiccService() {
+ mStubWrapper = new IEuiccServiceWrapper();
+ }
+
+ /**
+ * If overriding this method, call through to the super method for any unknown actions.
+ * {@inheritDoc}
+ */
+ @Override
+ @CallSuper
+ public IBinder onBind(Intent intent) {
+ return mStubWrapper;
+ }
+
+ /**
+ * Return the EID of the eUICC.
+ *
+ * @param slotId ID of the SIM slot being queried. This is currently not populated but is here
+ * to future-proof the APIs.
+ * @return the EID.
+ * @see android.telephony.euicc.EuiccManager#getEid
+ */
+ // TODO(b/36260308): Update doc when we have multi-SIM support.
+ public abstract String onGetEid(int slotId);
+
+ /**
+ * Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
+ *
+ * @param slotId ID of the SIM slot to use when starting the download. This is currently not
+ * populated but is here to future-proof the APIs.
+ * @param subscription A subscription whose metadata needs to be populated.
+ * @return The result of the operation.
+ * @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata
+ */
+ public abstract GetDownloadableSubscriptionMetadataResult getDownloadableSubscriptionMetadata(
+ int slotId, DownloadableSubscription subscription);
+
+ /**
+ * Download the given subscription.
+ *
+ * @param slotId ID of the SIM slot onto which the subscription should be downloaded. This is
+ * currently not populated but is here to future-proof the APIs.
+ * @param subscription The subscription to download.
+ * @param switchAfterDownload If true, the subscription should be enabled upon successful
+ * download.
+ * @return the result of the download operation.
+ * @see android.telephony.euicc.EuiccManager#downloadSubscription
+ */
+ public abstract DownloadResult downloadSubscription(int slotId,
+ DownloadableSubscription subscription, boolean switchAfterDownload);
+
+ /**
+ * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}.
+ */
+ private class IEuiccServiceWrapper extends IEuiccService.Stub {
+ @Override
+ public void downloadSubscription(int slotId, DownloadableSubscription subscription,
+ boolean switchAfterDownload, IDownloadSubscriptionCallback callback) {
+ DownloadResult result = EuiccService.this.downloadSubscription(
+ slotId, subscription, switchAfterDownload);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void getEid(int slotId, IGetEidCallback callback) {
+ String eid = EuiccService.this.onGetEid(slotId);
+ try {
+ callback.onSuccess(eid);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void getDownloadableSubscriptionMetadata(int slotId,
+ DownloadableSubscription subscription,
+ IGetDownloadableSubscriptionMetadataCallback callback) {
+ GetDownloadableSubscriptionMetadataResult result =
+ EuiccService.this.getDownloadableSubscriptionMetadata(slotId, subscription);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
new file mode 100644
index 0000000..791ad9b
--- /dev/null
+++ b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable GetDownloadableSubscriptionMetadataResult;
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
new file mode 100644
index 0000000..b7f46fa
--- /dev/null
+++ b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.euicc.DownloadableSubscription;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#getDownloadableSubscriptionMetadata} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class GetDownloadableSubscriptionMetadataResult implements Parcelable {
+
+ public static final Creator<GetDownloadableSubscriptionMetadataResult> CREATOR =
+ new Creator<GetDownloadableSubscriptionMetadataResult>() {
+ @Override
+ public GetDownloadableSubscriptionMetadataResult createFromParcel(Parcel in) {
+ return new GetDownloadableSubscriptionMetadataResult(in);
+ }
+
+ @Override
+ public GetDownloadableSubscriptionMetadataResult[] newArray(int size) {
+ return new GetDownloadableSubscriptionMetadataResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ RESULT_MUST_DEACTIVATE_REMOVABLE_SIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_MUST_DEACTIVATE_REMOVABLE_SIM = 1;
+ public static final int RESULT_GENERIC_ERROR = 2;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /**
+ * The {@link DownloadableSubscription} with filled-in metadata.
+ *
+ * <p>Only non-null if {@link #result} is {@link #RESULT_OK}.
+ */
+ @Nullable
+ public final DownloadableSubscription subscription;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private GetDownloadableSubscriptionMetadataResult(int result,
+ @Nullable DownloadableSubscription subscription, int detailedCode) {
+ this.result = result;
+ this.subscription = subscription;
+ this.detailedCode = detailedCode;
+ }
+
+ private GetDownloadableSubscriptionMetadataResult(Parcel in) {
+ this.result = in.readInt();
+ this.subscription = DownloadableSubscription.CREATOR.createFromParcel(in);
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ this.subscription.writeToParcel(dest, 0);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the download was successful. */
+ public static GetDownloadableSubscriptionMetadataResult success(
+ DownloadableSubscription subscription) {
+ return new GetDownloadableSubscriptionMetadataResult(RESULT_OK, subscription,
+ 0 /* detailedCode */);
+ }
+
+ /**
+ * Return a result indicating that the removable SIM must be deactivated to perform the
+ * operation.
+ */
+ public static GetDownloadableSubscriptionMetadataResult mustDeactivateRemovableSim() {
+ return new GetDownloadableSubscriptionMetadataResult(RESULT_MUST_DEACTIVATE_REMOVABLE_SIM,
+ null /* subscription */, 0 /* detailedCode */);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implementation-defined detailed error code for debugging purposes.
+ */
+ public static GetDownloadableSubscriptionMetadataResult genericError(int detailedCode) {
+ return new GetDownloadableSubscriptionMetadataResult(RESULT_GENERIC_ERROR,
+ null /* subscription */, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl b/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
new file mode 100644
index 0000000..0677cbe
--- /dev/null
+++ b/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.DownloadResult;
+
+/** @hide */
+oneway interface IDownloadSubscriptionCallback {
+ void onComplete(in DownloadResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl
new file mode 100644
index 0000000..58fe262
--- /dev/null
+++ b/core/java/android/service/euicc/IEuiccService.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.IDownloadSubscriptionCallback;
+import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
+import android.service.euicc.IGetEidCallback;
+import android.telephony.euicc.DownloadableSubscription;
+
+/** @hide */
+oneway interface IEuiccService {
+ void downloadSubscription(int slotId, in DownloadableSubscription subscription,
+ boolean switchAfterDownload, in IDownloadSubscriptionCallback callback);
+ void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription,
+ in IGetDownloadableSubscriptionMetadataCallback callback);
+ void getEid(int slotId, in IGetEidCallback callback);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl b/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
new file mode 100644
index 0000000..3353061
--- /dev/null
+++ b/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.GetDownloadableSubscriptionMetadataResult;
+
+/** @hide */
+oneway interface IGetDownloadableSubscriptionMetadataCallback {
+ void onComplete(in GetDownloadableSubscriptionMetadataResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IGetEidCallback.aidl b/core/java/android/service/euicc/IGetEidCallback.aidl
new file mode 100644
index 0000000..35ee9c2
--- /dev/null
+++ b/core/java/android/service/euicc/IGetEidCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+/** @hide */
+oneway interface IGetEidCallback {
+ void onSuccess(String eid);
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index faaca53..48a460d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1644,6 +1644,21 @@
<permission android:name="android.permission.BIND_IMS_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
+ EuiccManager APIs.
+ <p>Protection level: signature|privileged|development
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+ android:protectionLevel="signature|privileged|development" />
+
+ <!-- Must be required by an EuiccService to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ TODO(b/35851809): Mark this as a SystemApi.
+ @hide -->
+ <permission android:name="android.permission.BIND_EUICC_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
diff --git a/telephony/java/android/telephony/UiccAccessRule.aidl b/telephony/java/android/telephony/UiccAccessRule.aidl
new file mode 100644
index 0000000..f923c45
--- /dev/null
+++ b/telephony/java/android/telephony/UiccAccessRule.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable UiccAccessRule;
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
new file mode 100644
index 0000000..1ac4c5c
--- /dev/null
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.pm.PackageInfo;
+import android.content.pm.Signature;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * Describes a single UICC access rule according to the GlobalPlatform Secure Element Access Control
+ * specification.
+ *
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class UiccAccessRule implements Parcelable {
+ private static final String TAG = "UiccAccessRule";
+
+ private static final int ENCODING_VERSION = 1;
+
+ public static final Creator<UiccAccessRule> CREATOR = new Creator<UiccAccessRule>() {
+ @Override
+ public UiccAccessRule createFromParcel(Parcel in) {
+ return new UiccAccessRule(in);
+ }
+
+ @Override
+ public UiccAccessRule[] newArray(int size) {
+ return new UiccAccessRule[size];
+ }
+ };
+
+ /**
+ * Encode these access rules as a byte array which can be parsed with {@link #decodeRules}.
+ * @hide
+ */
+ public static byte[] encodeRules(UiccAccessRule[] accessRules) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream output = new DataOutputStream(baos);
+ output.writeInt(ENCODING_VERSION);
+ output.writeInt(accessRules.length);
+ for (UiccAccessRule accessRule : accessRules) {
+ output.writeInt(accessRule.mCertificateHash.length);
+ output.write(accessRule.mCertificateHash);
+ output.writeUTF(accessRule.mPackageName);
+ output.writeLong(accessRule.mAccessType);
+ }
+ output.close();
+ return baos.toByteArray();
+ } catch (IOException e) {
+ throw new IllegalStateException(
+ "ByteArrayOutputStream should never lead to an IOException", e);
+ }
+ }
+
+ /**
+ * Decodes a byte array generated with {@link #encodeRules}.
+ * @hide
+ */
+ public static UiccAccessRule[] decodeRules(byte[] encodedRules) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedRules);
+ try (DataInputStream input = new DataInputStream(bais)) {
+ input.readInt(); // version; currently ignored
+ int count = input.readInt();
+ UiccAccessRule[] accessRules = new UiccAccessRule[count];
+ for (int i = 0; i < count; i++) {
+ int certificateHashLength = input.readInt();
+ byte[] certificateHash = new byte[certificateHashLength];
+ input.readFully(certificateHash);
+ String packageName = input.readUTF();
+ long accessType = input.readLong();
+ accessRules[i] = new UiccAccessRule(certificateHash, packageName, accessType);
+ }
+ input.close();
+ return accessRules;
+ } catch (IOException e) {
+ throw new IllegalStateException(
+ "ByteArrayInputStream should never lead to an IOException", e);
+ }
+ }
+
+ private final byte[] mCertificateHash;
+ private final @Nullable String mPackageName;
+ // This bit is not currently used, but reserved for future use.
+ private final long mAccessType;
+
+ public UiccAccessRule(byte[] certificateHash, @Nullable String packageName, long accessType) {
+ this.mCertificateHash = certificateHash;
+ this.mPackageName = packageName;
+ this.mAccessType = accessType;
+ }
+
+ UiccAccessRule(Parcel in) {
+ mCertificateHash = in.createByteArray();
+ mPackageName = in.readString();
+ mAccessType = in.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(mCertificateHash);
+ dest.writeString(mPackageName);
+ dest.writeLong(mAccessType);
+ }
+
+ /**
+ * Return the package name this rule applies to.
+ *
+ * @return the package name, or null if this rule applies to any package signed with the given
+ * certificate.
+ */
+ public @Nullable String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the carrier privilege status associated with the given package.
+ *
+ * @param packageInfo package info fetched from
+ * {@link android.content.pm.PackageManager#getPackageInfo}.
+ * {@link android.content.pm.PackageManager#GET_SIGNATURES} must have been passed in.
+ * @return either {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_HAS_ACCESS} or
+ * {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_NO_ACCESS}.
+ */
+ public int getCarrierPrivilegeStatus(PackageInfo packageInfo) {
+ if (packageInfo.signatures == null || packageInfo.signatures.length == 0) {
+ throw new IllegalArgumentException(
+ "Must use GET_SIGNATURES when looking up package info");
+ }
+
+ for (Signature sig : packageInfo.signatures) {
+ int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName);
+ if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
+ return accessStatus;
+ }
+ }
+
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+
+ /**
+ * Returns the carrier privilege status for the given certificate and package name.
+ *
+ * @param signature The signature of the certificate.
+ * @param packageName name of the package.
+ * @return either {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_HAS_ACCESS} or
+ * {@link TelephonyManager#CARRIER_PRIVILEGE_STATUS_NO_ACCESS}.
+ */
+ public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
+ // SHA-1 is for backward compatible support only, strongly discouraged for new use.
+ byte[] certHash = getCertHash(signature, "SHA-1");
+ byte[] certHash256 = getCertHash(signature, "SHA-256");
+ if (matches(certHash, packageName) || matches(certHash256, packageName)) {
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ }
+
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+
+ private boolean matches(byte[] certHash, String packageName) {
+ return certHash != null && Arrays.equals(this.mCertificateHash, certHash) &&
+ (TextUtils.isEmpty(this.mPackageName) || this.mPackageName.equals(packageName));
+ }
+
+ @Override
+ public String toString() {
+ return "cert: " + IccUtils.bytesToHexString(mCertificateHash) + " pkg: " +
+ mPackageName + " access: " + mAccessType;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Converts a Signature into a Certificate hash usable for comparison.
+ */
+ private static byte[] getCertHash(Signature signature, String algo) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(algo);
+ return md.digest(signature.toByteArray());
+ } catch (NoSuchAlgorithmException ex) {
+ Rlog.e(TAG, "NoSuchAlgorithmException: " + ex);
+ }
+ return null;
+ }
+}
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl b/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl
new file mode 100644
index 0000000..26679c9
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.euicc;
+
+parcelable DownloadableSubscription;
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
new file mode 100644
index 0000000..e880978
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Information about a subscription which is available for download.
+ *
+ * TODO(b/35851809): Make this public.
+ * @hide
+ */
+public final class DownloadableSubscription implements Parcelable {
+
+ public static final Creator<DownloadableSubscription> CREATOR =
+ new Creator<DownloadableSubscription>() {
+ @Override
+ public DownloadableSubscription createFromParcel(Parcel in) {
+ return new DownloadableSubscription(in);
+ }
+
+ @Override
+ public DownloadableSubscription[] newArray(int size) {
+ return new DownloadableSubscription[size];
+ }
+ };
+
+ /**
+ * Activation code. May be null for subscriptions which are not based on activation codes, e.g.
+ * to download a default subscription assigned to this device.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ @Nullable
+ public final String encodedActivationCode;
+
+ // see getCarrierName and setCarrierName
+ @Nullable
+ private String carrierName;
+ // see isConsentGranted and setConsentGranted
+ private boolean consentGranted;
+
+ /** @hide */
+ private DownloadableSubscription(String encodedActivationCode) {
+ this.encodedActivationCode = encodedActivationCode;
+ }
+
+ private DownloadableSubscription(Parcel in) {
+ encodedActivationCode = in.readString();
+ carrierName = in.readString();
+ consentGranted = in.readInt() == 1;
+ }
+
+ /**
+ * Create a DownloadableSubscription for the given activation code.
+ *
+ * @param encodedActivationCode the activation code to use. Must not be null.
+ * @return the {@link DownloadableSubscription} which may be passed to
+ * {@link EuiccManager#downloadSubscription}.
+ */
+ public static DownloadableSubscription forActivationCode(String encodedActivationCode) {
+ Preconditions.checkNotNull(encodedActivationCode, "Activation code may not be null");
+ return new DownloadableSubscription(encodedActivationCode);
+ }
+
+ /**
+ * Set the user-visible carrier name.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public void setCarrierName(String carrierName) {
+ this.carrierName = carrierName;
+ }
+
+ /**
+ * Returns the user-visible carrier name.
+ *
+ * <p>Only present for downloadable subscriptions that were queried from a server (as opposed to
+ * those created with {@link #forActivationCode}). May be populated with
+ * {@link EuiccManager#getDownloadableSubscriptionMetadata}.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ @Nullable
+ public String getCarrierName() {
+ return this.carrierName;
+ }
+
+
+ /**
+ * Mark this download as being consented to by the user.
+ * @hide
+ */
+ public void setConsentGranted() {
+ this.consentGranted = true;
+ }
+
+ /**
+ * Returns whether the user has granted consent to download this subscription.
+ *
+ * <p>The {@link android.service.euicc.EuiccService} implementation should permit a subscription
+ * download if this is set, even if the calling app doesn't have permission to download it.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public boolean isConsentGranted() {
+ return this.consentGranted;
+ }
+
+ /**
+ * Unset any untrusted fields.
+ *
+ * <p>Should be called by the platform whenever an instance is received from an untrusted
+ * source to reset any secure fields that may only be set by the platform.
+ * @hide
+ */
+ public final void clearUntrustedFields() {
+ this.consentGranted = false;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(encodedActivationCode);
+ dest.writeString(carrierName);
+ dest.writeInt(consentGranted ? 1 : 0);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
new file mode 100644
index 0000000..73cf162
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.euicc.IEuiccController;
+
+/**
+ * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
+ *
+ * <p>You do not instantiate this class directly; instead, you retrieve an instance through
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ *
+ * <p>See {@link #isEnabled} before attempting to use these APIs.
+ *
+ * TODO(b/35851809): Make this public.
+ * @hide
+ */
+public class EuiccManager {
+
+ /**
+ * Intent action to launch the embedded SIM (eUICC) management settings screen.
+ *
+ * <p>This screen shows a list of embedded profiles and offers the user the ability to switch
+ * between them, download new profiles, and delete unused profiles.
+ *
+ * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if
+ * {@link #isEnabled} is false.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS =
+ "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
+
+ /**
+ * Intent action to provision an embedded subscription.
+ *
+ * <p>May be called during device provisioning to launch a screen to perform embedded SIM
+ * provisioning, e.g. if no physical SIM is present and the user elects to configure their
+ * embedded SIM.
+ *
+ * <p>The activity will immediately finish with {@link android.app.Activity#RESULT_CANCELED} if
+ * {@link #isEnabled} is false or if the device is already provisioned.
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
+ "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
+
+ /**
+ * Result code for an operation indicating that the operation succeeded.
+ */
+ public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
+
+ /**
+ * Result code for an operation indicating that the user must take some action before the
+ * operation can continue.
+ *
+ * @see #startResolutionActivity
+ */
+ public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1;
+
+ /**
+ * Result code for an operation indicating that a generic error occurred.
+ *
+ * <p>Note that in the future, other result codes may be returned indicating more specific
+ * errors. Thus, the caller should check for {@link #EMBEDDED_SUBSCRIPTION_RESULT_OK} or
+ * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} to determine if the operation
+ * succeeded or failed with a user-resolvable error, and assume the operation failed for any
+ * other result, rather than checking for this specific value.
+ */
+ public static final int EMBEDDED_SUBSCRIPTION_RESULT_GENERIC_ERROR = 2;
+
+ /**
+ * Key for an extra set on {@link PendingIntent} result callbacks providing a detailed result
+ * code.
+ *
+ * <p>This code is an implementation detail of the embedded subscription manager and is only
+ * intended for logging or debugging purposes.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
+
+ /**
+ * The key for an extra set on {@link #getDownloadableSubscriptionMetadata} PendingIntent result
+ * callbacks providing the downloadable subscription metadata.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+
+ private final Context mContext;
+ private final IEuiccController mController;
+
+ /** @hide */
+ public EuiccManager(Context context) {
+ mContext = context;
+ mController = IEuiccController.Stub.asInterface(ServiceManager.getService("econtroller"));
+ }
+
+ /**
+ * Whether embedded subscriptions are currently enabled.
+ *
+ * <p>Even on devices with the {@link PackageManager#FEATURE_TELEPHONY_EUICC} feature, embedded
+ * subscriptions may be turned off, e.g. because of a carrier restriction from an inserted
+ * physical SIM. Therefore, this runtime check should be used before accessing embedded
+ * subscription APIs.
+ *
+ * @return true if embedded subscriptions are currently enabled.
+ */
+ public boolean isEnabled() {
+ // In the future, this may reach out to IEuiccController (if non-null) to check any dynamic
+ // restrictions.
+ return mController != null;
+ }
+
+ /**
+ * Returns the EID identifying the eUICC hardware.
+ *
+ * <p>Requires that the calling app has carrier privileges on the active subscription on the
+ * eUICC.
+ *
+ * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
+ */
+ @Nullable
+ public String getEid() {
+ if (!isEnabled()) {
+ return null;
+ }
+ try {
+ return mController.getEid();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Attempt to download the given {@link DownloadableSubscription}.
+ *
+ * <p>Requires the calling app to be authorized to manage both the currently-active subscription
+ * and the subscription to be downloaded according to the subscription metadata. Without the
+ * former, a {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the
+ * callback intent to prompt the user to accept the download.
+ *
+ * @param subscription the subscription to download.
+ * @param switchAfterDownload if true, the profile will be activated upon successful download.
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ */
+ public void downloadSubscription(DownloadableSubscription subscription,
+ boolean switchAfterDownload, PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.downloadSubscription(subscription, switchAfterDownload, callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Start an activity to resolve a user-resolvable error.
+ *
+ * <p>If an operation returns {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}, this
+ * method may be called to prompt the user to resolve the issue.
+ *
+ * @param activity the calling activity (which should be in the foreground).
+ * @param requestCode an application-specific request code which will be provided to
+ * {@link Activity#onActivityResult} upon completion. Note that the operation may still be
+ * in progress when the resolution activity completes; it is not fully finished until the
+ * callback intent is triggered.
+ * @param resultIntent the Intent provided to the initial callback intent which failed with
+ * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}.
+ * @param callbackIntent a PendingIntent to launch when the operation completes. This is
+ * trigered upon completion of the original operation that required user resolution.
+ */
+ public void startResolutionActivity(Activity activity, int requestCode, Intent resultIntent,
+ PendingIntent callbackIntent) {
+ // TODO(b/33075886): Implement this API.
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /**
+ * Fills in the metadata for a DownloadableSubscription.
+ *
+ * <p>May be used in cases that a DownloadableSubscription was constructed to download a
+ * profile, but the metadata for the profile is unknown (e.g. we only know the activation code).
+ * The callback will be triggered with an Intent with
+ * {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION} set to the
+ * downloadable subscription metadata upon success.
+ *
+ * <p>Requires that the calling app has the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
+ * internal system use only.
+ *
+ * @param subscription the subscription which needs metadata filled in
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ @SystemApi
+ public void getDownloadableSubscriptionMetadata(
+ DownloadableSubscription subscription, PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.getDownloadableSubscriptionMetadata(subscription, callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static void sendUnavailableError(PendingIntent callbackIntent) {
+ try {
+ callbackIntent.send(EMBEDDED_SUBSCRIPTION_RESULT_GENERIC_ERROR);
+ } catch (PendingIntent.CanceledException e) {
+ // Caller canceled the callback; do nothing.
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
new file mode 100644
index 0000000..b2092bb
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.euicc;
+
+import android.app.PendingIntent;
+import android.telephony.euicc.DownloadableSubscription;
+
+/** @hide */
+interface IEuiccController {
+ oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+ in PendingIntent callbackIntent);
+ String getEid();
+ oneway void downloadSubscription(in DownloadableSubscription subscription,
+ boolean switchAfterDownload, in PendingIntent callbackIntent);
+}
\ No newline at end of file