Merge "Add TelephonyManager test hidden API for testing"
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 42725c5..e0467df 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -154,6 +154,7 @@
      * @param tag Debugging tag for dumps associated with this job (instead of the service class)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
     public abstract @Result int scheduleAsPackage(@NonNull JobInfo job, @NonNull String packageName,
@@ -196,6 +197,7 @@
      * Returns a list of all currently-executing jobs.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract List<JobInfo> getStartedJobs();
 
     /**
@@ -205,5 +207,6 @@
      * <p class="note">This is a slow operation, so it should be called sparingly.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract List<JobSnapshot> getAllJobSnapshots();
 }
\ No newline at end of file
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index ede8852..f13861e 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -35,7 +35,7 @@
     prebuilts: ["com.android.os.statsd.init.rc"],
     name: "com.android.os.statsd-defaults",
     updatable: true,
-    min_sdk_version: "R",
+    min_sdk_version: "30",
     key: "com.android.os.statsd.key",
     certificate: ":com.android.os.statsd.certificate",
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9a06867..a21a156 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -103,7 +103,6 @@
 public final class LoadedApk {
     static final String TAG = "LoadedApk";
     static final boolean DEBUG = false;
-    private static final String PROPERTY_NAME_APPEND_NATIVE = "pi.append_native_lib_paths";
 
     @UnsupportedAppUsage
     private final ActivityThread mActivityThread;
@@ -909,7 +908,7 @@
             needToSetupJitProfiles = true;
         }
 
-        if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
+        if (!libPaths.isEmpty()) {
             // Temporarily disable logging of disk reads on the Looper thread as this is necessary
             StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
             try {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a941756..a6089c3 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -835,6 +835,7 @@
     }
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     protected abstract IContentProvider acquireProvider(Context c, String name);
 
@@ -851,15 +852,19 @@
     }
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean releaseProvider(IContentProvider icp);
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean releaseUnstableProvider(IContentProvider icp);
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void unstableProviderDied(IContentProvider icp);
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a98bd6a..7ffcead 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -800,6 +800,7 @@
      * case {@link #getOpPackageName()} will be the name of the primary package in
      * that process (so that app ops uid verification will work with the name).
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract String getBasePackageName();
 
@@ -916,6 +917,7 @@
      * @see #MODE_PRIVATE
      * @removed
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract SharedPreferences getSharedPreferences(File file, @PreferencesMode int mode);
 
     /**
@@ -946,6 +948,7 @@
     public abstract boolean deleteSharedPreferences(String name);
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void reloadSharedPreferences();
 
     /**
@@ -1034,6 +1037,7 @@
      * @see #getSharedPreferences(String, int)
      * @removed
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract File getSharedPreferencesPath(String name);
 
     /**
@@ -1505,6 +1509,7 @@
      * There is no guarantee when these files will be deleted.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @SystemApi
     public abstract File getPreloadsFileCache();
@@ -2173,6 +2178,7 @@
      * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
             String[] receiverPermissions);
 
@@ -2203,6 +2209,7 @@
      * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void sendBroadcast(Intent intent,
             @Nullable String receiverPermission,
@@ -2213,6 +2220,7 @@
      * of an associated app op as per {@link android.app.AppOpsManager}.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void sendBroadcast(Intent intent,
             String receiverPermission, int appOp);
@@ -2328,6 +2336,7 @@
      * @see android.app.Activity#RESULT_OK
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void sendOrderedBroadcast(@NonNull Intent intent,
             @Nullable String receiverPermission, @Nullable Bundle options,
@@ -2340,6 +2349,7 @@
      * of an associated app op as per {@link android.app.AppOpsManager}.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void sendOrderedBroadcast(Intent intent,
             String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
@@ -2393,6 +2403,7 @@
      * @see #sendBroadcast(Intent, String, Bundle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
@@ -2415,6 +2426,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
@@ -2461,6 +2473,7 @@
      *       BroadcastReceiver, Handler, int, String, Bundle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@@ -2474,6 +2487,7 @@
      *       BroadcastReceiver, Handler, int, String, Bundle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage
     public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@@ -2688,6 +2702,7 @@
      * @hide
      * This is just here for sending CONNECTIVITY_ACTION.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @RequiresPermission(allOf = {
             android.Manifest.permission.INTERACT_ACROSS_USERS,
@@ -2978,6 +2993,7 @@
      * @see #sendBroadcast
      * @see #unregisterReceiver
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
     @UnsupportedAppUsage
@@ -3088,6 +3104,7 @@
     /**
      * @hide like {@link #startForegroundService(Intent)} but for a specific user.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     public abstract ComponentName startForegroundServiceAsUser(Intent service, UserHandle user);
@@ -3126,6 +3143,7 @@
     /**
      * @hide like {@link #startService(Intent)} but for a specific user.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage
@@ -3134,6 +3152,7 @@
     /**
      * @hide like {@link #stopService(Intent)} but for a specific user.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
 
@@ -5190,6 +5209,7 @@
     public abstract int checkPermission(@NonNull String permission, int pid, int uid);
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @PackageManager.PermissionResult
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract int checkPermission(@NonNull String permission, int pid, int uid,
@@ -5417,6 +5437,7 @@
             @Intent.AccessUriMode int modeFlags);
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @PackageManager.PermissionResult
     public abstract int checkUriPermission(Uri uri, int pid, int uid,
             @Intent.AccessUriMode int modeFlags, IBinder callerToken);
@@ -5701,6 +5722,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract Context createApplicationContext(ApplicationInfo application,
             @CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;
@@ -5920,6 +5942,7 @@
      * @see #isCredentialProtectedStorage()
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract Context createCredentialProtectedStorageContext();
 
@@ -5932,6 +5955,7 @@
      * @return The compatibility info holder, or null if not required by the application.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
 
     /**
@@ -5966,12 +5990,14 @@
      * @see #getDisplay()
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @TestApi
     public abstract int getDisplayId();
 
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void updateDisplay(int displayId);
 
     /**
@@ -6000,6 +6026,7 @@
      * @see #createCredentialProtectedStorageContext()
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract boolean isCredentialProtectedStorage();
 
@@ -6007,6 +6034,7 @@
      * Returns true if the context can load unsafe resources, e.g. fonts.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract boolean canLoadUnsafeResources();
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6648259..74463fd 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3796,6 +3796,7 @@
      *             found on the system.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage
     public abstract PackageInfo getPackageInfoAsUser(@NonNull String packageName,
@@ -3862,6 +3863,7 @@
      *         does not contain such an activity.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract @Nullable Intent getCarLaunchIntentForPackage(@NonNull String packageName);
 
     /**
@@ -3927,6 +3929,7 @@
      *             found on the system.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract int getPackageUidAsUser(@NonNull String packageName, @UserIdInt int userId)
             throws NameNotFoundException;
@@ -3945,6 +3948,7 @@
      *             found on the system.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract int getPackageUidAsUser(@NonNull String packageName,
             @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
@@ -3987,6 +3991,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract boolean arePermissionsIndividuallyControlled();
 
@@ -3995,6 +4000,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract boolean isWirelessConsentModeEnabled();
 
     /**
@@ -4047,6 +4053,7 @@
             @ApplicationInfoFlags int flags) throws NameNotFoundException;
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract ApplicationInfo getApplicationInfoAsUser(@NonNull String packageName,
@@ -4228,6 +4235,7 @@
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -4276,6 +4284,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     @NonNull
     @TestApi
@@ -4389,6 +4398,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
     public abstract void grantRuntimePermission(@NonNull String packageName,
@@ -4415,6 +4425,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
     public abstract void revokeRuntimePermission(@NonNull String packageName,
@@ -4459,6 +4470,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
@@ -4481,6 +4493,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
@@ -4704,6 +4717,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName);
 
@@ -4819,6 +4833,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @TestApi
     public abstract @Nullable String[] getNamesForUids(int[] uids);
 
@@ -4835,6 +4850,7 @@
      *             found on the system.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract int getUidForSharedUser(@NonNull String sharedUserName)
             throws NameNotFoundException;
@@ -4878,6 +4894,7 @@
      *         deleted with {@code DELETE_KEEP_DATA} flag set).
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @TestApi
     public abstract List<ApplicationInfo> getInstalledApplicationsAsUser(
@@ -4890,6 +4907,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
     public abstract @NonNull List<InstantAppInfo> getInstantApps();
@@ -4901,6 +4919,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
     public abstract @Nullable Drawable getInstantAppIcon(String packageName);
@@ -4949,6 +4968,7 @@
      * deprecated
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract int getInstantAppCookieMaxSize();
 
     /**
@@ -5006,6 +5026,7 @@
     /**
      * @removed
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract boolean setInstantAppCookie(@Nullable byte[] cookie);
 
     /**
@@ -5044,6 +5065,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(
             @InstallFlags int flags, @UserIdInt int userId);
 
@@ -5056,6 +5078,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @RequiresPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES)
     @SystemApi
@@ -5075,6 +5098,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     @TestApi
     public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
@@ -5086,6 +5110,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     @TestApi
     public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
@@ -5192,6 +5217,7 @@
      *         containing something else, such as the activity resolver.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @UnsupportedAppUsage
     public abstract ResolveInfo resolveActivityAsUser(@NonNull Intent intent,
@@ -5233,6 +5259,7 @@
      *         empty list is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract List<ResolveInfo> queryIntentActivitiesAsUser(@NonNull Intent intent,
@@ -5256,6 +5283,7 @@
      *         empty list is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @SystemApi
@@ -5318,6 +5346,7 @@
      *         no matching receivers, an empty list or null is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@@ -5329,6 +5358,7 @@
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
@@ -5367,6 +5397,7 @@
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     public abstract ResolveInfo resolveServiceAsUser(@NonNull Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId);
@@ -5399,6 +5430,7 @@
      *         empty list or null is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
@@ -5437,6 +5469,7 @@
      *         no matching services, an empty list or null is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
@@ -5504,6 +5537,7 @@
      *         provider. If a provider was not found, returns null.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @UnsupportedAppUsage
     public abstract ProviderInfo resolveContentProviderAsUser(@NonNull String providerName,
@@ -5888,6 +5922,7 @@
      * @return the drawable or null if no drawable is required.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @UnsupportedAppUsage
     public abstract Drawable getUserBadgeForDensity(@NonNull UserHandle user, int density);
@@ -5906,6 +5941,7 @@
      * @return the drawable or null if no drawable is required.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @UnsupportedAppUsage
     public abstract Drawable getUserBadgeForDensityNoBackground(@NonNull UserHandle user,
@@ -6030,6 +6066,7 @@
             throws NameNotFoundException;
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract Resources getResourcesForApplicationAsUser(@NonNull String packageName,
@@ -6075,6 +6112,7 @@
      *
      * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @SystemApi
     public abstract int installExistingPackage(@NonNull String packageName)
@@ -6087,6 +6125,7 @@
      *
      * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @SystemApi
     public abstract int installExistingPackage(@NonNull String packageName,
@@ -6099,6 +6138,7 @@
      *
      * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @RequiresPermission(anyOf = {
             Manifest.permission.INSTALL_EXISTING_PACKAGES,
@@ -6179,6 +6219,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT)
     public abstract void verifyIntentFilter(int verificationId, int verificationCode,
@@ -6204,6 +6245,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
     public abstract int getIntentVerificationStatusAsUser(@NonNull String packageName,
@@ -6229,6 +6271,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
     public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String packageName,
@@ -6246,6 +6289,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @SystemApi
     public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
@@ -6262,6 +6306,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @SystemApi
     public abstract List<IntentFilter> getAllIntentFilters(@NonNull String packageName);
@@ -6276,6 +6321,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -6293,6 +6339,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(allOf = {
             Manifest.permission.SET_PREFERRED_APPLICATIONS,
@@ -6319,6 +6366,7 @@
             @Nullable String installerPackageName);
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
     public abstract void setUpdateAvailable(@NonNull String packageName, boolean updateAvaialble);
@@ -6339,6 +6387,7 @@
      *            indicate that no callback is desired.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
     @UnsupportedAppUsage
     public abstract void deletePackage(@NonNull String packageName,
@@ -6359,6 +6408,7 @@
      * @param userId The user Id
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @RequiresPermission(anyOf = {
             Manifest.permission.DELETE_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
@@ -6376,6 +6426,7 @@
      *
      * @deprecated use {@link #getInstallSourceInfo(String)} instead
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @Nullable
     public abstract String getInstallerPackageName(@NonNull String packageName);
@@ -6415,6 +6466,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void clearApplicationUserData(@NonNull String packageName,
             @Nullable IPackageDataObserver observer);
@@ -6434,6 +6486,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void deleteApplicationCacheFiles(@NonNull String packageName,
             @Nullable IPackageDataObserver observer);
@@ -6456,6 +6509,7 @@
      *            callback is desired.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void deleteApplicationCacheFilesAsUser(@NonNull String packageName,
             @UserIdInt int userId, @Nullable IPackageDataObserver observer);
@@ -6489,6 +6543,7 @@
     }
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void freeStorageAndNotify(@Nullable String volumeUuid, long freeStorageSize,
             @Nullable IPackageDataObserver observer);
@@ -6522,6 +6577,7 @@
     }
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void freeStorage(@Nullable String volumeUuid, long freeStorageSize,
             @Nullable IntentSender pi);
@@ -6545,6 +6601,7 @@
      * @deprecated use {@link StorageStatsManager} instead.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @UnsupportedAppUsage
     public abstract void getPackageSizeInfoAsUser(@NonNull String packageName,
@@ -6676,6 +6733,7 @@
      * an app to be responsible for a particular role and to check current role
      * holders, see {@link android.app.role.RoleManager}.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Deprecated
     @UnsupportedAppUsage
     public abstract void replacePreferredActivity(@NonNull IntentFilter filter, int match,
@@ -6772,6 +6830,7 @@
      * default, if any.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @UnsupportedAppUsage
     public abstract ComponentName getHomeActivities(@NonNull List<ResolveInfo> outActivities);
@@ -6873,6 +6932,7 @@
      * @param userId Ther userId of the user whose restrictions are to be flushed.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void flushPackageRestrictionsAsUser(@UserIdInt int userId);
 
@@ -6883,6 +6943,7 @@
      * or by installing it, such as with {@link #installExistingPackage(String)}
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean setApplicationHiddenSettingAsUser(@NonNull String packageName,
             boolean hidden, @NonNull UserHandle userHandle);
@@ -6892,6 +6953,7 @@
      * @see #setApplicationHiddenSettingAsUser(String, boolean, UserHandle)
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
             @NonNull UserHandle userHandle);
@@ -6918,6 +6980,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
     public abstract void addOnPermissionsChangeListener(
@@ -6930,6 +6993,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
     public abstract void removeOnPermissionsChangeListener(
@@ -6943,6 +7007,7 @@
      *        application's AndroidManifest.xml.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
@@ -6950,6 +7015,7 @@
     /** Return the signing {@link KeySet} for this application.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract KeySet getSigningKeySet(@NonNull String packageName);
@@ -6961,6 +7027,7 @@
      * Compare to {@link #isSignedByExactly(String packageName, KeySet ks)}.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isSignedBy(@NonNull String packageName, @NonNull KeySet ks);
 
@@ -6970,6 +7037,7 @@
      * {@link #isSignedBy(String packageName, KeySet ks)}.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isSignedByExactly(@NonNull String packageName, @NonNull KeySet ks);
 
@@ -7187,6 +7255,7 @@
      * @throws IllegalArgumentException if the package was not found.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isPackageSuspendedForUser(@NonNull String packageName, int userId);
 
@@ -7262,6 +7331,7 @@
      * @param packageName the package to change the category hint for.
      * @param categoryHint the category hint to set.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void setApplicationCategoryHint(@NonNull String packageName,
             @ApplicationInfo.Category int categoryHint);
 
@@ -7277,34 +7347,43 @@
     }
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract int getMoveStatus(int moveId);
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void registerMoveCallback(@NonNull MoveCallback callback,
             @NonNull Handler handler);
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void unregisterMoveCallback(@NonNull MoveCallback callback);
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract int movePackage(@NonNull String packageName, @NonNull VolumeInfo vol);
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract @Nullable VolumeInfo getPackageCurrentVolume(@NonNull ApplicationInfo app);
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public abstract List<VolumeInfo> getPackageCandidateVolumes(
             @NonNull ApplicationInfo app);
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract int movePrimaryStorage(@NonNull VolumeInfo vol);
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract @Nullable VolumeInfo getPrimaryStorageCurrentVolume();
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes();
 
     /**
@@ -7314,6 +7393,7 @@
      * @return identity that uniquely identifies current device
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
 
@@ -7322,6 +7402,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isUpgrade();
 
@@ -7351,6 +7432,7 @@
      *            {@link #ONLY_IF_NO_MATCH_FOUND}.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void addCrossProfileIntentFilter(@NonNull IntentFilter filter,
             @UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags);
@@ -7362,12 +7444,14 @@
      * @param sourceUserId The source user id.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void clearCrossProfileIntentFilters(@UserIdInt int sourceUserId);
 
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract Drawable loadItemIcon(@NonNull PackageItemInfo itemInfo,
@@ -7376,12 +7460,14 @@
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @NonNull
     @UnsupportedAppUsage
     public abstract Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
             @Nullable ApplicationInfo appInfo);
 
     /** {@hide} */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isPackageAvailable(@NonNull String packageName);
 
@@ -7599,6 +7685,7 @@
      *         user, {@code INSTALL_REASON_UNKNOWN} is returned.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @TestApi
     @InstallReason
     public abstract int getInstallReason(@NonNull String packageName, @NonNull UserHandle user);
@@ -7627,6 +7714,7 @@
      * @see {@link android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS}
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @SystemApi
     public abstract ComponentName getInstantAppResolverSettingsComponent();
@@ -7638,6 +7726,7 @@
      * @see {@link android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE}
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     @SystemApi
     public abstract ComponentName getInstantAppInstallerComponent();
@@ -7648,6 +7737,7 @@
      * @see {@link android.provider.Settings.Secure#ANDROID_ID}
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @Nullable
     public abstract String getInstantAppAndroidId(@NonNull String packageName,
             @NonNull UserHandle user);
@@ -7692,6 +7782,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void registerDexModule(@NonNull String dexModulePath,
             @Nullable DexModuleRegisterCallback callback);
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 2e48ce9..a33fb58 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -188,6 +188,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void prepare(int maxCount, @NonNull Surface surface)
             throws CameraAccessException;
 
@@ -227,6 +228,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
 
     /**
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 0edd055..969db96 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -257,6 +257,7 @@
      * @throws IllegalArgumentException if id==0
      * @hide This API is not thoroughly elaborated yet
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract @Nullable Bitmap getMetadataImage(int id);
 
     /**
diff --git a/core/java/android/service/autofill/InternalTransformation.java b/core/java/android/service/autofill/InternalTransformation.java
index 0dba2b9..d31ea99 100644
--- a/core/java/android/service/autofill/InternalTransformation.java
+++ b/core/java/android/service/autofill/InternalTransformation.java
@@ -45,6 +45,7 @@
      * @param template the {@link RemoteViews presentation template}.
      * @param childViewId resource id of the child view inside the template.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     abstract void apply(@NonNull ValueFinder finder, @NonNull RemoteViews template,
             int childViewId) throws Exception;
 
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 606e8f9..29ce231 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -97,6 +97,7 @@
     public abstract void setVisibility(int visibility);
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void setAssistBlocked(boolean state);
 
     /**
@@ -431,6 +432,7 @@
     public abstract void asyncCommit();
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract Rect getTempRect();
 
     /**
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f2772d6..fb2412b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1384,6 +1384,7 @@
     }
 
     /** @hide */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void alwaysReadCloseOnTouchAttr();
 
@@ -1564,6 +1565,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void clearContentView();
 
     /**
@@ -2632,18 +2634,21 @@
      * Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void onMultiWindowModeChanged();
 
     /**
      * Called when the activity changes to/from picture-in-picture mode.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
 
     /**
      * Called when the activity just relaunched.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void reportActivityRelaunched();
 
     /**
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index f62a28e..023d9ff2 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -154,6 +154,7 @@
      *               HTTP request header
      * @hide Used by Browser and by WebViewProvider implementations.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract String getCookie(String url, boolean privateBrowsing);
 
@@ -230,6 +231,7 @@
      * @param privateBrowsing whether to use the private browsing cookie jar
      * @hide Used by Browser and WebViewProvider implementations.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract boolean hasCookies(boolean privateBrowsing);
 
@@ -264,6 +266,7 @@
      *
      * @hide Only for use by WebViewProvider implementations
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     protected abstract boolean allowFileSchemeCookiesImpl();
 
@@ -299,6 +302,7 @@
      *
      * @hide Only for use by WebViewProvider implementations
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     protected abstract void setAcceptFileSchemeCookiesImpl(boolean accept);
 }
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index b9e7042..2cb37b4 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -35,6 +35,7 @@
      * @deprecated This method is now obsolete.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract int getId();
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index 08956e0..b705658 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -75,6 +75,7 @@
 
     /** {@hide}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void bulkRequestIconForPageUrl(ContentResolver cr, String where,
             IconListener listener);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 91b9390..9b753f1 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -268,6 +268,7 @@
      * @deprecated This method is now obsolete.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract void setNavDump(boolean enabled);
@@ -280,6 +281,7 @@
      * @deprecated This method is now obsolete.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract boolean getNavDump();
@@ -457,6 +459,7 @@
      * @deprecated This method is now obsolete.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract  void setUseWebViewBackgroundForOverscrollBackground(boolean view);
@@ -469,6 +472,7 @@
      * @deprecated This method is now obsolete.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract  boolean getUseWebViewBackgroundForOverscrollBackground();
@@ -534,6 +538,7 @@
      * Developers should access this via {@link CookieManager#setShouldAcceptThirdPartyCookies}.
      * @hide Internal API.
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void setAcceptThirdPartyCookies(boolean accept);
 
@@ -542,6 +547,7 @@
      * Developers should access this via {@link CookieManager#getShouldAcceptThirdPartyCookies}.
      * @hide Internal API
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract boolean getAcceptThirdPartyCookies();
 
@@ -669,6 +675,7 @@
      * @deprecated Please use {@link #setUserAgentString} instead.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract void setUserAgent(int ua);
@@ -687,6 +694,7 @@
      * @deprecated Please use {@link #getUserAgentString} instead.
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract int getUserAgent();
@@ -1050,6 +1058,7 @@
      *             {@link #setPluginState}
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract void setPluginsEnabled(boolean flag);
@@ -1259,6 +1268,7 @@
      * @deprecated This method has been replaced by {@link #getPluginState}
      * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     @Deprecated
     public abstract boolean getPluginsEnabled();
@@ -1445,6 +1455,7 @@
      * WebView.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag);
 
@@ -1455,6 +1466,7 @@
      * @see #setVideoOverlayForEmbeddedEncryptedVideoEnabled
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
     public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 64e1ca8..a785a1a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5346,6 +5346,7 @@
      *
      * @param down true if the scroll is going down, false if it is going up
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     abstract void fillGap(boolean down);
 
     void hideSelector() {
@@ -5383,6 +5384,7 @@
      * @param y Where the user touched
      * @return The position of the first (or only) item in the row containing y
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     abstract int findMotionRow(int y);
 
@@ -5430,6 +5432,7 @@
      *
      * @param position the position of the new selection
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     abstract void setSelectionInt(int position);
 
     /**
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index daf6914..76e97ad 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -310,6 +310,7 @@
         }
     }
 
+    @SuppressWarnings("HiddenAbstractMethod")
     abstract void layout(int delta, boolean animate);
 
     @Override
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 610bffe..0ef4b94 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -200,6 +200,7 @@
      * @return The window transformation that needs to be applied for this frame.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract int getTransform();
 
     /**
@@ -207,6 +208,7 @@
      * @return The scaling mode that needs to be applied for this frame.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract int getScalingMode();
 
     /**
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 982e5f3..07de617 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -680,6 +680,7 @@
     public static abstract class VideoCall {
 
         /** @hide */
+        @SuppressWarnings("HiddenAbstractMethod")
         public abstract void destroy();
 
         /**
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 8f5ec36..e595002 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -98,12 +98,14 @@
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract void fillInNotifierBundle(Bundle bundle);
 
     /**
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     @UnsupportedAppUsage
     public abstract boolean isEmpty();
 
@@ -111,6 +113,7 @@
      * Invalidate this object.  The location area code and the cell id are set to -1.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract void setStateInvalid();
 
     /**
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 28feab2..42d7707 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -22,7 +22,12 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.telephony.BinderCacheManager;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
+import android.telephony.ims.aidl.IImsRcsController;
+
+import com.android.internal.telephony.ITelephony;
 
 /**
  * Provides access to information about Telephony IMS services on the device.
@@ -30,8 +35,6 @@
 @SystemService(Context.TELEPHONY_IMS_SERVICE)
 public class ImsManager {
 
-    private Context mContext;
-
     /**
      * <p>Broadcast Action: Indicates that a previously allowed IMS operation was rejected by the
      * network due to the network returning a "forbidden" response. This may be due to a
@@ -87,6 +90,14 @@
     public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
             "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
 
+    // Cache Telephony Binder interfaces, one cache per process.
+    private static final BinderCacheManager<ITelephony> sTelephonyCache =
+            new BinderCacheManager<>(ImsManager::getITelephonyInterface);
+    private static final BinderCacheManager<IImsRcsController> sRcsCache =
+            new BinderCacheManager<>(ImsManager::getIImsRcsControllerInterface);
+
+    private final Context mContext;
+
     /**
      * Use {@link Context#getSystemService(String)} to get an instance of this class.
      * @hide
@@ -108,7 +119,7 @@
             throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
         }
 
-        return new ImsRcsManager(mContext, subscriptionId);
+        return new ImsRcsManager(mContext, subscriptionId, sRcsCache);
     }
 
     /**
@@ -124,17 +135,19 @@
             throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
         }
 
-        return new ImsMmTelManager(subscriptionId);
+        return new ImsMmTelManager(subscriptionId, sTelephonyCache);
     }
 
     /**
-     * Create an instance of SipDelegateManager for the subscription id specified.
+     * Create an instance of {@link SipDelegateManager} for the subscription id specified.
      * <p>
-     * Used for RCS single registration cases, where an IMS application needs to forward SIP
-     * traffic through the device's IMS service.
-     * @param subscriptionId The ID of the subscription that this SipDelegateManager will use.
+     * Allows an IMS application to forward SIP traffic through the device's IMS service,
+     * which is used for cellular carriers that require the device to share a single IMS
+     * registration for both MMTEL and RCS features.
+     * @param subscriptionId The ID of the subscription that this {@link SipDelegateManager} will
+     *                       be bound to.
      * @throws IllegalArgumentException if the subscription is invalid.
-     * @return a SipDelegateManager instance for the specified subscription ID.
+     * @return a {@link SipDelegateManager} instance for the specified subscription ID.
      * @hide
      */
     @SystemApi
@@ -144,6 +157,22 @@
             throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
         }
 
-        return new SipDelegateManager(mContext, subscriptionId);
+        return new SipDelegateManager(mContext, subscriptionId, sRcsCache);
+    }
+
+    private static IImsRcsController getIImsRcsControllerInterface() {
+        return IImsRcsController.Stub.asInterface(
+                TelephonyFrameworkInitializer
+                        .getTelephonyServiceManager()
+                        .getTelephonyImsServiceRegisterer()
+                        .get());
+    }
+
+    private static ITelephony getITelephonyInterface() {
+        return ITelephony.Stub.asInterface(
+                TelephonyFrameworkInitializer
+                        .getTelephonyServiceManager()
+                        .getTelephonyServiceRegisterer()
+                        .get());
     }
 }
