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