diff --git a/telephony/java/android/telephony/ims/DelegateMessageCallback.java b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
new file mode 100644
index 0000000..beec4a6
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.telephony.ims.stub.SipDelegate;
+
+/**
+ * Callback interface provided to the SipTransport implementation to notify a remote application of
+ * the following:
+ * <ul>
+ *     <li>A new incoming SIP message associated with the feature tags the SipDelegate registered
+ *     with has been received or an in-dialog request to this SipDelegate has been received.</li>
+ *     <li>Acknowledge that an outgoing SIP message from the RCS application has been sent
+ *     successfully or notify the application of the reason why it was not sent</li>
+ * </ul>
+ * @hide
+ */
+public interface DelegateMessageCallback {
+
+    /**
+     * Send a new incoming SIP message to the remote application for processing.
+     */
+    void onMessageReceived(@NonNull SipMessage message);
+
+    /**
+     * Notify the remote application that a previous request to send a SIP message using
+     * {@link SipDelegate#sendMessage} has succeeded.
+     *
+     * @param viaTransactionId The transaction ID found in the via header field of the
+     *         previously sent {@link SipMessage}.
+     */
+    void onMessageSent(@NonNull String viaTransactionId);
+
+    /**
+     * Notify the remote application that a previous request to send a SIP message using
+     * {@link SipDelegate#sendMessage} has failed.
+     *
+     * @param viaTransactionId The Transaction ID found in the via header field of the previously
+     *         sent {@link SipMessage}.
+     * @param reason The reason for the failure.
+     */
+    void onMessageSendFailure(@NonNull String viaTransactionId,
+            @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.aidl b/telephony/java/android/telephony/ims/DelegateRegistrationState.aidl
new file mode 100644
index 0000000..756ea92
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 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.ims;
+
+parcelable DelegateRegistrationState;
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
new file mode 100644
index 0000000..4facfa7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains the full state of the IMS feature tags associated with a SipDelegate and managed by the
+ * ImsService.
+ * @hide
+ */
+public final class DelegateRegistrationState implements Parcelable {
+
+    /**
+     * This feature tag has been deregistered for an unknown reason. Outgoing out-of-dialog SIP
+     * messages associated with feature tags that are not registered will fail.
+     */
+    public static final int DEREGISTERED_REASON_UNKNOWN = 0;
+
+    /**
+     * This feature tag has been deregistered because it is not provisioned to be used on this radio
+     * access technology or PDN. Outgoing out-of-dialog SIP messages associated with feature tags
+     * that are not registered will fail.
+     * <p>
+     * There may be new incoming SIP dialog requests on a feature that that is not provisioned. It
+     * is still expected that the SipDelegateConnection responds to the request.
+     */
+    public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1;
+
+    /**
+     * This feature tag has been deregistered because IMS has been deregistered. All outgoing SIP
+     * messages will fail until IMS registration occurs.
+     */
+    public static final int DEREGISTERED_REASON_NOT_REGISTERED = 2;
+
+    /**
+     * This feature tag is being deregistered because the PDN that the IMS registration is on is
+     *changing.
+     * All open SIP dialogs need to be closed before the PDN change can proceed.
+     */
+    public static final int DEREGISTERING_REASON_PDN_CHANGE = 3;
+
+    /**
+     * This feature tag is being deregistered due to a provisioning change. This can be triggered by
+     * many things, such as a provisioning change triggered by the carrier network, a radio access
+     * technology change by the modem causing a different set of feature tags to be provisioned, or
+     * a user triggered hange, such as data being enabled/disabled.
+     * <p>
+     * All open SIP dialogs associated with the new deprovisioned feature tag need to be closed
+     * before the IMS registration modification can proceed.
+     */
+    public static final int DEREGISTERING_REASON_PROVISIONING_CHANGE = 4;
+
+    /**
+     * This feature tag is deregistering because the SipDelegate associated with this feature tag
+     * needs to change its supported feature set.
+     * <p>
+     * All open SIP Dialogs associated with this feature tag must be closed before this operation
+     * can proceed.
+     */
+    public static final int DEREGISTERING_REASON_FEATURE_TAGS_CHANGING = 5;
+
+    /**
+     * This feature tag is deregistering because the SipDelegate is in the process of being
+     * destroyed.
+     * <p>
+     * All open SIP Dialogs associated with this feature tag must be closed before this operation
+     * can proceed.
+     */
+    public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "DEREGISTERED_REASON_", value = {
+            DEREGISTERED_REASON_UNKNOWN,
+            DEREGISTERED_REASON_NOT_PROVISIONED,
+            DEREGISTERED_REASON_NOT_REGISTERED
+    })
+    public @interface DeregisteredReason {}
+
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "DEREGISTERING_REASON_", value = {
+            DEREGISTERING_REASON_PDN_CHANGE,
+            DEREGISTERING_REASON_PROVISIONING_CHANGE,
+            DEREGISTERING_REASON_FEATURE_TAGS_CHANGING,
+            DEREGISTERING_REASON_DESTROY_PENDING
+    })
+    public @interface DeregisteringReason {}
+
+    private final ArrayList<String> mRegisteredTags = new ArrayList<>();
+    private final ArrayList<FeatureTagState> mDeregisteringTags = new ArrayList<>();
+    private final ArrayList<FeatureTagState> mDeregisteredTags = new ArrayList<>();
+
+    /**
+     * Builder used to create new instances of {@link DelegateRegistrationState}.
+     */
+    public static class Builder {
+
+        private final DelegateRegistrationState mState;
+
+        /* Create a new instance of {@link Builder} */
+        public Builder() {
+            mState = new DelegateRegistrationState();
+        }
+
+        /**
+         * Add a feature tag that is currently included in the current network IMS Registration.
+         * @param featureTag The IMS media feature tag included in the current IMS registration.
+         * @return The in-progress Builder instance for RegistrationState.
+         */
+        public Builder addRegisteredFeatureTag(@NonNull String featureTag) {
+            if (!mState.mRegisteredTags.contains(featureTag)) {
+                mState.mRegisteredTags.add(featureTag);
+            }
+            return this;
+        }
+
+        /**
+         * Add a list of feature tags that are currently included in the current network IMS
+         * Registration.
+         * @param featureTags The IMS media feature tags included in the current IMS registration.
+         * @return The in-progress Builder instance for RegistrationState.
+         */
+        public Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
+            mState.mRegisteredTags.addAll(featureTags);
+            return this;
+        }
+
+        /**
+         * Add a feature tag that is in the current network IMS Registration, but is in the progress
+         * of being deregistered and requires action from the RCS application before the IMS
+         * registration can be modified.
+         *
+         * See {@link DeregisteringReason} for more information regarding what is required by the
+         * RCS application to proceed.
+         *
+         * @param featureTag The media feature tag that has limited or no availability due to its
+         *         current deregistering state.
+         * @param reason The reason why the media feature tag has moved to the deregistering state.
+         *         The availability of the feature tag depends on the {@link DeregisteringReason}.
+         * @return The in-progress Builder instance for RegistrationState.
+         */
+        public Builder addDeregisteringFeatureTag(@NonNull String featureTag,
+                @DeregisteringReason int reason) {
+            boolean ftExists = mState.mDeregisteringTags.stream().anyMatch(
+                    f -> f.getFeatureTag().equals(featureTag));
+            if (!ftExists) {
+                mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
+            }
+            return this;
+        }
+
+        /**
+         * Add a feature tag that is currently not included in the network RCS registration. See
+         * {@link DeregisteredReason} for more information regarding the reason for why the feature
+         * tag is not registered.
+         * @param featureTag The media feature tag that is not registered.
+         * @param reason The reason why the media feature tag has been deregistered.
+         * @return The in-progress Builder instance for RegistrationState.
+         */
+        public Builder addDeregisteredFeatureTag(@NonNull String featureTag,
+                @DeregisteredReason int reason) {
+            boolean ftExists = mState.mDeregisteredTags.stream().anyMatch(
+                    f -> f.getFeatureTag().equals(featureTag));
+            if (!ftExists) {
+                mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
+            }
+            return this;
+        }
+
+        /**
+         * @return the finalized instance.
+         */
+        public DelegateRegistrationState build() {
+            return mState;
+        }
+    }
+
+    /**
+     * The builder should be used to construct a new instance of this class.
+     */
+    private DelegateRegistrationState() {}
+
+    /**
+     * Used for unparcelling only.
+     */
+    private DelegateRegistrationState(Parcel source) {
+        source.readList(mRegisteredTags, null /*classloader*/);
+        readStateFromParcel(source, mDeregisteringTags);
+        readStateFromParcel(source, mDeregisteredTags);
+    }
+
+    /**
+     * Get the feature tags that this SipDelegate is associated with that are currently part of the
+     * network IMS registration. SIP Messages both in and out of a SIP Dialog may be sent and
+     * received using these feature tags.
+     * @return A Set of feature tags that the SipDelegate has associated with that are included in
+     * the network IMS registration.
+     */
+    public @NonNull Set<String> getRegisteredFeatureTags() {
+        return new ArraySet<>(mRegisteredTags);
+    }
+
+    /**
+     * Get the feature tags that this SipDelegate is associated with that are currently part of the
+     * network IMS registration but are in the process of being deregistered.
+     * <p>
+     * Any incoming SIP messages associated with a feature tag included in this list will still be
+     * delivered. Outgoing SIP messages that are still in-dialog will be delivered to the
+     * SipDelegate, but outgoing out-of-dialog SIP messages with  a feature tag that is included in
+     * this list will fail.
+     * <p>
+     * The SipDelegate will stay in this state for a limited period of time while it waits for the
+     * RCS application to perform a specific action. More details on the actions that can cause this
+     * state as well as the expected response are included in the reason codes and can be found in
+     * {@link DeregisteringReason}.
+     * @return A Set of feature tags that the SipDelegate has associated with that are included in
+     * the network IMS registration but are in the process of deregistering.
+     */
+    public @NonNull Set<FeatureTagState> getDeregisteringFeatureTags() {
+        return new ArraySet<>(mDeregisteringTags);
+    }
+
+    /**
+     * Get the list of feature tags that are associated with this SipDelegate but are not currently
+     * included in the network IMS registration.
+     * <p>
+     * See {@link DeregisteredReason} codes for more information related to the reasons why this may
+     * occur.
+     * <p>
+     * Due to network race conditions, there may still be onditions where an incoming out-of-dialog
+     * SIP message is delivered for a feature tag that is considered deregistered. Due to this
+     * condition, in-dialog outgoing SIP messages for deregistered feature tags will still be
+     * allowed as long as they are in response to a dialog started by a remote party. Any outgoing
+     * out-of-dialog SIP messages associated with feature tags included in this list will fail to be
+     * sent.
+     * @return A list of feature tags that the SipDelegate has associated with that not included in
+     * the network IMS registration.
+     */
+    public @NonNull Set<FeatureTagState> getDeregisteredFeatureTags() {
+        return new ArraySet<>(mDeregisteredTags);
+    }
+
+    public static final Creator<DelegateRegistrationState> CREATOR =
+            new Creator<DelegateRegistrationState>() {
+        @Override
+        public DelegateRegistrationState createFromParcel(Parcel source) {
+            return new DelegateRegistrationState(source);
+        }
+
+        @Override
+        public DelegateRegistrationState[] newArray(int size) {
+            return new DelegateRegistrationState[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeList(mRegisteredTags);
+        writeStateToParcel(dest, mDeregisteringTags);
+        writeStateToParcel(dest, mDeregisteredTags);
+    }
+
+    private void writeStateToParcel(Parcel dest, List<FeatureTagState> state) {
+        dest.writeInt(state.size());
+        for (FeatureTagState s : state) {
+            dest.writeString(s.getFeatureTag());
+            dest.writeInt(s.getState());
+        }
+    }
+
+    private void readStateFromParcel(Parcel source, List<FeatureTagState> emptyState) {
+        int len = source.readInt();
+        for (int i = 0; i < len; i++) {
+            String ft = source.readString();
+            int reason = source.readInt();
+            emptyState.add(new FeatureTagState(ft, reason));
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DelegateRegistrationState that = (DelegateRegistrationState) o;
+        return mRegisteredTags.equals(that.mRegisteredTags)
+                && mDeregisteringTags.equals(that.mDeregisteringTags)
+                && mDeregisteredTags.equals(that.mDeregisteredTags);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.aidl b/telephony/java/android/telephony/ims/DelegateRequest.aidl
new file mode 100644
index 0000000..60c990f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 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.ims;
+
+parcelable DelegateRequest;
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.java b/telephony/java/android/telephony/ims/DelegateRequest.java
new file mode 100644
index 0000000..f384901
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRequest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains information required for the creation of a {@link SipDelegate} and the associated
+ * SipDelegateConnection given back to the requesting application.
+ * @hide
+ */
+public final class DelegateRequest implements Parcelable {
+
+    private final ArrayList<String> mFeatureTags;
+
+    /**
+     * Create a new DelegateRequest, which will be used to create a SipDelegate by the ImsService.
+     * @param featureTags The list of IMS feature tags that will be associated with the SipDelegate
+     *                    created using this DelegateRequest. All feature tags are expected to be in
+     *                    the format defined in RCC.07 section 2.6.1.3.
+     */
+    public DelegateRequest(@NonNull Set<String> featureTags) {
+        if (featureTags == null) {
+            throw new IllegalStateException("Invalid arguments, featureTags List can not be null");
+        }
+        mFeatureTags = new ArrayList<>(featureTags);
+    }
+
+    /**
+     * @return the list of IMS feature tag associated with this DelegateRequest in the format
+     * defined in RCC.07 section 2.6.1.3.
+     */
+    public Set<String> getFeatureTags() {
+        return new ArraySet<>(mFeatureTags);
+    }
+
+    /**
+     * Internal constructor used only for unparcelling.
+     */
+    private DelegateRequest(Parcel in) {
+        mFeatureTags = new ArrayList<>();
+        in.readList(mFeatureTags, null /*classLoader*/);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeList(mFeatureTags);
+    }
+
+    public static final @NonNull Creator<DelegateRequest> CREATOR = new Creator<DelegateRequest>() {
+        @Override
+        public DelegateRequest createFromParcel(Parcel source) {
+            return new DelegateRequest(source);
+        }
+
+        @Override
+        public DelegateRequest[] newArray(int size) {
+            return new DelegateRequest[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DelegateRequest that = (DelegateRequest) o;
+        return mFeatureTags.equals(that.mFeatureTags);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFeatureTags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
new file mode 100644
index 0000000..0f1afc4
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.ims.stub.SipDelegate;
+import android.telephony.ims.stub.SipTransportImplBase;
+
+import java.util.List;
+
+/**
+ * Callback interface to notify a remote application of the following:
+ * <ul>
+ *     <li>the {@link SipDelegate} associated with this callback has been created or destroyed in
+ *         response to a creation or destruction request from the framework</li>
+ *     <li>the SIP IMS configuration associated with this {@link SipDelegate} has changed</li>
+ *     <li>the IMS registration of the feature tags associated with this {@link SipDelegate} have
+ *         changed.</li>
+ * </ul>
+ * @hide
+ */
+public interface DelegateStateCallback {
+
+    /**
+     * This must be called by the ImsService after {@link SipTransportImplBase#createSipDelegate} is
+     * called by the framework to notify the framework and remote application that the
+     * {@link SipDelegate} has been successfully created.
+     *
+     * @param delegate The SipDelegate created to service the DelegateRequest.
+     * @param deniedTags A List of {@link FeatureTagState}, which contains the feature tags
+     *    associated with this {@link SipDelegate} that have no access to send/receive SIP messages
+     *    as well as a reason for why the feature tag is denied. For more information on the reason
+     *    why the feature tag was denied access, see the
+     *    {@link SipDelegateManager.DeniedReason} reasons. This is considered a permanent denial due
+     *    to this {@link SipDelegate} not supporting a feature or this ImsService already
+     *    implementing this feature elsewhere. If all features of this {@link SipDelegate} are
+     *    denied, {@link #onCreated(SipDelegate, List)} should still be called as the framework will
+     *    later call {@link SipTransportImplBase#destroySipDelegate(SipDelegate, int)} to clean the
+     *    delegate up.
+     */
+    void onCreated(@NonNull SipDelegate delegate, @Nullable List<FeatureTagState> deniedTags);
+
+    /**
+     * This must be called by the ImsService after the framework calls
+     * {@link SipTransportImplBase#destroySipDelegate} to notify the framework and remote
+     * application that the procedure to destroy the {@link SipDelegate} has been completed.
+     * @param reasonCode The reason for closing this delegate.
+     */
+    void onDestroyed(@SipDelegateManager.SipDelegateDestroyReason int reasonCode);
+
+    /**
+     * Call to notify the remote application of a configuration change associated with this
+     * {@link SipDelegate}.
+     * <p>
+     * The remote application will not be able to proceed sending SIP messages until after this
+     * configuration is sent the first time, so this configuration should be sent as soon as the
+     * {@link SipDelegate} has access to these configuration parameters.
+     * <p>
+     * Incoming SIP messages should not be routed to the remote application until AFTER this
+     * configuration change is sent to ensure that the remote application can respond correctly.
+     * Similarly, if there is an event that triggers the IMS configuration to change, incoming SIP
+     * messages routing should be delayed until the {@link SipDelegate} sends the IMS configuration
+     * change event to reduce conditions where the remote application is using a stale IMS
+     * configuration.
+     */
+    void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration config);
+
+    /**
+     * Call to notify the remote application that the {@link SipDelegate} has modified the IMS
+     * registration state of the RCS feature tags that were requested as part of the initial
+     * {@link DelegateRequest}.
+     * <p>
+     * See {@link DelegateRegistrationState} for more information about how IMS Registration state
+     * should be communicated the associated SipDelegateConnection in cases such as
+     * IMS deregistration, handover, PDN change, provisioning changes, etc…
+     * <p>
+     * Note: Even after the status of the feature tags are updated here to deregistered, the
+     * SipDelegate must still be able to handle these messages and call
+     * {@link DelegateMessageCallback#onMessageSendFailure} to notify the RCS application that the
+     * message was not sent.
+     *
+     * @param registrationState The current network IMS registration state for all feature tags
+     *         associated with this SipDelegate.
+     */
+    void onFeatureTagRegistrationChanged(@NonNull DelegateRegistrationState registrationState);
+}
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.aidl b/telephony/java/android/telephony/ims/FeatureTagState.aidl
new file mode 100644
index 0000000..bce5574
--- /dev/null
+++ b/telephony/java/android/telephony/ims/FeatureTagState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 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.ims;
+
+parcelable FeatureTagState;
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.java b/telephony/java/android/telephony/ims/FeatureTagState.java
new file mode 100644
index 0000000..060be6f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/FeatureTagState.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Maps an IMS media feature tag 3gpp universal resource name (URN) previously mapped to a
+ * {@link SipDelegate} in the associated {@link DelegateRequest} to its current availability
+ * state as set by the ImsService managing the related IMS registration.
+ *
+ * This class is only used to report more information about a IMS feature tag that is not fully
+ * available at this time.
+ * <p>
+ * Please see {@link DelegateRegistrationState}, {@link DelegateStateCallback}, and
+ * {@link DelegateConnectionStateCallback} for more information about how this class is used to
+ * convey the state of IMS feature tags that were requested by {@link DelegateRequest} but are not
+ * currently available.
+ * @hide
+ */
+public final class FeatureTagState implements Parcelable {
+
+    private final String mFeatureTag;
+    private final int mState;
+
+    /**
+     * Associate an IMS feature tag with its current state. See {@link DelegateRegistrationState}
+     * and {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged(
+     * DelegateRegistrationState, List)} and
+     * {@link DelegateStateCallback#onCreated(SipDelegate, List)} for examples on how and when this
+     * is used.
+     *
+     * @param featureTag The IMS feature tag that is deregistered, in the process of
+     *                   deregistering, or denied.
+     * @param state The {@link DelegateRegistrationState.DeregisteredReason},
+     *         {@link DelegateRegistrationState.DeregisteringReason}, or
+     *         {@link SipDelegateManager.DeniedReason} associated with this feature tag.
+     */
+    public FeatureTagState(@NonNull String featureTag, int state) {
+        mFeatureTag = featureTag;
+        mState = state;
+    }
+
+    /**
+     * Used for constructing instances during un-parcelling.
+     */
+    private FeatureTagState(Parcel source) {
+        mFeatureTag = source.readString();
+        mState = source.readInt();
+    }
+
+    /**
+     * @return The IMS feature tag string that is in the process of deregistering,
+     * deregistered, or denied.
+     */
+    public @NonNull String getFeatureTag() {
+        return mFeatureTag;
+    }
+
+    /**
+     * @return The reason for why the feature tag is currently in the process of deregistering,
+     * has been deregistered, or has been denied. See {@link DelegateRegistrationState} and
+     * {@link DelegateConnectionStateCallback} for more information.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mFeatureTag);
+        dest.writeInt(mState);
+    }
+
+    public static final Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
+        @Override
+        public FeatureTagState createFromParcel(Parcel source) {
+            return new FeatureTagState(source);
+        }
+
+        @Override
+        public FeatureTagState[] newArray(int size) {
+            return new FeatureTagState[size];
+        }
+    };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        FeatureTagState that = (FeatureTagState) o;
+        return mState == that.mState
+                && mFeatureTag.equals(that.mFeatureTag);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mFeatureTag, mState);
+    }
+
+    @Override
+    public String toString() {
+        return "FeatureTagState{" + "mFeatureTag='" + mFeatureTag + ", mState=" + mState + '}';
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index a4f2a31..d1a893f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.BinderCacheManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -213,6 +214,7 @@
     }
 
     private final int mSubId;
+    private final BinderCacheManager<ITelephony> mBinderCache;
 
     /**
      * Create an instance of {@link ImsMmTelManager} for the subscription id specified.
@@ -242,7 +244,8 @@
             throw new IllegalArgumentException("Invalid subscription ID");
         }
 
-        return new ImsMmTelManager(subId);
+        return new ImsMmTelManager(subId, new BinderCacheManager<>(
+                ImsMmTelManager::getITelephonyInterface));
     }
 
     /**
@@ -250,8 +253,9 @@
      * @hide
      */
     @VisibleForTesting
-    public ImsMmTelManager(int subId) {
+    public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
         mSubId = subId;
+        mBinderCache = binderCache;
     }
 
     /**
@@ -1367,7 +1371,11 @@
         }
     }
 
-    private static ITelephony getITelephony() {
+    private ITelephony getITelephony() {
+        return mBinderCache.getBinder();
+    }
+
+    private static ITelephony getITelephonyInterface() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 TelephonyFrameworkInitializer
                         .getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 8b6dac8..4292aae 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -28,6 +28,7 @@
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.BinderCacheManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -149,14 +150,17 @@
 
     private final int mSubId;
     private final Context mContext;
+    private final BinderCacheManager<IImsRcsController> mBinderCache;
 
     /**
      * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
      * @hide
      */
-    public ImsRcsManager(Context context, int subId) {
+    public ImsRcsManager(Context context, int subId,
+            BinderCacheManager<IImsRcsController> binderCache) {
         mSubId = subId;
         mContext = context;
+        mBinderCache = binderCache;
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/SipDelegateConnection.java b/telephony/java/android/telephony/ims/SipDelegateConnection.java
new file mode 100644
index 0000000..6bfdc2c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateConnection.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.telephony.ims.stub.SipDelegate;
+
+/**
+ * Represents a connection to the remote {@link SipDelegate} that is managed by the
+ * {@link ImsService} implementing IMS for the subscription that is associated with it.
+ * <p>
+ * The remote delegate will handle messages sent by this {@link SipDelegateConnection}, notifying
+ * the associated {@link DelegateMessageCallback} when the message was either sent successfully or
+ * failed to be sent.
+ * <p>
+ * It is also the responsibility of this {@link SipDelegateConnection} to acknowledge when incoming
+ * SIP messages have been received successfully via
+ * {@link DelegateMessageCallback#onMessageReceived(SipMessage)} or when there was an error
+ * receiving the message using {@link #notifyMessageReceived(String)} and
+ * {@link #notifyMessageReceiveError(String, int)}.
+ *
+ * @see SipDelegateManager#createSipDelegate
+ * @hide
+ */
+public interface SipDelegateConnection {
+
+    /**
+     * Send a SIP message to the SIP delegate to be sent over the carrier’s network. The
+     * {@link SipMessage} will either be acknowledged with
+     * {@link DelegateMessageCallback#onMessageSent(String)} upon successful sending of this message
+     * or {@link DelegateMessageCallback#onMessageSendFailure(String, int)} if there was an error
+     * sending the message.
+     * @param sipMessage The SipMessage to be sent.
+     * @param configVersion The SipDelegateImsConfiguration version used to construct the
+     *                      SipMessage. See {@link SipDelegateImsConfiguration#getVersion} for more
+     *                      information on this parameter and why it is used.
+     */
+    void sendMessage(@NonNull SipMessage sipMessage, int configVersion);
+
+    /**
+     * Notify the {@link SipDelegate} that a SIP message received from
+     * {@link DelegateMessageCallback#onMessageReceived(SipMessage)} has been received successfully
+     * and is being processed.
+     * @param viaTransactionId Per RFC3261 Sec 8.1.1.7 the transaction ID associated with the Via
+     *         branch parameter.
+     */
+    void notifyMessageReceived(@NonNull String viaTransactionId);
+
+    /**
+     * Notify the SIP delegate that the SIP message has been received from
+     * {@link DelegateMessageCallback#onMessageReceived(SipMessage)}, however there was an error
+     * processing it.
+     * @param viaTransactionId Per RFC3261 Sec 8.1.1.7 the transaction ID associated with the Via
+     *         branch parameter.
+     * @param reason The reason why the error occurred.
+     */
+    void notifyMessageReceiveError(@NonNull String viaTransactionId,
+            @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl
new file mode 100644
index 0000000..44ae1b1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 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.ims;
+
+parcelable SipDelegateImsConfiguration;
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
new file mode 100644
index 0000000..8abd0ee
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The IMS registration and other attributes that the {@link SipDelegateConnection} used by the
+ * IMS application will need to be aware of to correctly generate outgoing {@link SipMessage}s.
+ * <p>
+ * The IMS service must generate new instances of this configuration as the IMS configuration
+ * managed by the IMS service changes. Along with each {@link SipDelegateImsConfiguration} instance
+ * containing the configuration is the "version", which should be incremented every time a new
+ * {@link SipDelegateImsConfiguration} instance is created. The {@link SipDelegateConnection} will
+ * include the version of the {@link SipDelegateImsConfiguration} instance that it used in order for
+ * the {@link SipDelegate} to easily identify if the IMS application used a now stale configuration
+ * to generate the {@link SipMessage} and return
+ * {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION} in
+ * {@link DelegateMessageCallback#onMessageSendFailure(String, int)} so that the IMS application can
+ * regenerate that {@link SipMessage} using the correct {@link SipDelegateImsConfiguration}
+ * instance.
+ * <p>
+ * Every time the IMS configuration state changes in the IMS service, a full configuration should
+ * be generated. The new  {@link SipDelegateImsConfiguration} instance should not be an incremental
+ * update.
+ * @hide
+ */
+public class SipDelegateImsConfiguration implements Parcelable {
+
+    /**
+     * IPV4 Address type.
+     * <p>
+     * Used as a potential value for {@link #KEY_SIP_CONFIG_IPTYPE_STRING}.
+     */
+    public static final String IPTYPE_IPV4 = "IPV4";
+
+    /**
+     * IPV6 Address type.
+     * <p>
+     * Used as a potential value for {@link #KEY_SIP_CONFIG_IPTYPE_STRING}.
+     */
+    public static final String IPTYPE_IPV6 = "IPV6";
+
+    /**
+     * The SIP transport uses UDP.
+     * <p>
+     * Used as a potential value for {@link #KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING}.
+     */
+    public static final String SIP_TRANSPORT_UDP = "UDP";
+
+    /**
+     * The SIP transport uses TCP.
+     * <p>
+     * Used as a potential value for {@link #KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING}.
+     */
+    public static final String SIP_TRANSPORT_TCP = "TCP";
+
+    /**
+     * Flag specifying if SIP compact form is enabled
+     */
+    public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL =
+            "sip_config_is_compact_form_enabled_bool";
+
+    /**
+     * Flag specifying if SIP keepalives are enabled
+     */
+    public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL =
+            "sip_config_is_keepalive_enabled_bool";
+
+    /**
+     * Maximum SIP payload to be sent on UDP. If the SIP message payload is greater than max udp
+     * payload size, then TCP must be used
+     */
+    public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT =
+            "sip_config_udp_max_payload_size_int";
+
+    /**
+     * Transport protocol used for SIP signaling.
+     * Available options are: {@link #SIP_TRANSPORT_UDP }, {@link #SIP_TRANSPORT_TCP }
+     */
+    public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING =
+            "sip_config_protocol_type_string";
+
+    /**
+     * IMS public user identifier string
+     */
+    public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING =
+            "sip_config_ue_public_user_id_string";
+
+    /**
+     * IMS private user identifier string
+     */
+    public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING =
+            "sip_config_ue_private_user_id_string";
+
+    /**
+     * IMS home domain string
+     */
+    public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+
+    /**
+     * IMEI string. Application can include the Instance-ID feature tag " +sip.instance" in the
+     * Contact header with a value of the device IMEI in the form "urn:gsma:imei:<device IMEI>".
+     */
+    public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+
+    /**
+     * IP address type for SIP signaling.
+     * Available options are: {@link #IPTYPE_IPV6}, {@link #IPTYPE_IPV4}
+     */
+    public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+
+    /**
+     * Local IPaddress used for SIP signaling.
+     */
+    public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING =
+            "sip_config_ue_default_ipaddress_string";
+
+    /**
+     * Local port used for sending SIP traffic
+     */
+    public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT =
+            "sip_config_ue_default_port_int";
+
+    /**
+     * SIP server / PCSCF default ip address
+     */
+    public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING =
+            "sip_config_server_default_ipaddress_string";
+
+    /**
+     * SIP server / PCSCF port used for sending SIP traffic
+     */
+    public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT =
+            "sip_config_server_default_port_int";
+
+    /**
+     * Flag specifying if Network Address Translation is enabled and UE is behind a NAT.
+     */
+    public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL =
+            "sip_config_is_nat_enabled_bool";
+
+    /**
+     * UE's public IPaddress when UE is behind a NAT.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING =
+            "sip_config_ue_public_ipaddress_with_nat_string";
+
+    /**
+     * UE's public SIP port when UE is behind a NAT.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT =
+            "sip_config_ue_public_port_with_nat_int";
+
+    /**
+     * Flag specifying if Globally routable user-agent uri (GRUU) is enabled as per TS 23.808
+     */
+    public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL =
+            "sip_config_is_gruu_enabled_bool";
+
+    /**
+     * UE's Globally routable user-agent uri if this feature is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING =
+            "sip_config_ue_public_gruu_string";
+
+    /**
+     * Flag specifying if SIP over IPSec is enabled.
+     */
+    public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL =
+            "sip_config_is_ipsec_enabled_bool";
+    /**
+     * UE's SIP port used to send traffic when IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT =
+            "sip_config_ue_ipsec_client_port_int";
+
+    /**
+     * UE's SIP port used to receive traffic when IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT =
+            "sip_config_ue_ipsec_server_port_int";
+
+    /**
+     * UE's SIP port used for the previous IPsec security association if IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT =
+            "sip_config_ue_ipsec_old_client_port_int";
+
+    /**
+     * Port number used by the SIP server to send SIP traffic when IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT =
+            "sip_config_server_ipsec_client_port_int";
+
+    /**
+     * Port number used by the SIP server to receive incoming SIP traffic when IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT =
+            "sip_config_server_ipsec_server_port_int";
+
+    /**
+     * Port number used by the SIP server to send SIP traffic on the previous IPSec security
+     * association when IPSec is enabled.
+     * <p>
+     * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+     */
+    public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT =
+            "sip_config_server_ipsec_old_client_port_int";
+    /**
+     * SIP Authentication header string
+     */
+    public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING =
+            "sip_config_auhentication_header_string";
+
+    /**
+     * SIP Authentication nonce string
+     */
+    public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING =
+            "sip_config_authentication_nonce_string";
+
+    /**
+     * SIP service route header string
+     */
+    public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING =
+            "sip_config_service_route_header_string";
+
+    /**
+     * SIP security verify header string
+     */
+    public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING =
+            "sip_config_security_verify_header_string";
+
+    /**
+     * SIP Path header string
+     */
+    public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING =
+            "sip_config_path_header_string";
+
+    /**
+     * SIP User part string in contact header
+     */
+    public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING =
+            "sip_config_uri_user_part_string";
+
+    /**
+     * SIP P-access-network-info header string
+     */
+    public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING =
+            "sip_config_p_access_network_info_header_string";
+
+    /**
+     * SIP P-last-access-network-info header string
+     */
+    public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING =
+            "sip_config_p_last_access_network_info_header_string";
+
+    /**
+     * SIP P-associated-uri header string
+     */
+    public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING =
+            "sip_config_p_associated_uri_header_string";
+
+    /**@hide*/
+    @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_STRING", value = {
+            KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING,
+            KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING,
+            KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING,
+            KEY_SIP_CONFIG_HOME_DOMAIN_STRING,
+            KEY_SIP_CONFIG_IMEI_STRING,
+            KEY_SIP_CONFIG_IPTYPE_STRING,
+            KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING,
+            KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING,
+            KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING,
+            KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING,
+            KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING,
+            KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING,
+            KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING,
+            KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING,
+            KEY_SIP_CONFIG_PATH_HEADER_STRING,
+            KEY_SIP_CONFIG_URI_USER_PART_STRING,
+            KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING,
+            KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING,
+            KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StringConfigKey {}
+
+    /**@hide*/
+    @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_INT", value = {
+            KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT,
+            KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT,
+            KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT,
+            KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT,
+            KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT,
+            KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT,
+            KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT,
+            KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT,
+            KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT,
+            KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IntConfigKey {}
+
+    /**@hide*/
+    @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_BOOL", value = {
+            KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL,
+            KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL,
+            KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL,
+            KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL,
+            KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BooleanConfigKey {}
+
+    /**
+     * Builder class to be used when constructing a new SipDelegateImsConfiguration.
+     */
+    public static class Builder {
+        private final long mVersion;
+        private final PersistableBundle mBundle;
+
+        /**
+         * Creates an empty implementation of SipDelegateImsConfiguration.
+         * @param version The version associated with the SipDelegateImsConfiguration being built.
+         *                See {@link #getVersion} for more information.
+         */
+        public Builder(int version) {
+            mVersion = version;
+            mBundle = new PersistableBundle();
+        }
+        /**
+         * Clones an existing implementation of SipDelegateImsConfiguration to handle situations
+         * where only a small number of parameters have changed from the previous configuration.
+         * <p>
+         * Automatically increments the version of this configuration by 1. See {@link #getVersion}
+         * for more information.
+         */
+        public Builder(@NonNull SipDelegateImsConfiguration config) {
+            mVersion = config.getVersion() + 1;
+            mBundle = config.copyBundle();
+        }
+        /**
+         * Put a string value into this configuration bundle for the given key.
+         */
+        public Builder putString(@StringConfigKey String key, String value) {
+            mBundle.putString(key, value);
+            return this;
+        }
+
+        /**
+         * Replace the existing default value with a new value for a given key.
+         */
+        public Builder putInt(@IntConfigKey String key, int value) {
+            mBundle.putInt(key, value);
+            return this;
+        }
+
+        /**
+         * Replace the existing default value with a new value for a given key.
+         */
+        public Builder putBoolean(@BooleanConfigKey String key, boolean value) {
+            mBundle.putBoolean(key, value);
+            return this;
+        }
+
+        /**
+         * @return a new SipDelegateImsConfiguration from this Builder.
+         */
+        public SipDelegateImsConfiguration build() {
+            return new SipDelegateImsConfiguration(mVersion, mBundle);
+        }
+    }
+
+    private final long mVersion;
+    private final PersistableBundle mBundle;
+
+    private SipDelegateImsConfiguration(long version, PersistableBundle bundle) {
+        mVersion = version;
+        mBundle = bundle;
+    }
+
+    private SipDelegateImsConfiguration(Parcel source) {
+        mVersion = source.readLong();
+        mBundle = source.readPersistableBundle();
+    }
+
+    /**
+     * @return the string value associated with a given key or {@code null} if it doesn't exist.
+     */
+    public @StringConfigKey String getString(String key) {
+        return mBundle.getString(key);
+    }
+
+    /**
+     * @return the Integer value associated with a given key or {@code null} if the value doesn't
+     * exist.
+     */
+    public @IntConfigKey Integer getInt(String key) {
+        if (!mBundle.containsKey(key)) {
+            return null;
+        }
+        return mBundle.getInt(key);
+    }
+
+    /**
+     * @return the Integer value associated with a given key or {@code null} if the value doesn't
+     * exist.
+     */
+    public @BooleanConfigKey Boolean getBoolen(String key) {
+        if (!mBundle.containsKey(key)) {
+            return null;
+        }
+        return mBundle.getBoolean(key);
+    }
+
+    /**
+     * @return a shallow copy of the full configuration.
+     */
+    public PersistableBundle copyBundle() {
+        return new PersistableBundle(mBundle);
+    }
+
+    /**
+     * An integer representing the version number of this SipDelegateImsConfiguration.
+     * {@link SipMessage}s that are created using this configuration will also have a this
+     * version number associated with them, which will allow the IMS service to validate that the
+     * {@link SipMessage} was using the latest configuration during creation and not a stale
+     * configuration due to race conditions between the configuration being updated and the RCS
+     * application not receiving the updated configuration before generating a new message.
+     *
+     * @return the version number associated with this {@link SipDelegateImsConfiguration}.
+     */
+    public long getVersion() {
+        return mVersion;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mVersion);
+        dest.writePersistableBundle(mBundle);
+    }
+
+    public static final Creator<SipDelegateImsConfiguration> CREATOR =
+            new Creator<SipDelegateImsConfiguration>() {
+        @Override
+        public SipDelegateImsConfiguration createFromParcel(Parcel source) {
+            return new SipDelegateImsConfiguration(source);
+        }
+
+        @Override
+        public SipDelegateImsConfiguration[] newArray(int size) {
+            return new SipDelegateImsConfiguration[size];
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 82c8a9c..337b7d4 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -17,29 +17,251 @@
 package android.telephony.ims;
 
 import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.telephony.BinderCacheManager;
 import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
+import android.telephony.ims.stub.DelegateConnectionMessageCallback;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
 /**
- * Manages the creation and destruction of SipDelegates, which allow an IMS application to forward
- * SIP messages for the purposes of providing a single IMS registration to the carrier's IMS network
- * from multiple sources.
+ * Manages the creation and destruction of SipDelegates for the {@link ImsService} managing IMS
+ * for the subscription ID that this SipDelegateManager has been created for.
+ *
+ * This allows multiple IMS applications to forward SIP messages to/from their application for the
+ * purposes of providing a single IMS registration to the carrier's IMS network from potentially
+ * many IMS stacks implementing a subset of the supported MMTEL/RCS features.
  * @hide
  */
 @SystemApi
 public class SipDelegateManager {
 
+    /**
+     * The SIP message has failed being sent or received for an unknown reason.
+     * <p>
+     * The caller should retry a message that failed with this response.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0;
+
+    /**
+     * The remote service associated with this connection has died and the message was not
+     * properly sent/received.
+     * <p>
+     * This is considered a permanent error and the system will automatically begin the teardown and
+     * destruction of the SipDelegate. No further messages should be sent on this transport.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1;
+
+    /**
+     * The message has not been sent/received because the delegate is in the process of closing and
+     * has become unavailable. No further messages should be sent/received on this delegate.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2;
+
+    /**
+     * The SIP message has an invalid start line and the message can not be sent.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3;
+
+    /**
+     * One or more of the header fields in the header section of the outgoing SIP message is invalid
+     * and the SIP message can not be sent.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4;
+
+    /**
+     * The body content of the SIP message is invalid and the message can not be sent.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5;
+
+    /**
+     * The feature tag associated with the outgoing message does not match any known feature tags
+     * and this message can not be sent.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6;
+
+    /**
+     * The feature tag associated with the outgoing message is not enabled for the associated
+     * SipDelegateConnection and can not be sent.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7;
+
+    /**
+     * The link to the network has been lost and the outgoing message has failed to send.
+     * <p>
+     * This message should be retried when connectivity to the network is re-established. See
+     * {@link android.net.ConnectivityManager.NetworkCallback} for how this can be determined.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8;
+
+    /**
+     * The outgoing SIP message has not been sent due to the SipDelegate not being registered for
+     * IMS at this time.
+     * <p>
+     * This is considered a temporary failure, the message should not be retried until an IMS
+     * registration change callback is received via
+     * {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged}
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9;
+
+    /**
+     * The outgoing SIP message has not been sent because the {@link SipDelegateImsConfiguration}
+     * version associated with the outgoing {@link SipMessage} is now stale and has failed
+     * validation checks.
+     * <p>
+     * The @link SipMessage} should be recreated using the newest
+     * {@link SipDelegateImsConfiguration} and sent again.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10;
+
+    /**
+     * The outgoing SIP message has not been sent because the internal state of the associated
+     * {@link SipDelegate} is changing and has temporarily brought the transport down.
+     * <p>
+     * This is considered a temporary error and the {@link SipDelegateConnection} should resend the
+     * message once {@link DelegateRegistrationState#DEREGISTERING_REASON_FEATURE_TAGS_CHANGING} is
+     * no longer reported.
+     * @hide
+     */
+    public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "MESSAGE_FAILURE_REASON_", value = {
+            MESSAGE_FAILURE_REASON_UNKNOWN,
+            MESSAGE_FAILURE_REASON_DELEGATE_DEAD,
+            MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+            MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+            MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
+            MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT,
+            MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+            MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE,
+            MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE,
+            MESSAGE_FAILURE_REASON_NOT_REGISTERED,
+            MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
+            MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION
+    })
+    public @interface MessageFailureReason {}
+
+
+    /**
+     * Access to use this feature tag has been denied for an unknown reason.
+     * @hide
+     */
+    public static final int DENIED_REASON_UNKNOWN = 0;
+
+    /**
+     * This feature tag is allowed to be used by this SipDelegateConnection, but it is in use by
+     * another SipDelegateConnection and can not be associated with this delegate. The feature tag
+     * will stay in this state until the feature tag is release by the other application.
+     * @hide
+     */
+    public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1;
+
+    /**
+     * Access to use this feature tag has been denied because this application does not have the
+     * permissions required to access this feature tag.
+     * @hide
+     */
+    public static final int DENIED_REASON_NOT_ALLOWED = 2;
+
+    /**
+     * Access to use this feature tag has been denied because single registration is not allowed by
+     * the carrier at this time. The application should fall back to dual registration if
+     * applicable.
+     * @hide
+     */
+    public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3;
+
+    /**
+     * This feature tag is not recognized as a valid feature tag by the SipDelegate and has been
+     * denied.
+     * @hide
+     */
+    public static final int DENIED_REASON_INVALID = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "DENIED_REASON_", value = {
+            DENIED_REASON_UNKNOWN,
+            DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
+            DENIED_REASON_NOT_ALLOWED,
+            DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED,
+            DENIED_REASON_INVALID
+    })
+    public @interface DeniedReason {}
+
+    /**
+     * The SipDelegate has closed due to an unknown reason.
+     * @hide
+     */
+    public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0;
+
+    /**
+     * The SipDelegate has closed because the IMS service has died unexpectedly.
+     * @hide
+     */
+    public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1;
+
+    /**
+     * The SipDelegate has closed because the IMS application has requested that the connection be
+     * destroyed.
+     * @hide
+     */
+    public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2;
+
+    /**
+     * The SipDelegate has closed because the IMS service does not support the creation of
+     * SipDelegates.
+     * @hide
+     */
+    public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_NOT_SUPPORTED = 3;
+
+    /**
+     * The SipDelegate has been closed due to the user disabling RCS.
+     * @hide
+     */
+    public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 4;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = "SIP_DELEGATE_DESTROY_REASON", value = {
+            SIP_DELEGATE_DESTROY_REASON_UNKNOWN,
+            SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD,
+            SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP,
+            SIP_DELEGATE_DESTROY_REASON_SERVICE_NOT_SUPPORTED,
+            SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS
+    })
+    public @interface SipDelegateDestroyReason {}
+
     private final Context mContext;
     private final int mSubId;
+    private final BinderCacheManager<IImsRcsController> mBinderCache;
 
     /**
      * Only visible for testing. To instantiate an instance of this class, please use
@@ -47,9 +269,11 @@
      * @hide
      */
     @VisibleForTesting
-    public SipDelegateManager(Context context, int subId) {
+    public SipDelegateManager(Context context, int subId,
+            BinderCacheManager<IImsRcsController> binderCache) {
         mContext = context;
         mSubId = subId;
+        mBinderCache = binderCache;
     }
 
     /**
@@ -69,7 +293,7 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isSupported() throws ImsException {
         try {
-            IImsRcsController controller = getIImsRcsController();
+            IImsRcsController controller = mBinderCache.getBinder();
             if (controller == null) {
                 throw new ImsException("Telephony server is down",
                         ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
@@ -83,11 +307,90 @@
         }
     }
 
-    private IImsRcsController getIImsRcsController() {
-        IBinder binder = TelephonyFrameworkInitializer
-                .getTelephonyServiceManager()
-                .getTelephonyImsServiceRegisterer()
-                .get();
-        return IImsRcsController.Stub.asInterface(binder);
+    /**
+     * Request that the ImsService implementation create a SipDelegate, which will configure the
+     * ImsService to forward SIP traffic that matches the filtering criteria set in supplied
+     * {@link DelegateRequest} to the application that the supplied callbacks are registered for.
+     * <p>
+     * This API requires that the caller is running as part of a long-running process and will
+     * always be available to handle incoming messages. One mechanism that can be used for this is
+     * the {@link android.service.carrier.CarrierMessagingClientService}, which the framework keeps
+     * a persistent binding to when the app is the default SMS application.
+     * @param request The parameters that are associated with the SipDelegate creation request that
+     *                will be used to create the SipDelegate connection.
+     * @param executor The executor that will be used to call the callbacks associated with this
+     *          SipDelegate.
+     * @param dc The callback that will be used to notify the listener of the creation/destruction
+     *           of the remote SipDelegate as well as changes to the state of the remote SipDelegate
+     *           connection.
+     * @param mc The callback that will be used to notify the listener of new incoming SIP messages
+     *           as well as the status of messages that were sent by the associated
+     *           SipDelegateConnection.
+     * @throws ImsException Thrown if there was a problem communicating with the ImsService
+     * associated with this SipDelegateManager. See {@link ImsException#getCode()}.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor,
+            @NonNull DelegateConnectionStateCallback dc,
+            @NonNull DelegateConnectionMessageCallback mc) throws ImsException {
+        if (request == null || executor == null || dc == null || mc == null) {
+            throw new IllegalArgumentException("Invalid arguments passed into createSipDelegate");
+        }
+        try {
+            SipDelegateConnectionAidlWrapper wrapper =
+                    new SipDelegateConnectionAidlWrapper(executor, dc, mc);
+            IImsRcsController controller = mBinderCache.listenOnBinder(wrapper,
+                    wrapper::binderDied);
+            if (controller == null) {
+                throw new ImsException("Telephony server is down",
+                        ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+            }
+            controller.createSipDelegate(mSubId, request, wrapper.getStateCallbackBinder(),
+                    wrapper.getMessageCallbackBinder());
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
+        } catch (RemoteException e) {
+            throw new ImsException(e.getMessage(),
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    /**
+     * Destroy a previously created {@link SipDelegateConnection} that was created using
+     * {@link #createSipDelegate}.
+     * <p>
+     * This will also clean up all related callbacks in the associated ImsService.
+     * @param delegateConnection The SipDelegateConnection to destroy.
+     * @param reason The reason for why this SipDelegateConnection was destroyed.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection,
+            @SipDelegateDestroyReason int reason) {
+
+        if (delegateConnection == null) {
+            throw new IllegalArgumentException("invalid argument passed into destroySipDelegate");
+        }
+        if (delegateConnection instanceof SipDelegateConnectionAidlWrapper) {
+            SipDelegateConnectionAidlWrapper w =
+                    (SipDelegateConnectionAidlWrapper) delegateConnection;
+            try {
+                IImsRcsController c = mBinderCache.removeRunnable(w);
+                c.destroySipDelegate(mSubId, w.getSipDelegateBinder(), reason);
+            } catch (RemoteException e) {
+                // Connection to telephony died, but this will signal destruction of SipDelegate
+                // eventually anyway, so return normally.
+                try {
+                    w.getStateCallbackBinder().onDestroyed(
+                            SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+                } catch (RemoteException ignore) {
+                    // Local to process.
+                }
+            }
+        } else {
+            throw new IllegalArgumentException("Unknown SipDelegateConnection implementation passed"
+                    + " into this method");
+        }
     }
 }
diff --git a/telephony/java/android/telephony/ims/SipMessage.aidl b/telephony/java/android/telephony/ims/SipMessage.aidl
new file mode 100644
index 0000000..5140f8a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipMessage.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2020 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.ims;
+
+parcelable SipMessage;
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
new file mode 100644
index 0000000..c3b1be2
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 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.ims;
+
+import android.annotation.NonNull;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a partially encoded SIP message. See RFC 3261 for more information on how SIP
+ * messages are structured and used.
+ * <p>
+ * The SIP message is represented in a partially encoded form in order to allow for easier
+ * verification and should not be used as a generic SIP message container.
+ * @hide
+ */
+public final class SipMessage implements Parcelable {
+    // Should not be set to true for production!
+    private static final boolean IS_DEBUGGING = Build.IS_ENG;
+
+    private static final String[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
+            "BYE", "CANCEL", "REGISTER"};
+
+    private final String mStartLine;
+    private final String mHeaderSection;
+    private final byte[] mContent;
+
+    /**
+     * Represents a partially encoded SIP message.
+     *
+     * @param startLine The start line of the message, containing either the request-line or
+     *                  status-line.
+     * @param headerSection A String containing the full unencoded SIP message header.
+     * @param content UTF-8 encoded SIP message body.
+     */
+    public SipMessage(@NonNull String startLine, @NonNull String headerSection,
+            @NonNull byte[] content) {
+        if (startLine == null || headerSection == null || content == null) {
+            throw new IllegalArgumentException("One or more null parameters entered");
+        }
+        mStartLine = startLine;
+        mHeaderSection = headerSection;
+        mContent = content;
+    }
+
+    /**
+     * Private constructor used only for unparcelling.
+     */
+    private SipMessage(Parcel source) {
+        mStartLine = source.readString();
+        mHeaderSection = source.readString();
+        mContent = new byte[source.readInt()];
+        source.readByteArray(mContent);
+    }
+    /**
+     * @return The start line of the SIP message, which contains either the request-line or
+     * status-line.
+     */
+    public @NonNull String getStartLine() {
+        return mStartLine;
+    }
+
+    /**
+     * @return The full, unencoded header section of the SIP message.
+     */
+    public @NonNull String getHeaderSection() {
+        return mHeaderSection;
+    }
+
+    /**
+     * @return only the UTF-8 encoded SIP message body.
+     */
+    public @NonNull byte[] getContent() {
+        return mContent;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mStartLine);
+        dest.writeString(mHeaderSection);
+        dest.writeInt(mContent.length);
+        dest.writeByteArray(mContent);
+    }
+
+    public static final Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
+        @Override
+        public SipMessage createFromParcel(Parcel source) {
+            return new SipMessage(source);
+        }
+
+        @Override
+        public SipMessage[] newArray(int size) {
+            return new SipMessage[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder();
+        b.append("StartLine: [");
+        if (IS_DEBUGGING) {
+            b.append(mStartLine);
+        } else {
+            b.append(sanitizeStartLineRequest(mStartLine));
+        }
+        b.append("], [");
+        b.append("Header: [");
+        if (IS_DEBUGGING) {
+            b.append(mHeaderSection);
+        } else {
+            // only identify transaction id/call ID when it is available.
+            b.append("***");
+        }
+        b.append("], ");
+        b.append("Content: [NOT SHOWN]");
+        return b.toString();
+    }
+
+    /**
+     * Start lines containing requests are formatted: METHOD SP Request-URI SP SIP-Version CRLF.
+     * Detect if this is a REQUEST and redact Request-URI portion here, as it contains PII.
+     */
+    private String sanitizeStartLineRequest(String startLine) {
+        String[] splitLine = startLine.split(" ");
+        if (splitLine == null || splitLine.length == 0)  {
+            return "(INVALID STARTLINE)";
+        }
+        for (String method : SIP_REQUEST_METHODS) {
+            if (splitLine[0].contains(method)) {
+                return splitLine[0] + " <Request-URI> " + splitLine[2];
+            }
+        }
+        return startLine;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 8e84e93..f218e35 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -17,10 +17,15 @@
 package android.telephony.ims.aidl;
 
 import android.net.Uri;
+import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.aidl.IRcsUceControllerCallback;
 import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
-import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
 
 import com.android.ims.ImsFeatureContainer;
 import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -58,6 +63,10 @@
 
     // SipDelegateManager
     boolean isSipDelegateSupported(int subId);
+    void createSipDelegate(int subId, in DelegateRequest request,
+            ISipDelegateConnectionStateCallback delegateState,
+            ISipDelegateMessageCallback delegateMessage);
+    void destroySipDelegate(int subId, ISipDelegate connection, int reason);
 
     // Internal commands that should not be made public
     void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
new file mode 100644
index 0000000..477ee95
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 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.ims.aidl;
+
+import android.telephony.ims.SipMessage;
+
+/**
+ * See {@link SipDelegate} and {@link SipDelegateConnection} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegate {
+    void sendMessage(in SipMessage sipMessage, int configVersion);
+    void notifyMessageReceived(in String viaTransactionId);
+    void notifyMessageReceiveError(in String viaTransactionId, int reason);
+
+    // only used by SipDelegate.
+    void closeDialog(in String callId);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl
new file mode 100644
index 0000000..ddfcb99
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 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.ims.aidl;
+
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.aidl.ISipDelegate;
+
+/**
+ * See {@link SipDelegateConnectionStateCallback} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegateConnectionStateCallback {
+    void onCreated(ISipDelegate c);
+    void onFeatureTagStatusChanged(in DelegateRegistrationState registrationState,
+                in List<FeatureTagState> deniedFeatureTags);
+    void onImsConfigurationChanged(in SipDelegateImsConfiguration registeredSipConfig);
+    void onDestroyed(int reason);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl
new file mode 100644
index 0000000..30b7d6c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 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.ims.aidl;
+
+import android.telephony.ims.SipMessage;
+
+/**
+ * See {@link DelegateMessageCallback} and {@link DelegateConnectionMessageCallback} for docs
+ * regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegateMessageCallback {
+   void onMessageReceived(in SipMessage message);
+   void onMessageSent(in String viaTransactionId);
+   void onMessageSendFailure(in String viaTransactionId, int reason);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl
new file mode 100644
index 0000000..609ee26
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020 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.ims.aidl;
+
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.aidl.ISipDelegate;
+
+/**
+ * See {@link SipDelegateStateCallback} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegateStateCallback {
+    void onCreated(ISipDelegate c, in List<FeatureTagState> deniedFeatureTags);
+    void onFeatureTagRegistrationChanged(in DelegateRegistrationState registrationState);
+    void onImsConfigurationChanged(in SipDelegateImsConfiguration registeredSipConfig);
+    void onDestroyed(int reason);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl b/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
index fe23343..cd88839 100644
--- a/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
@@ -16,9 +16,17 @@
 
 package android.telephony.ims.aidl;
 
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateStateCallback;
+
 /**
  * Interface for commands to the SIP Transport implementation.
  * {@hide}
  */
-interface ISipTransport {
+oneway interface ISipTransport {
+    void createSipDelegate(in DelegateRequest request, ISipDelegateStateCallback dc,
+            ISipDelegateMessageCallback mc);
+    void destroySipDelegate(ISipDelegate delegate, int reason);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
new file mode 100644
index 0000000..a7f62cc
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2020 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.ims.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Implementation of callbacks by wrapping the internal AIDL from telephony. Also implements
+ * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, List)} is called
+ * in order to trampoline events back to telephony.
+ * @hide
+ */
+public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMessageCallback {
+
+    private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
+        @Override
+        public void sendMessage(SipMessage sipMessage, int configVersion) {
+            SipDelegate d = mDelegate;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> d.sendMessage(sipMessage, configVersion));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void notifyMessageReceived(String viaTransactionId)  {
+            SipDelegate d = mDelegate;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> d.notifyMessageReceived(viaTransactionId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+        }
+
+        @Override
+        public void notifyMessageReceiveError(String viaTransactionId, int reason) {
+            SipDelegate d = mDelegate;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> d.notifyMessageReceiveError(viaTransactionId, reason));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+        }
+
+        @Override
+        public void closeDialog(String callId)  {
+            SipDelegate d = mDelegate;
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> d.closeDialog(callId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
+
+    private final ISipDelegateMessageCallback mMessageBinder;
+    private final ISipDelegateStateCallback mStateBinder;
+    private final Executor mExecutor;
+
+    private volatile SipDelegate mDelegate;
+
+    public SipDelegateAidlWrapper(Executor executor, ISipDelegateStateCallback stateBinder,
+            ISipDelegateMessageCallback messageBinder) {
+        mExecutor = executor;
+        mStateBinder = stateBinder;
+        mMessageBinder = messageBinder;
+    }
+
+    @Override
+    public void onMessageReceived(SipMessage message) {
+        try {
+            mMessageBinder.onMessageReceived(message);
+        } catch (RemoteException e) {
+            // BinderDied will be called on SipTransport instance to trigger destruction. Notify
+            // failure message failure locally for now.
+            SipDelegate d = mDelegate;
+            if (d != null) {
+                notifyLocalMessageFailedToBeReceived(message,
+                        SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+            }
+        }
+    }
+
+    @Override
+    public void onMessageSent(String viaTransactionId) {
+        try {
+            mMessageBinder.onMessageSent(viaTransactionId);
+        } catch (RemoteException e) {
+            // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+        }
+    }
+
+    @Override
+    public void onMessageSendFailure(String viaTransactionId, int reason) {
+        try {
+            mMessageBinder.onMessageSendFailure(viaTransactionId, reason);
+        } catch (RemoteException e) {
+            // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+        }
+    }
+
+    @Override
+    public void onCreated(@NonNull SipDelegate delegate,
+            @Nullable List<FeatureTagState> deniedTags) {
+        mDelegate = delegate;
+        try {
+            mStateBinder.onCreated(mDelegateBinder, deniedTags);
+        } catch (RemoteException e) {
+            // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+        }
+    }
+
+    @Override
+    public void onFeatureTagRegistrationChanged(DelegateRegistrationState registrationState) {
+        try {
+            mStateBinder.onFeatureTagRegistrationChanged(registrationState);
+        } catch (RemoteException e) {
+            // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+        }
+    }
+
+    @Override
+    public void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration config) {
+        try {
+            mStateBinder.onImsConfigurationChanged(config);
+        } catch (RemoteException e) {
+            // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+        }
+    }
+
+    @Override
+    public void onDestroyed(int reasonCode) {
+        mDelegate = null;
+        try {
+            mStateBinder.onDestroyed(reasonCode);
+        } catch (RemoteException e) {
+            // Do not worry about this if the remote side is already dead.
+        }
+    }
+
+    public SipDelegate getDelegate()  {
+        return mDelegate;
+    }
+
+    public ISipDelegate getDelegateBinder() {
+        return mDelegateBinder;
+    }
+
+    private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
+        //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
+        // transaction ID can not be parsed.
+        SipDelegate d = mDelegate;
+        if (d != null) {
+            mExecutor.execute(() -> d.notifyMessageReceiveError(null, reason));
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
new file mode 100644
index 0000000..3bd1a46
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2020 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.ims.aidl;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.DelegateConnectionMessageCallback;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Wrapper class implementing {@link SipDelegateConnection} using AIDL, which is returned to the
+ * local process. Also holds a reference to incoming connection message and state AIDL impl to
+ * trampoline events to callbacks as well as notify the local process in the event that the remote
+ * process becomes unavailable.
+ * <p>
+ * When the remote {@link SipDelegate} is created, this instance tracks the
+ * {@link ISipDelegate} associated with it and implements the
+ * {@link SipDelegateConnection} sent back to the local callback.
+ * @hide
+ */
+public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
+        IBinder.DeathRecipient {
+    private static final String LOG_TAG = "SipDelegateCAW";
+
+    private final ISipDelegateConnectionStateCallback.Stub mStateBinder =
+            new ISipDelegateConnectionStateCallback.Stub() {
+        @Override
+        public void onCreated(ISipDelegate c) {
+            associateSipDelegate(c);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mStateCallback.onCreated(SipDelegateConnectionAidlWrapper.this));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onFeatureTagStatusChanged(DelegateRegistrationState registrationState,
+                List<FeatureTagState> deniedFeatureTags) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mStateCallback.onFeatureTagStatusChanged(registrationState,
+                                new ArraySet<>(deniedFeatureTags)));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onImsConfigurationChanged(SipDelegateImsConfiguration registeredSipConfig) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mStateCallback.onImsConfigurationChanged(registeredSipConfig));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onDestroyed(int reason) {
+            invalidateSipDelegateBinder();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() ->
+                        mStateCallback.onDestroyed(reason));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
+
+    private final ISipDelegateMessageCallback.Stub mMessageBinder =
+            new ISipDelegateMessageCallback.Stub() {
+                @Override
+                public void onMessageReceived(SipMessage message) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() ->
+                                mMessageCallback.onMessageReceived(message));
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+
+                @Override
+                public void onMessageSent(String viaTransactionId) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() ->
+                                mMessageCallback.onMessageSent(viaTransactionId));
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+
+                @Override
+                public void onMessageSendFailure(String viaTransactionId, int reason) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        mExecutor.execute(() ->
+                                mMessageCallback.onMessageSendFailure(viaTransactionId, reason));
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            };
+
+
+    private final Executor mExecutor;
+    private final DelegateConnectionStateCallback mStateCallback;
+    private final DelegateConnectionMessageCallback mMessageCallback;
+    private final AtomicReference<ISipDelegate> mDelegateBinder =
+            new AtomicReference<>();
+
+    /**
+     * Wrap the local state and message callbacks, calling the implementation of these interfaces
+     * when the remote process calls these methods.
+     */
+    public SipDelegateConnectionAidlWrapper(Executor executor,
+            DelegateConnectionStateCallback stateCallback,
+            DelegateConnectionMessageCallback messageCallback) {
+        mExecutor = executor;
+        mStateCallback = stateCallback;
+        mMessageCallback = messageCallback;
+    }
+
+    @Override
+    public void sendMessage(SipMessage sipMessage, int configVersion) {
+        try {
+            ISipDelegate conn = getSipDelegateBinder();
+            if (conn == null) {
+                notifyLocalMessageFailedToSend(sipMessage,
+                        SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+                return;
+            }
+            conn.sendMessage(sipMessage, configVersion);
+        } catch (RemoteException e) {
+            notifyLocalMessageFailedToSend(sipMessage,
+                        SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+        }
+    }
+
+    @Override
+    public void notifyMessageReceived(String viaTransactionId) {
+        try {
+            ISipDelegate conn = getSipDelegateBinder();
+            if (conn == null) {
+                return;
+            }
+            conn.notifyMessageReceived(viaTransactionId);
+        } catch (RemoteException e) {
+            // Nothing to do here, app will eventually get remote death callback.
+        }
+    }
+
+    @Override
+    public void notifyMessageReceiveError(String viaTransactionId, int reason) {
+        try {
+            ISipDelegate conn = getSipDelegateBinder();
+            if (conn == null) {
+                return;
+            }
+            conn.notifyMessageReceiveError(viaTransactionId, reason);
+        } catch (RemoteException e) {
+            // Nothing to do here, app will eventually get remote death callback.
+        }
+    }
+
+    // Also called upon IImsRcsController death (telephony process dies).
+    @Override
+    public void binderDied() {
+        invalidateSipDelegateBinder();
+        mExecutor.execute(() -> mStateCallback.onDestroyed(
+                SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD));
+    }
+
+    /**
+     * @return Implementation of state binder.
+     */
+    public ISipDelegateConnectionStateCallback getStateCallbackBinder() {
+        return mStateBinder;
+    }
+
+    /**
+     * @return Implementation of message binder.
+     */
+    public ISipDelegateMessageCallback getMessageCallbackBinder() {
+        return mMessageBinder;
+    }
+
+    /**
+     * @return The ISipDelegateConnection associated with this wrapper.
+     */
+    public ISipDelegate getSipDelegateBinder() {
+        return mDelegateBinder.get();
+    }
+
+    private void associateSipDelegate(ISipDelegate c) {
+        if (c != null) {
+            try {
+                c.asBinder().linkToDeath(this, 0 /*flags*/);
+            } catch (RemoteException e) {
+                // already dead.
+                c = null;
+            }
+        }
+        mDelegateBinder.set(c);
+    }
+
+    private void invalidateSipDelegateBinder() {
+        ISipDelegate oldVal = mDelegateBinder.getAndUpdate((unused) -> null);
+        if (oldVal != null) {
+            try {
+                oldVal.asBinder().unlinkToDeath(this, 0 /*flags*/);
+            } catch (NoSuchElementException e) {
+                Log.i(LOG_TAG, "invalidateSipDelegateBinder: " + e);
+            }
+        }
+    }
+
+    private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
+        //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
+        // transaction ID can not be parsed.
+        mExecutor.execute(() ->
+                mMessageCallback.onMessageSendFailure(null, reason));
+    }
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index b0a7b62..96ca022 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -509,6 +509,7 @@
      * @return true if the capability is enabled, false otherwise.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     public abstract boolean queryCapabilityConfiguration(int capability, int radioTech);
 
     /**
@@ -547,5 +548,6 @@
      * @return Binder instance that the framework will use to communicate with this feature.
      * @hide
      */
+    @SuppressWarnings("HiddenAbstractMethod")
     protected abstract IInterface getBinder();
 }
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
new file mode 100644
index 0000000..59f9601
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+/**
+ * The callback associated with a {@link SipDelegateConnection}, which handles newly received
+ * messages as well as the result of sending a SIP message.
+ * @hide
+ */
+public interface DelegateConnectionMessageCallback {
+
+    /**
+     * A new {@link SipMessage} has been received from the delegate.
+     * @param message the {@link SipMessage} routed to this RCS application.
+     */
+    void onMessageReceived(@NonNull SipMessage message);
+
+    /**
+     * A message previously sent to the SIP delegate using
+     * {@link SipDelegateConnection#sendMessage} has been successfully sent.
+     * @param viaTransactionId The transaction ID found in the via header field of the
+     *                         previously sent {@link SipMessage}.
+     */
+    void onMessageSent(@NonNull String viaTransactionId);
+
+    /**
+     * A message previously sent to the SIP delegate using
+     * {@link SipDelegateConnection#sendMessage} has failed to be sent.
+     * @param viaTransactionId The Transaction ID found in the via header field of the
+     *                         previously sent {@link SipMessage}.
+     * @param reason The reason for the failure.
+     */
+    void onMessageSendFailure(String viaTransactionId,
+            @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
new file mode 100644
index 0000000..9761805
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 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.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+
+import java.util.Set;
+
+/**
+ * The callback associated with a {@link SipDelegateConnection} that manages the state of the
+ * SipDelegateConnection.
+ * <p>
+ * After {@link SipDelegateManager#createSipDelegate} is used to request a new
+ * {@link SipDelegateConnection} be created, {@link #onCreated} will be called with the
+ * {@link SipDelegateConnection} instance that must be used to communicate with the remote
+ * {@link SipDelegate}.
+ * <p>
+ * After, {@link #onFeatureTagStatusChanged} will always be called at least once with the current
+ * status of the feature tags that have been requested. The application may receive multiple
+ * {@link #onFeatureTagStatusChanged} callbacks over the lifetime of the associated
+ * {@link SipDelegateConnection}, which will signal changes to how SIP messages associated with
+ * those feature tags will be handled.
+ * <p>
+ * In order to start sending SIP messages, the SIP configuration parameters will need to be
+ * received, so the messaging application should make no assumptions about these parameters and wait
+ * until {@link #onImsConfigurationChanged(SipDelegateImsConfiguration)} has been called. This is
+ * guaranteed to happen after the first {@link #onFeatureTagStatusChanged} if there is at least one
+ * feature tag that has been successfully associated with the {@link SipDelegateConnection}. If all
+ * feature tags were denied, no IMS configuration will be sent.
+ * <p>
+ * The {@link SipDelegateConnection} will stay associated with this RCS application until either the
+ * RCS application calls {@link SipDelegateManager#destroySipDelegate} or telephony destroys the
+ * {@link SipDelegateConnection}. In both cases, {@link #onDestroyed(int)}  will be called.
+ * Telephony destroying the {@link SipDelegateConnection} instance is rare and will only happen in
+ * rare cases, such as if telephony itself or IMS service dies unexpectedly. See
+ * {@link SipDelegateManager.SipDelegateDestroyReason} reasons for more information on all of the
+ * cases that will trigger the {@link SipDelegateConnection} to be destroyed.
+ *
+ * @hide
+ */
+public interface DelegateConnectionStateCallback {
+
+    /**
+     * A {@link SipDelegateConnection} has been successfully created for the
+     * {@link DelegateRequest} used when calling {@link SipDelegateManager#createSipDelegate}.
+     */
+    void onCreated(@NonNull SipDelegateConnection c);
+
+    /**
+     * The status of the RCS feature tags that were requested as part of the initial
+     * {@link DelegateRequest}.
+     * <p>
+     * There are four states that each RCS feature tag can be in: registered, deregistering,
+     * deregistered, and denied.
+     * <p>
+     * When a feature tag is considered registered, SIP messages associated with that feature tag
+     * may be sent and received freely.
+     * <p>
+     * When a feature tag is deregistering, the network IMS registration still contains the feature
+     * tag, however the IMS service and associated {@link SipDelegate} is in the progress of
+     * modifying the IMS registration to remove this feature tag and requires the application to
+     * perform an action before the IMS registration can change. The specific action required for
+     * the SipDelegate to continue modifying the IMS registration can be found in the definition of
+     * each {@link DelegateRegistrationState.DeregisteringReason}.
+     * <p>
+     * When a feature tag is in the deregistered state, new out-of-dialog SIP messages for that
+     * feature tag will be rejected, however due to network race conditions, the RCS application
+     * should still be able to handle new out-of-dialog SIP requests from the network. This may not
+     * be possible, however, if the IMS registration itself was lost. See the
+     * {@link DelegateRegistrationState.DeregisteredReason} reasons for more information on how SIP
+     * messages are handled in each of these cases.
+     * <p>
+     * If a feature tag is denied, no incoming messages will be routed to the associated
+     * {@link DelegateConnectionMessageCallback} and all outgoing SIP messages related to this
+     * feature tag will be rejected. See {@link SipDelegateManager.DeniedReason}
+     * reasons for more information about the conditions when this will happen.
+     * <p>
+     * The set of feature tags contained in the registered, deregistering, deregistered, and denied
+     * lists will always equal the set of feature tags requested in the initial
+     * {@link DelegateRequest}.
+     * <p>
+     * Transitions of feature tags from registered, deregistering, and deregistered and vice-versa
+     * may happen quite often, however transitions to/from denied are rare and only occur if the
+     * user has changed the role of your application to add/remove support for one or more requested
+     * feature tags or carrier provisioning has enabled or disabled single registration entirely.
+     * Please see {@link SipDelegateManager.DeniedReason} reasons for an explanation of each of
+     * these cases as well as what may cause them to change.
+     *
+     * @param registrationState The new IMS registration state of each of the feature tags
+     *     associated with the {@link SipDelegate}.
+     * @param deniedFeatureTags A list of {@link FeatureTagState} objects, each containing a feature
+     *     tag associated with this {@link SipDelegateConnection} that has no access to
+     *     send/receive SIP messages as well as a reason for why the feature tag is denied. For more
+     *     information on the reason why the feature tag was denied access, see the
+     *     {@link SipDelegateManager.DeniedReason} reasons.
+     */
+    void onFeatureTagStatusChanged(@NonNull DelegateRegistrationState registrationState,
+            @NonNull Set<FeatureTagState> deniedFeatureTags);
+
+
+    /**
+     * IMS configuration of the underlying IMS stack used by this IMS application for construction
+     * of the SIP messages that will be sent over the carrier's network.
+     * <p>
+     * There should never be assumptions made about the configuration of the underling IMS stack and
+     * the IMS application should wait for this indication before sending out any outgoing SIP
+     * messages.
+     * <p>
+     * Configuration may change due to IMS registration changes as well as
+     * other optional events on the carrier network. If IMS stack is already registered at the time
+     * of callback registration, then this method shall be invoked with the current configuration.
+     * Otherwise, there may be a delay in this method being called if initial IMS registration has
+     * not compleed yet.
+     *
+     * @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
+     */
+    void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration registeredSipConfig);
+
+    /**
+     * The previously created {@link SipDelegateConnection} instance delivered via
+     * {@link #onCreated(SipDelegateConnection)} has been destroyed. This interface should no longer
+     * be used for any SIP message handling.
+     *
+     * @param reason The reason for the failure.
+     */
+    void onDestroyed(@SipDelegateManager.SipDelegateDestroyReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 12abdd1..a6f5c45 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -17,6 +17,8 @@
 package android.telephony.ims.stub;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.RemoteException;
@@ -126,6 +128,57 @@
     }
 
     /**
+     * Called by the framework to request that the ImsService perform the network registration
+     * of all SIP delegates associated with this ImsService.
+     * <p>
+     * If the SIP delegate feature tag configuration has changed, then this method will be
+     * called in order to let the ImsService know that it can pick up these changes in the IMS
+     * registration.
+     * @hide
+     */
+    public void updateSipDelegateRegistration() {
+        // Stub implementation, ImsService should implement this
+    }
+
+
+    /**
+     * Called by the framework to request that the ImsService perform the network deregistration of
+     * all SIP delegates associated with this ImsService.
+     * <p>
+     * This is typically called in situations where the user has changed the configuration of the
+     * device (for example, the default messaging application) and the framework is reconfiguring
+     * the tags associated with each IMS application.
+     * <p>
+     * This should not affect the registration of features managed by the ImsService itself, such as
+     * feature tags related to MMTEL registration.
+     * @hide
+     */
+    public void triggerSipDelegateDeregistration() {
+        // Stub implementation, ImsService should implement this
+    }
+
+    /**
+     * Called by the framework to notify the ImsService that a SIP delegate connection has received
+     * a SIP message containing a permanent failure response (such as a 403) or an indication that a
+     * SIP response timer has timed out in response to an outgoing SIP message. This method will be
+     * called when this condition occurs to trigger the ImsService to tear down the full IMS
+     * registration and re-register again.
+     *
+     * @param sipCode The SIP error code that represents a permanent failure that was received in
+     *    response to a request generated by the IMS application. See RFC3261 7.2 for the general
+     *    classes of responses available here, however the codes that generate this condition may
+     *    be carrier specific.
+     * @param sipReason The reason associated with the SIP error code. {@code null} if there was no
+     *    reason associated with the error.
+     * @hide
+     */
+    public void triggerNetworkReregistration(@IntRange(from = 100, to = 699) int sipCode,
+            @Nullable String sipReason) {
+        // Stub implementation, ImsService should implement this
+    }
+
+
+    /**
      * Notify the framework that the device is connected to the IMS network.
      *
      * @param imsRadioTech the radio access technology. Valid values are defined as
diff --git a/telephony/java/android/telephony/ims/stub/SipDelegate.java b/telephony/java/android/telephony/ims/stub/SipDelegate.java
new file mode 100644
index 0000000..3ec9709
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/SipDelegate.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+/**
+ * The {@link SipDelegate} is implemented by the {@link ImsService} and allows a privileged
+ * IMS application to use this delegate to send SIP messages as well as acknowledge the receipt of
+ * incoming SIP messages delivered to the application over the existing IMS registration, allowing
+ * for a single IMS registration for multiple IMS applications.
+ * <p>
+ * Once the SIP delegate is created for that application,
+ * {@link ImsRegistrationImplBase#updateSipDelegateRegistration()} will be called, indicating that
+ * the application is finished setting up SipDelegates and the existing IMS registration may be
+ * modified to include the features managed by these SipDelegates.
+ * <p>
+ * This SipDelegate will need to notify the remote application of the registration of these features
+ * as well as the associated {@link SipDelegateImsConfiguration} before the application can start
+ * sending/receiving SIP messages via the transport. See
+ * {@link android.telephony.ims.DelegateStateCallback} for more information.
+ * @hide
+ */
+public interface SipDelegate {
+
+    /**
+     * The framework calls this method when a remote RCS application wishes to send a new outgoing
+     * SIP message.
+     * <p>
+     * Once sent, this SIP delegate should notify the remote application of the success or
+     * failure using {@link DelegateMessageCallback#onMessageSent(String)} or
+     * {@link DelegateMessageCallback#onMessageSendFailure(String, int)}.
+     * @param message The SIP message to be sent over the operator’s network.
+     * @param configVersion The SipDelegateImsConfiguration version used to construct the
+     *         SipMessage. See {@link SipDelegateImsConfiguration} for more information. If the
+     *         version specified here does not match the most recently constructed
+     *         {@link SipDelegateImsConfiguration}, this message should fail validation checks and
+     *         {@link DelegateMessageCallback#onMessageSendFailure} should be called with code
+     *         {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION}.
+     */
+    void sendMessage(@NonNull SipMessage message, int configVersion);
+
+    /**
+     * The framework is requesting that routing resources associated with the SIP dialog using the
+     * provided Call-ID to be cleaned up.
+     * <p>
+     * Typically a SIP Dialog close event will be signalled by that dialog receiving a BYE or 200 OK
+     * message, however, in some cases, the framework will request that the ImsService close the
+     * dialog due to the open dialog holding up an event such as applying a provisioning change or
+     * handing over to another transport type.
+     * @param callId The call-ID header value associated with the ongoing SIP Dialog that the
+     *         framework is requesting be closed.
+     */
+    void closeDialog(@NonNull String callId);
+
+    /**
+     * The remote application has received the SIP message and is processing it.
+     * @param viaTransactionId The Transaction ID found in the via header field of the
+     *                         previously sent {@link SipMessage}.
+     */
+    void notifyMessageReceived(@NonNull String viaTransactionId);
+
+    /**
+     * The remote application has either not received the SIP message or there was an error
+     * processing it.
+     * @param viaTransactionId The Transaction ID found in the via header field of the
+     *                         previously sent {@link SipMessage}.
+     * @param reason The reason why the message was not correctly received.
+     */
+    void notifyMessageReceiveError(@NonNull String viaTransactionId,
+            @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index b2b2914..b48f631 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -18,27 +18,75 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.IBinder;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateStateCallback;
 import android.telephony.ims.aidl.ISipTransport;
+import android.telephony.ims.aidl.SipDelegateAidlWrapper;
+import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
- * Manages the creation and destruction of SipDelegates in order to proxy SIP traffic to other
- * IMS applications in order to support IMS single registration.
+ * The ImsService implements this class to manage the creation and destruction of
+ * {@link SipDelegate}s.
+ *
+ * {@link SipDelegate}s allow the ImsService to forward SIP traffic generated and consumed by IMS
+ * applications as a delegate to the associated carrier's IMS Network in order to support using a
+ * single IMS registration for all MMTEL and RCS signalling traffic.
  * @hide
  */
 @SystemApi
 public class SipTransportImplBase {
+    private static final String LOG_TAG = "SipTransportIB";
+
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            mBinderExecutor.execute(() -> binderDiedInternal());
+        }
+    };
+
+    private final ISipTransport.Stub mSipTransportImpl = new ISipTransport.Stub() {
+        @Override
+        public void createSipDelegate(DelegateRequest request, ISipDelegateStateCallback dc,
+                ISipDelegateMessageCallback mc) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mBinderExecutor.execute(() -> createSipDelegateInternal(request, dc, mc));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void destroySipDelegate(ISipDelegate delegate, int reason) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mBinderExecutor.execute(() -> destroySipDelegateInternal(delegate, reason));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
 
     private final Executor mBinderExecutor;
-    private final ISipTransport mSipTransportImpl = new ISipTransport.Stub() {
-
-    };
+    private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>();
 
     /**
      * Create an implementation of SipTransportImplBase.
      *
-     * @param executor The executor that remote calls from the framework should be called on.
+     * @param executor The executor that remote calls from the framework will be called on. This
+     *                 includes the methods here as well as the methods in {@link SipDelegate}.
      */
     public SipTransportImplBase(@NonNull Executor executor) {
         if (executor == null) {
@@ -49,6 +97,79 @@
     }
 
     /**
+     * Called by the Telephony framework to request the creation of a new {@link SipDelegate}.
+     * <p>
+     * The implementation must call {@link DelegateStateCallback#onCreated(SipDelegate, List)} with
+     * the {@link SipDelegate} that is associated with the {@link DelegateRequest}.
+     * <p>
+     * This method will be called on the Executor specified in
+     * {@link SipTransportImplBase#SipTransportImplBase(Executor)}.
+     *
+     * @param request A SIP delegate request containing the parameters that the remote RCS
+     * application wishes to use.
+     * @param dc A callback back to the remote application to be used to communicate state callbacks
+     *           for the SipDelegate.
+     * @param mc A callback back to the remote application to be used to send SIP messages to the
+     *           remote application and acknowledge the sending of outgoing SIP messages.
+     * @hide
+     */
+    public void createSipDelegate(@NonNull DelegateRequest request,
+            @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) {
+        throw new UnsupportedOperationException("destroySipDelegate not implemented!");
+    }
+
+    /**
+     * Destroys the SipDelegate associated with a remote IMS application.
+     * <p>
+     * After the delegate is destroyed, {@link DelegateStateCallback#onDestroyed(int)} must be
+     * called to notify listeners of its destruction to release associated resources.
+     * <p>
+     * This method will be called on the Executor specified in
+     * {@link SipTransportImplBase#SipTransportImplBase(Executor)}.
+     * @param delegate The delegate to be destroyed.
+     * @param reason The reason the remote connection to this {@link SipDelegate} is being
+     *         destroyed.
+     * @hide
+     */
+    public void destroySipDelegate(@NonNull SipDelegate delegate,
+            @SipDelegateManager.SipDelegateDestroyReason int reason) {
+        throw new UnsupportedOperationException("destroySipDelegate not implemented!");
+    }
+
+    private void createSipDelegateInternal(DelegateRequest r, ISipDelegateStateCallback cb,
+            ISipDelegateMessageCallback mc) {
+        SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc);
+        mDelegates.add(wrapper);
+        createSipDelegate(r, wrapper, wrapper);
+    }
+
+    private void destroySipDelegateInternal(ISipDelegate d, int reason) {
+        SipDelegateAidlWrapper result = null;
+        for (SipDelegateAidlWrapper w : mDelegates) {
+            if (Objects.equals(d, w.getDelegateBinder())) {
+                result = w;
+                break;
+            }
+        }
+
+        if (result != null) {
+            mDelegates.remove(result);
+            destroySipDelegate(result.getDelegate(), reason);
+        } else {
+            Log.w(LOG_TAG, "destroySipDelegateInternal, could not findSipDelegate corresponding to "
+                    + d);
+        }
+    }
+
+    private void binderDiedInternal() {
+        for (SipDelegateAidlWrapper w : mDelegates) {
+            destroySipDelegate(w.getDelegate(),
+                    SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+        }
+        mDelegates.clear();
+    }
+
+    /**
      * @return The IInterface used by the framework.
      * @hide
      */