Merge "Deprecate AsyncTask"
diff --git a/Android.bp b/Android.bp
index 90dca03..b546430 100644
--- a/Android.bp
+++ b/Android.bp
@@ -34,6 +34,27 @@
     path: "core/java",
 }
 
+// These are subset of framework-core-sources that are needed by the
+// android.test.mock library. Ideally, the library should use public APIs only,
+// but unfortunately its API signature has some references to these private APIs.
+filegroup {
+    name: "framework-core-sources-for-test-mock",
+    srcs: [
+        "core/java/android/app/IApplicationThread.aidl",
+        "core/java/android/app/IServiceConnection.aidl",
+        "core/java/android/content/IContentProvider.java",
+        "core/java/android/content/pm/IPackageDataObserver.aidl",
+        "core/java/android/content/pm/InstantAppInfo.java",
+        "core/java/android/content/pm/KeySet.java",
+        "core/java/android/content/pm/PackageManager.java",
+        "core/java/android/content/pm/VerifierDeviceIdentity.java",
+        "core/java/android/content/res/Resources.java",
+        "core/java/android/os/storage/VolumeInfo.java",
+        "core/java/android/view/DisplayAdjustments.java",
+    ],
+    path: "core/java",
+}
+
 filegroup {
     name: "framework-drm-sources",
     srcs: [
@@ -162,6 +183,23 @@
 }
 
 filegroup {
+    name: "framework-telephony-common-sources",
+    srcs: [
+        "telephony/common/**/*.java",
+    ],
+    path: "telephony/common",
+}
+
+filegroup {
+    name: "framework-mms-sources",
+    srcs: [
+        "mms/java/**/*.java",
+        "mms/java/**/*.aidl",
+    ],
+    path: "mms/java",
+}
+
+filegroup {
     name: "framework-wifi-sources",
     srcs: [
         "wifi/java/**/*.java",
@@ -185,10 +223,12 @@
         ":framework-mca-filterfw-sources",
         ":framework-mca-filterpacks-sources",
         ":framework-mime-sources",
+        ":framework-mms-sources",
         ":framework-opengl-sources",
         ":framework-rs-sources",
         ":framework-sax-sources",
         ":framework-telecomm-sources",
+        ":framework-telephony-common-sources",
         ":framework-telephony-sources",
         ":framework-wifi-sources",
         ":PacProcessor-aidl-sources",
@@ -246,6 +286,7 @@
             "media/mca/effect/java",
             "media/mca/filterfw/java",
             "media/mca/filterpacks/java",
+            "mms/java",
             "opengl/java",
             "rs/java",
             "sax/java",
@@ -830,9 +871,11 @@
     "media/mca/filterfw/java",
     "media/mca/filterpacks/java",
     "drm/java",
+    "mms/java",
     "opengl/java",
     "sax/java",
     "telecomm/java",
+    "telephony/common",
     "telephony/java",
     "wifi/java",
     "lowpan/java",
@@ -915,10 +958,10 @@
 
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
     "--ignore-classes-on-classpath " +
-    "--hide-package com.android.okhttp " +
-    "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
+    "--hide-package com.android.server " +
     "--error UnhiddenSystemApi " +
     "--hide RequiresPermission " +
+    "--hide CallbackInterface " +
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo "
@@ -1401,8 +1444,6 @@
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
     srcs: [
-        ":non_openjdk_java_files",
-        ":openjdk_java_files",
         ":opt-telephony-common-srcs",
     ],
 
@@ -1493,6 +1534,10 @@
             api_file: "api/test-current.txt",
             removed_api_file: "api/test-removed.txt",
         },
+        api_lint: {
+            enabled: true,
+            baseline_file: "api/test-lint-baseline.txt",
+        },
     },
 }
 
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6a909c0..f7a2858 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -254,6 +254,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DefaultContainerService)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/CaptivePortalLogin)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ext.jar)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/google/android/mms)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index e731138..6831117 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,6 @@
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 
-api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREUPLOAD_COMMIT}
-
 strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
 
 hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/api/current.txt b/api/current.txt
index ec4110a..f51f345 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2815,7 +2815,7 @@
     method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
-    method @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) @NonNull public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
+    method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -3524,11 +3524,11 @@
 
 package android.annotation {
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface SuppressLint {
     method public abstract String[] value();
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface TargetApi {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD}) public @interface TargetApi {
     method public abstract int value();
   }
 
@@ -3741,7 +3741,7 @@
     method public void onContentChanged();
     method public boolean onContextItemSelected(@NonNull android.view.MenuItem);
     method public void onContextMenuClosed(@NonNull android.view.Menu);
-    method @MainThread @CallSuper protected void onCreate(@Nullable android.os.Bundle);
+    method @CallSuper @MainThread protected void onCreate(@Nullable android.os.Bundle);
     method public void onCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
     method @Nullable public CharSequence onCreateDescription();
@@ -3883,8 +3883,8 @@
     method public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
     method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int);
     method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
-    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int);
-    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
+    method public boolean startActivityIfNeeded(@NonNull @RequiresPermission android.content.Intent, int);
+    method public boolean startActivityIfNeeded(@NonNull @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
     method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -3892,8 +3892,8 @@
     method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
     method @Deprecated public void startManagingCursor(android.database.Cursor);
-    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent);
-    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent, @Nullable android.os.Bundle);
+    method public boolean startNextMatchingActivity(@NonNull @RequiresPermission android.content.Intent);
+    method public boolean startNextMatchingActivity(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
     method public void startPostponedEnterTransition();
     method public void startSearch(@Nullable String, boolean, @Nullable android.os.Bundle, boolean);
     method public void stopLocalVoiceInteraction();
@@ -6642,7 +6642,7 @@
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
     method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
-    method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
+    method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
     method public boolean getAutoTimeRequired();
     method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
@@ -7562,7 +7562,7 @@
     method public int checkSlicePermission(@NonNull android.net.Uri, int, int);
     method @NonNull public java.util.List<android.net.Uri> getPinnedSlices();
     method @NonNull public java.util.Set<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
-    method @WorkerThread @NonNull public java.util.Collection<android.net.Uri> getSliceDescendants(@NonNull android.net.Uri);
+    method @NonNull @WorkerThread public java.util.Collection<android.net.Uri> getSliceDescendants(@NonNull android.net.Uri);
     method public void grantSlicePermission(@NonNull String, @NonNull android.net.Uri);
     method @Nullable public android.net.Uri mapIntentToUri(@NonNull android.content.Intent);
     method public void pinSlice(@NonNull android.net.Uri, @NonNull java.util.Set<android.app.slice.SliceSpec>);
@@ -7718,10 +7718,10 @@
   public class StorageStatsManager {
     method @WorkerThread public long getFreeBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getTotalBytes(@NonNull java.util.UUID) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.ExternalStorageStats queryExternalStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUid(@NonNull java.util.UUID, int) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.ExternalStorageStats queryExternalStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForUid(@NonNull java.util.UUID, int) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -7980,9 +7980,9 @@
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
@@ -8350,9 +8350,9 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
@@ -9517,14 +9517,14 @@
     method public static void addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long);
     method public static Object addStatusChangeListener(int, android.content.SyncStatusObserver);
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public final int bulkInsert(@RequiresPermission.Write @NonNull android.net.Uri, @NonNull android.content.ContentValues[]);
+    method public final int bulkInsert(@NonNull @RequiresPermission.Write android.net.Uri, @NonNull android.content.ContentValues[]);
     method @Nullable public final android.os.Bundle call(@NonNull android.net.Uri, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
     method @Nullable public final android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated public void cancelSync(android.net.Uri);
     method public static void cancelSync(android.accounts.Account, String);
     method public static void cancelSync(android.content.SyncRequest);
     method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri);
-    method public final int delete(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable String, @Nullable String[]);
+    method public final int delete(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable String, @Nullable String[]);
     method @Deprecated public static android.content.SyncInfo getCurrentSync();
     method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
     method public static int getIsSyncable(android.accounts.Account, String);
@@ -9537,7 +9537,7 @@
     method public static boolean getSyncAutomatically(android.accounts.Account, String);
     method @Nullable public final String getType(@NonNull android.net.Uri);
     method @NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String);
-    method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
+    method @Nullable public final android.net.Uri insert(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable android.content.ContentValues);
     method public static boolean isSyncActive(android.accounts.Account, String);
     method public static boolean isSyncPending(android.accounts.Account, String);
     method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
@@ -9556,9 +9556,9 @@
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
     method public final boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
     method public final void registerContentObserver(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver);
     method public void releasePersistableUriPermission(@NonNull android.net.Uri, int);
@@ -9573,7 +9573,7 @@
     method public void takePersistableUriPermission(@NonNull android.net.Uri, int);
     method @Nullable public final android.net.Uri uncanonicalize(@NonNull android.net.Uri);
     method public final void unregisterContentObserver(@NonNull android.database.ContentObserver);
-    method public final int update(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
+    method public final int update(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
     method public static void validateSyncExtrasBundle(android.os.Bundle);
     method @NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider);
     method @NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient);
@@ -9669,9 +9669,9 @@
 
   public abstract class Context {
     ctor public Context();
-    method public boolean bindIsolatedService(@RequiresPermission @NonNull android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
+    method public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
     method public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int);
-    method public boolean bindService(@RequiresPermission @NonNull android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
+    method public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
     method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
     method @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
     method @CheckResult(suggest="#enforceCallingPermission(String,String)") public abstract int checkCallingPermission(@NonNull String);
@@ -9768,7 +9768,8 @@
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String);
     method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
-    method public abstract void sendOrderedBroadcast(@RequiresPermission @NonNull android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -11621,7 +11622,7 @@
     method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int);
     method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle);
     method @NonNull public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence, @NonNull android.os.UserHandle);
-    method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions(@NonNull String, int);
+    method @NonNull @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions(@NonNull String, int);
     method @Nullable public abstract android.content.res.XmlResourceParser getXml(@NonNull String, @XmlRes int, @Nullable android.content.pm.ApplicationInfo);
     method public boolean hasSigningCertificate(@NonNull String, @NonNull byte[], int);
     method public boolean hasSigningCertificate(int, @NonNull byte[], int);
@@ -12312,7 +12313,7 @@
     ctor @Deprecated public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
     method public final void finishPreloading();
     method public final void flushLayoutCache();
-    method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimatorRes @AnimRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimRes @AnimatorRes int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
     method @AnyRes public static int getAttributeSetSourceResId(@Nullable android.util.AttributeSet);
     method public boolean getBoolean(@BoolRes int) throws android.content.res.Resources.NotFoundException;
@@ -13582,10 +13583,10 @@
     method public static android.graphics.Bitmap createBitmap(int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean);
     method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
-    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@NonNull android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@ColorInt @NonNull int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.util.DisplayMetrics, @ColorInt @NonNull int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@ColorInt @NonNull int[], int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, @ColorInt @NonNull int[], int, int, @NonNull android.graphics.Bitmap.Config);
     method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture);
     method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture, int, int, @NonNull android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createScaledBitmap(@NonNull android.graphics.Bitmap, int, int, boolean);
@@ -13816,8 +13817,8 @@
     method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint);
     method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.Paint);
     method public void drawLine(float, float, float, float, @NonNull android.graphics.Paint);
-    method public void drawLines(@Size(multiple=4) @NonNull float[], int, int, @NonNull android.graphics.Paint);
-    method public void drawLines(@Size(multiple=4) @NonNull float[], @NonNull android.graphics.Paint);
+    method public void drawLines(@NonNull @Size(multiple=4) float[], int, int, @NonNull android.graphics.Paint);
+    method public void drawLines(@NonNull @Size(multiple=4) float[], @NonNull android.graphics.Paint);
     method public void drawOval(@NonNull android.graphics.RectF, @NonNull android.graphics.Paint);
     method public void drawOval(float, float, float, float, @NonNull android.graphics.Paint);
     method public void drawPaint(@NonNull android.graphics.Paint);
@@ -13827,7 +13828,7 @@
     method public void drawPicture(@NonNull android.graphics.Picture, @NonNull android.graphics.Rect);
     method public void drawPoint(float, float, @NonNull android.graphics.Paint);
     method public void drawPoints(@Size(multiple=2) float[], int, int, @NonNull android.graphics.Paint);
-    method public void drawPoints(@Size(multiple=2) @NonNull float[], @NonNull android.graphics.Paint);
+    method public void drawPoints(@NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method @Deprecated public void drawPosText(@NonNull char[], int, int, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method @Deprecated public void drawPosText(@NonNull String, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method public void drawRGB(int, int, int);
@@ -14188,10 +14189,10 @@
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.nio.ByteBuffer);
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.io.File);
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
-    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
     method public int getAllocator();
     method @Nullable public android.graphics.Rect getCrop();
     method public int getMemorySizePolicy();
@@ -14210,7 +14211,7 @@
     method public void setPostProcessor(@Nullable android.graphics.PostProcessor);
     method public void setTargetColorSpace(android.graphics.ColorSpace);
     method public void setTargetSampleSize(@IntRange(from=1) int);
-    method public void setTargetSize(@Px @IntRange(from=1) int, @Px @IntRange(from=1) int);
+    method public void setTargetSize(@IntRange(from=1) @Px int, @IntRange(from=1) @Px int);
     method public void setUnpremultipliedRequired(boolean);
     field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
@@ -14317,8 +14318,8 @@
   }
 
   public class LinearGradient extends android.graphics.Shader {
-    ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
-    ctor public LinearGradient(float, float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
     ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
     ctor public LinearGradient(float, float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
   }
@@ -14860,8 +14861,8 @@
   }
 
   public class RadialGradient extends android.graphics.Shader {
-    ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
-    ctor public RadialGradient(float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
     ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
     ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
   }
@@ -15119,8 +15120,8 @@
   }
 
   public class SweepGradient extends android.graphics.Shader {
-    ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]);
-    ctor public SweepGradient(float, float, @NonNull @ColorLong long[], @Nullable float[]);
+    ctor public SweepGradient(float, float, @ColorInt @NonNull int[], @Nullable float[]);
+    ctor public SweepGradient(float, float, @ColorLong @NonNull long[], @Nullable float[]);
     ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int);
     ctor public SweepGradient(float, float, @ColorLong long, @ColorLong long);
   }
@@ -15513,8 +15514,8 @@
     method public void setColor(@ColorInt int);
     method public void setColor(@Nullable android.content.res.ColorStateList);
     method public void setColorFilter(@Nullable android.graphics.ColorFilter);
-    method public void setColors(@Nullable @ColorInt int[]);
-    method public void setColors(@Nullable @ColorInt int[], @Nullable float[]);
+    method public void setColors(@ColorInt @Nullable int[]);
+    method public void setColors(@ColorInt @Nullable int[], @Nullable float[]);
     method public void setCornerRadii(@Nullable float[]);
     method public void setCornerRadius(float);
     method public void setDither(boolean);
@@ -15962,14 +15963,14 @@
 
   public static class LineBreaker.ParagraphConstraints {
     ctor public LineBreaker.ParagraphConstraints();
-    method @Px @FloatRange(from=0) public float getDefaultTabStop();
-    method @Px @FloatRange(from=0.0f) public float getFirstWidth();
-    method @Px @IntRange(from=0) public int getFirstWidthLineCount();
+    method @FloatRange(from=0) @Px public float getDefaultTabStop();
+    method @FloatRange(from=0.0f) @Px public float getFirstWidth();
+    method @IntRange(from=0) @Px public int getFirstWidthLineCount();
     method @Nullable public float[] getTabStops();
-    method @Px @FloatRange(from=0.0f) public float getWidth();
-    method public void setIndent(@Px @FloatRange(from=0.0f) float, @Px @IntRange(from=0) int);
-    method public void setTabStops(@Nullable float[], @Px @FloatRange(from=0) float);
-    method public void setWidth(@Px @FloatRange(from=0.0f) float);
+    method @FloatRange(from=0.0f) @Px public float getWidth();
+    method public void setIndent(@FloatRange(from=0.0f) @Px float, @IntRange(from=0) @Px int);
+    method public void setTabStops(@Nullable float[], @FloatRange(from=0) @Px float);
+    method public void setWidth(@FloatRange(from=0.0f) @Px float);
   }
 
   public static class LineBreaker.Result {
@@ -15992,7 +15993,7 @@
   public static final class MeasuredText.Builder {
     ctor public MeasuredText.Builder(@NonNull char[]);
     ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText);
-    method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @Px @FloatRange(from=0) float);
+    method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
     method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
     method @NonNull public android.graphics.text.MeasuredText build();
     method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
@@ -23003,7 +23004,7 @@
     method @Nullable public String getGnssHardwareModelName();
     method public int getGnssYearOfHardware();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) @Nullable public android.location.Location getLastKnownLocation(@NonNull String);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
     method @Nullable public android.location.LocationProvider getProvider(@NonNull String);
     method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
     method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
@@ -28457,17 +28458,17 @@
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean bindProcessToNetwork(@Nullable android.net.Network);
     method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.Network getActiveNetwork();
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @NonNull public android.net.Network[] getAllNetworks();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
     method @Deprecated public boolean getBackgroundDataSetting();
     method @Nullable public android.net.Network getBoundNetworkForProcess();
     method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
     method @Nullable public android.net.ProxyInfo getDefaultProxy();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
     method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
@@ -29366,7 +29367,8 @@
   }
 
   public class AudioGroup {
-    ctor public AudioGroup();
+    ctor @Deprecated public AudioGroup();
+    ctor public AudioGroup(@Nullable android.content.Context);
     method public void clear();
     method public int getMode();
     method public android.net.rtp.AudioStream[] getStreams();
@@ -30773,10 +30775,10 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method public boolean removeAidsForService(android.content.ComponentName, String);
-    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method public boolean supportsAidPrefixRegistration();
-    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
     field public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
     field public static final String CATEGORY_OTHER = "other";
@@ -34431,7 +34433,7 @@
     method public void addData(String, byte[], int);
     method public void addFile(String, java.io.File, int) throws java.io.IOException;
     method public void addText(String, String);
-    method @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.DropBoxManager.Entry getNextEntry(String, long);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.DropBoxManager.Entry getNextEntry(String, long);
     method public boolean isTagEnabled(String);
     field public static final String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
     field public static final String EXTRA_DROPPED_COUNT = "android.os.extra.DROPPED_COUNT";
@@ -42666,6 +42668,7 @@
     field public static final int IP_MULTICAST_TTL;
     field public static final int IP_TOS;
     field public static final int IP_TTL;
+    field public static final int MAP_ANONYMOUS;
     field public static final int MAP_FIXED;
     field public static final int MAP_PRIVATE;
     field public static final int MAP_SHARED;
@@ -43800,7 +43803,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
     method @Nullable public String getSystemDialerPackage();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
@@ -44295,6 +44298,8 @@
   public abstract class CellInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getCellConnectionStatus();
+    method @NonNull public abstract android.telephony.CellIdentity getCellIdentity();
+    method @NonNull public abstract android.telephony.CellSignalStrength getCellSignalStrength();
     method public long getTimeStamp();
     method public boolean isRegistered();
     field public static final int CONNECTION_NONE = 0; // 0x0
@@ -44439,6 +44444,7 @@
     method public int describeContents();
     method public int getAsuLevel();
     method public int getDbm();
+    method public int getEcNo();
     method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR;
@@ -44726,6 +44732,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
+    method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
     method public int getSubscriptionId();
     method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
     method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
@@ -44733,6 +44740,7 @@
     method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
     method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSmscAddress(@NonNull String);
     field public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
     field public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
     field public static final String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -44919,6 +44927,7 @@
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
+    field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
     field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
     field public static final int INVALID_SIM_SLOT_INDEX = -1; // 0xffffffff
     field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
@@ -44984,8 +44993,8 @@
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
     method public String getIccAuthentication(int, int, String);
@@ -45019,11 +45028,12 @@
     method @Nullable public CharSequence getSimSpecificCarrierIdName();
     method public int getSimState();
     method public int getSimState(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubIdForPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId();
     method public int getSupportedModemCount();
     method @Nullable public String getTypeAllocationCode();
     method @Nullable public String getTypeAllocationCode(int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
@@ -46957,7 +46967,7 @@
   }
 
   public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan android.text.ParcelableSpan {
-    ctor public LineHeightSpan.Standard(@Px @IntRange(from=1) int);
+    ctor public LineHeightSpan.Standard(@IntRange(from=1) @Px int);
     ctor public LineHeightSpan.Standard(@NonNull android.os.Parcel);
     method public void chooseHeight(@NonNull CharSequence, int, int, int, int, @NonNull android.graphics.Paint.FontMetricsInt);
     method public int describeContents();
@@ -51086,11 +51096,11 @@
     field @Deprecated public static final boolean TRACE_RECYCLER = false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.CapturedViewProperty {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface ViewDebug.CapturedViewProperty {
     method public abstract boolean retrieveReturn() default false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.ExportedProperty {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface ViewDebug.ExportedProperty {
     method public abstract String category() default "";
     method public abstract boolean deepExport() default false;
     method public abstract android.view.ViewDebug.FlagToString[] flagMapping() default {};
@@ -51102,7 +51112,7 @@
     method public abstract boolean resolveId() default false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.FlagToString {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface ViewDebug.FlagToString {
     method public abstract int equals();
     method public abstract int mask();
     method public abstract String name();
@@ -51120,7 +51130,7 @@
     enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType REQUEST_LAYOUT;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.IntToString {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface ViewDebug.IntToString {
     method public abstract int from();
     method public abstract String to();
   }
@@ -53669,18 +53679,18 @@
   }
 
   public interface TextClassifier {
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull android.view.textclassifier.TextClassification.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextClassification classifyText(@NonNull android.view.textclassifier.TextClassification.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextClassification classifyText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
     method public default void destroy();
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextLanguage detectLanguage(@NonNull android.view.textclassifier.TextLanguage.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextLinks generateLinks(@NonNull android.view.textclassifier.TextLinks.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextLanguage detectLanguage(@NonNull android.view.textclassifier.TextLanguage.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextLinks generateLinks(@NonNull android.view.textclassifier.TextLinks.Request);
     method @WorkerThread public default int getMaxGenerateLinksTextLength();
     method public default boolean isDestroyed();
     method public default void onSelectionEvent(@NonNull android.view.textclassifier.SelectionEvent);
     method public default void onTextClassifierEvent(@NonNull android.view.textclassifier.TextClassifierEvent);
-    method @WorkerThread @NonNull public default android.view.textclassifier.ConversationActions suggestConversationActions(@NonNull android.view.textclassifier.ConversationActions.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
+    method @NonNull @WorkerThread public default android.view.textclassifier.ConversationActions suggestConversationActions(@NonNull android.view.textclassifier.ConversationActions.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
     field public static final String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER";
     field public static final String HINT_TEXT_IS_EDITABLE = "android.text_is_editable";
     field public static final String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable";
@@ -56143,12 +56153,12 @@
     ctor public Magnifier.Builder(@NonNull android.view.View);
     method @NonNull public android.widget.Magnifier build();
     method @NonNull public android.widget.Magnifier.Builder setClippingEnabled(boolean);
-    method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@FloatRange(from=0) @Px float);
     method @NonNull public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(@Px int, @Px int);
-    method @NonNull public android.widget.Magnifier.Builder setElevation(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setElevation(@FloatRange(from=0) @Px float);
     method @NonNull public android.widget.Magnifier.Builder setInitialZoom(@FloatRange(from=0.0f) float);
     method @NonNull public android.widget.Magnifier.Builder setOverlay(@Nullable android.graphics.drawable.Drawable);
-    method @NonNull public android.widget.Magnifier.Builder setSize(@Px @IntRange(from=0) int, @Px @IntRange(from=0) int);
+    method @NonNull public android.widget.Magnifier.Builder setSize(@IntRange(from=0) @Px int, @IntRange(from=0) @Px int);
     method @NonNull public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
   }
 
@@ -56642,7 +56652,7 @@
     method @NonNull public static android.widget.RemoteViews.RemoteResponse fromPendingIntent(@NonNull android.app.PendingIntent);
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface RemoteViews.RemoteView {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface RemoteViews.RemoteView {
   }
 
   public abstract class RemoteViewsService extends android.app.Service {
@@ -57318,7 +57328,7 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFallbackLineSpacing(boolean);
     method public void setFilters(android.text.InputFilter[]);
-    method public void setFirstBaselineToTopHeight(@Px @IntRange(from=0) int);
+    method public void setFirstBaselineToTopHeight(@IntRange(from=0) @Px int);
     method public void setFontFeatureSettings(@Nullable String);
     method public boolean setFontVariationSettings(@Nullable String);
     method protected boolean setFrame(int, int, int, int);
@@ -57340,9 +57350,9 @@
     method public void setInputType(int);
     method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
-    method public void setLastBaselineToBottomHeight(@Px @IntRange(from=0) int);
+    method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
     method public void setLetterSpacing(float);
-    method public void setLineHeight(@Px @IntRange(from=0) int);
+    method public void setLineHeight(@IntRange(from=0) @Px int);
     method public void setLineSpacing(float, float);
     method public void setLines(int);
     method public final void setLinkTextColor(@ColorInt int);
@@ -60397,7 +60407,7 @@
     ctor public OutOfMemoryError(String);
   }
 
-  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface Override {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Override {
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
@@ -60889,9 +60899,9 @@
     method @NonNull public StringBuilder reverse();
     method public void setCharAt(int, char);
     method public void setLength(int);
-    method public CharSequence subSequence(int, int);
-    method public String substring(int);
-    method public String substring(int, int);
+    method @NonNull public CharSequence subSequence(int, int);
+    method @NonNull public String substring(int);
+    method @NonNull public String substring(int, int);
     method public void trimToSize();
   }
 
@@ -60901,7 +60911,7 @@
     ctor public StringIndexOutOfBoundsException(int);
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface SuppressWarnings {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface SuppressWarnings {
     method public abstract String[] value();
   }
 
@@ -71224,20 +71234,20 @@
     method public boolean addAll(@NonNull java.util.Collection<? extends K>);
     method public final void clear();
     method public boolean contains(@NonNull Object);
-    method public final boolean containsAll(java.util.Collection<?>);
+    method public final boolean containsAll(@NonNull java.util.Collection<?>);
     method public void forEach(@NonNull java.util.function.Consumer<? super K>);
-    method public java.util.concurrent.ConcurrentHashMap<K,V> getMap();
+    method @NonNull public java.util.concurrent.ConcurrentHashMap<K,V> getMap();
     method @Nullable public V getMappedValue();
     method public final boolean isEmpty();
     method @NonNull public java.util.Iterator<K> iterator();
     method public boolean remove(@NonNull Object);
-    method public final boolean removeAll(java.util.Collection<?>);
-    method public final boolean retainAll(java.util.Collection<?>);
+    method public final boolean removeAll(@NonNull java.util.Collection<?>);
+    method public final boolean retainAll(@NonNull java.util.Collection<?>);
     method public final int size();
     method @NonNull public java.util.Spliterator<K> spliterator();
-    method public final Object[] toArray();
-    method public final <T> T[] toArray(T[]);
-    method public final String toString();
+    method @NonNull public final Object[] toArray();
+    method @NonNull public final <T> T[] toArray(@NonNull T[]);
+    method @NonNull public final String toString();
   }
 
   public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection<E> implements java.util.Deque<E> java.io.Serializable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6574c80..94dc126 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -568,7 +568,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
@@ -1242,9 +1242,13 @@
     method public boolean disableBLE();
     method public boolean enableBLE();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset();
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public long getDiscoveryEndMillis();
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isLeEnabled();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int, int);
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int);
     field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
     field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
   }
@@ -1355,7 +1359,7 @@
     method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@RequiresPermission @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BUGREPORT_SERVICE = "bugreport";
@@ -1373,6 +1377,7 @@
     field public static final String STATS_MANAGER = "stats";
     field public static final String STATUS_BAR_SERVICE = "statusbar";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
+    field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
     field public static final String VR_SERVICE = "vrmanager";
     field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
     field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -1842,8 +1847,8 @@
 
   public final class RollbackManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -2353,24 +2358,24 @@
   }
 
   public final class ContextHubManager {
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] getContextHubHandles();
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
     method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int unloadNanoApp(int);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     field public static final int EVENT_HUB_RESET = 6; // 0x6
     field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
@@ -3035,7 +3040,7 @@
   }
 
   public final class UsbPort {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) @Nullable public android.hardware.usb.UsbPortStatus getStatus();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
   }
 
@@ -3428,7 +3433,7 @@
     method @NonNull public android.location.LocationRequest setFastestInterval(long);
     method public void setHideFromAppOps(boolean);
     method @NonNull public android.location.LocationRequest setInterval(long);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @NonNull public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
     method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
     method @NonNull public android.location.LocationRequest setNumUpdates(int);
     method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
@@ -4432,7 +4437,8 @@
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
     method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
     method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
   }
 
 }
@@ -4698,8 +4704,11 @@
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
     method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
     field public static final int CHANGE_REASON_ADDED = 0; // 0x0
     field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -4714,10 +4723,16 @@
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
     field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
+    field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
+    field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
     field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
     field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
     field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+    field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
+    field public static final int IFACE_IP_MODE_LOCAL_ONLY = 2; // 0x2
+    field public static final int IFACE_IP_MODE_TETHERED = 1; // 0x1
+    field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff
     field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
     field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
     field public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
@@ -5315,8 +5330,8 @@
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
@@ -5639,6 +5654,14 @@
 
 }
 
+package android.os.telephony {
+
+  public class TelephonyRegistryManager {
+    method public void notifyCarrierNetworkChange(boolean);
+  }
+
+}
+
 package android.permission {
 
   public final class PermissionControllerManager {
@@ -6122,7 +6145,7 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
@@ -6202,18 +6225,18 @@
   }
 
   public class RecoveryController {
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public android.security.keystore.recovery.RecoverySession createRecoverySession();
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.RecoverySession createRecoverySession();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
+    method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
+    method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void initRecoveryService(@NonNull String, @NonNull byte[], @NonNull byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static boolean isRecoverableKeyStoreEnabled(@NonNull android.content.Context);
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void removeKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
@@ -6228,8 +6251,8 @@
 
   public class RecoverySession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void close();
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
   }
 
   public class SessionExpiredException extends java.security.GeneralSecurityException {
@@ -6370,7 +6393,29 @@
   public abstract class ApnService extends android.app.Service {
     ctor public ApnService();
     method @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
-    method @WorkerThread @NonNull public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
+    method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
+  }
+
+  public abstract class CarrierMessagingServiceWrapper {
+    ctor public CarrierMessagingServiceWrapper();
+    method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String);
+    method public void disposeConnection(@NonNull android.content.Context);
+    method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void filterSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public abstract void onServiceReady();
+    method public void sendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+  }
+
+  public abstract static class CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper {
+    ctor public CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper();
+    method public void onDownloadMmsComplete(int);
+    method public void onFilterComplete(int);
+    method public void onSendMmsComplete(int, @Nullable byte[]);
+    method public void onSendMultipartSmsComplete(int, @Nullable int[]);
+    method public void onSendSmsComplete(int, int);
   }
 
 }
@@ -6482,13 +6527,13 @@
     method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(@Nullable java.util.List<android.telephony.UiccAccessRule>);
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) public static @interface EuiccProfileInfo.PolicyRule {
+  @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.PolicyRule {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileClass {
+  @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileClass {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileState {
+  @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileState {
   }
 
   public abstract class EuiccService extends android.app.Service {
@@ -6667,7 +6712,7 @@
 package android.service.oemlock {
 
   public class OemLockManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) @Nullable public String getLockName();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public String getLockName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByCarrier();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByCarrier(boolean, @Nullable byte[]);
@@ -6680,7 +6725,7 @@
 
   public class PersistentDataBlockManager {
     method @RequiresPermission("android.permission.ACCESS_PDB_STATE") public int getDataBlockSize();
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) @android.service.persistentdata.PersistentDataBlockManager.FlashLockState public int getFlashLockState();
+    method @android.service.persistentdata.PersistentDataBlockManager.FlashLockState @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public int getFlashLockState();
     method public long getMaximumDataBlockSize();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public boolean getOemUnlockEnabled();
     method public byte[] read();
@@ -7245,9 +7290,10 @@
 
   public abstract class CellBroadcastService extends android.app.Service {
     ctor public CellBroadcastService();
-    method @CallSuper public android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onCdmaCellBroadcastSms(int, byte[]);
-    method public abstract void onGsmCellBroadcastSms(int, byte[]);
+    method @CallSuper @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int);
+    method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>);
+    method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]);
     field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
   }
 
@@ -8159,7 +8205,6 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
-    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
@@ -8180,6 +8225,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
     method public static long getMaxNumberVerificationTimeoutMillis();
+    method @NonNull public String getNetworkCountryIso(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
     method public int getSimApplicationState();
@@ -8200,6 +8246,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
     method public boolean isDataConnectivityPossible();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
@@ -8213,6 +8260,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
+    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
@@ -8235,6 +8283,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
     method public void updateServiceLocation();
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED = "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -8530,10 +8579,10 @@
     field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) public static @interface EuiccCardManager.CancelReason {
+  @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.CancelReason {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) public static @interface EuiccCardManager.ResetOption {
+  @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.ResetOption {
   }
 
   public static interface EuiccCardManager.ResultCallback<T> {
@@ -8589,7 +8638,7 @@
     field public static final int EVENT_INSTALL = 1; // 0x1
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) public static @interface EuiccNotification.Event {
+  @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccNotification.Event {
   }
 
   public final class EuiccRulesAuthTable implements android.os.Parcelable {
@@ -8607,7 +8656,7 @@
     method public android.telephony.euicc.EuiccRulesAuthTable build();
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
+  @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
   }
 
 }
@@ -8811,20 +8860,23 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
   }
 
-  public class ImsMmTelManager {
+  public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.function.Consumer<java.lang.Boolean>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
@@ -8834,7 +8886,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
     field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
     field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
@@ -8846,12 +8899,8 @@
     method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
   }
 
-  public static class ImsMmTelManager.RegistrationCallback {
-    ctor public ImsMmTelManager.RegistrationCallback();
-    method public void onRegistered(int);
-    method public void onRegistering(int);
-    method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
-    method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+  @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
+    ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
@@ -9227,14 +9276,17 @@
   }
 
   public class ImsUtListener {
+    method public void onLineIdentificationSupplementaryServiceResponse(int, @NonNull android.telephony.ims.ImsSsInfo);
     method public void onSupplementaryServiceIndication(android.telephony.ims.ImsSsData);
     method public void onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]);
     method public void onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]);
     method public void onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]);
-    method public void onUtConfigurationQueried(int, android.os.Bundle);
+    method @Deprecated public void onUtConfigurationQueried(int, android.os.Bundle);
     method public void onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo);
     method public void onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo);
     method public void onUtConfigurationUpdated(int);
+    field @Deprecated public static final String BUNDLE_KEY_CLIR = "queryClir";
+    field @Deprecated public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
   }
 
   public abstract class ImsVideoCallProvider {
@@ -9261,12 +9313,12 @@
 
   public class ProvisioningManager {
     method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
     field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
@@ -9283,6 +9335,24 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
+  public interface RegistrationManager {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
+    field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
+    field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1
+  }
+
+  public static class RegistrationManager.RegistrationCallback {
+    ctor public RegistrationManager.RegistrationCallback();
+    method public void onRegistered(int);
+    method public void onRegistering(int);
+    method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
+    method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+  }
+
 }
 
 package android.telephony.ims.feature {
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index fffec3e..c64e3d8 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -127,6 +127,12 @@
     
 
 
+MutableBareField: android.net.wifi.WifiConfiguration#allowAutojoin:
+    
+MutableBareField: android.net.wifi.WifiConfiguration#carrierId:
+    
+
+
 NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
     
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 716f0c6..a82ec4e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -793,8 +793,8 @@
   public final class RollbackManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
@@ -1078,7 +1078,7 @@
     method @NonNull public android.location.LocationRequest setExpireIn(long);
     method @NonNull public android.location.LocationRequest setFastestInterval(long);
     method @NonNull public android.location.LocationRequest setInterval(long);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @NonNull public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
     method @NonNull public android.location.LocationRequest setNumUpdates(int);
     method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
     method @NonNull public android.location.LocationRequest setQuality(int);
@@ -1654,7 +1654,8 @@
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
     method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
     method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
   }
 
 }
@@ -1852,8 +1853,8 @@
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
@@ -2398,7 +2399,7 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
@@ -2898,6 +2899,7 @@
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
+    method @NonNull public String getNetworkCountryIso(int);
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
new file mode 100644
index 0000000..1f85f3f
--- /dev/null
+++ b/api/test-lint-baseline.txt
@@ -0,0 +1,2263 @@
+// Baseline format: 1.0
+AcronymName: android.app.NotificationChannel#isImportanceLockedByOEM():
+    
+AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean):
+    
+
+
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_CLEANUP:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_DOWNLOAD_RESULT_INTERNAL:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_FILE_DESCRIPTOR_REQUEST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FD_COUNT:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FINAL_URI:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FREE_URI_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_URI_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_SERVICE_ID:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILES_IN_USE:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILE_ROOT:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_LIST:
+    
+
+
+ArrayReturn: android.app.UiAutomation#executeShellCommandRw(String):
+    
+ArrayReturn: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
+    
+ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
+    
+ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
+    
+ArrayReturn: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
+    
+ArrayReturn: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
+    
+ArrayReturn: android.metrics.LogMaker#serialize():
+    
+ArrayReturn: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]) parameter #0:
+    
+ArrayReturn: android.os.HwBlob#wrapArray(boolean[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(byte[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(double[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(float[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(int[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(long[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(short[]):
+    
+ArrayReturn: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor[], int[], boolean) parameter #0:
+    
+ArrayReturn: android.os.NativeHandle#getFileDescriptors():
+    
+ArrayReturn: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]):
+    
+ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
+    
+ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
+    
+ArrayReturn: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
+    
+ArrayReturn: android.view.inspector.InspectableProperty#enumMapping():
+    
+ArrayReturn: android.view.inspector.InspectableProperty#flagMapping():
+    
+
+
+AutoBoxing: android.os.HwBlob#wrapArray(byte[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(double[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(float[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(int[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(long[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(short[]):
+    
+AutoBoxing: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
+    
+
+
+BannedThrow: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]):
+    
+BannedThrow: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]):
+    
+BannedThrow: android.app.ActivityTaskManager#resizeStack(int, android.graphics.Rect):
+    
+BannedThrow: android.app.ActivityTaskManager#setTaskWindowingMode(int, int, boolean):
+    
+BannedThrow: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, int[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, short[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int[], short[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, int):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, short):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], int[]):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#build():
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#setFocusDuckingBehavior(int):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#addMix(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#setLooper(android.os.Looper):
+    
+BannedThrow: android.os.HwBinder#getService(String, String):
+    
+BannedThrow: android.os.HwBinder#getService(String, String, boolean):
+    
+BannedThrow: android.os.Process#getThreadScheduler(int):
+    
+
+
+CallbackInterface: android.app.prediction.AppPredictor.Callback:
+    
+CallbackInterface: android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback:
+    
+CallbackInterface: android.widget.Magnifier.Callback:
+    
+
+
+CallbackMethodName: android.os.RemoteCallback:
+    
+
+
+CompileTimeConstant: android.view.inputmethod.InputMethodSystemProperty#MULTI_CLIENT_IME_ENABLED:
+    
+
+
+ConcreteCollection: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
+    
+ConcreteCollection: android.content.ContentCaptureOptions#ContentCaptureOptions(int, int, int, int, int, android.util.ArraySet<android.content.ComponentName>) parameter #5:
+    
+ConcreteCollection: android.content.ContentCaptureOptions#whitelistedComponents:
+    
+ConcreteCollection: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+ConcreteCollection: android.os.HwParcel#readBoolVector():
+    
+ConcreteCollection: android.os.HwParcel#readDoubleVector():
+    
+ConcreteCollection: android.os.HwParcel#readFloatVector():
+    
+ConcreteCollection: android.os.HwParcel#readInt16Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt32Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt64Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt8Vector():
+    
+ConcreteCollection: android.os.HwParcel#readNativeHandleVector():
+    
+ConcreteCollection: android.os.HwParcel#readStringVector():
+    
+ConcreteCollection: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
+    
+ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
+    
+ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
+    
+ConcreteCollection: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>) parameter #2:
+    
+ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms():
+    
+
+
+ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
+    
+
+
+ContextNameSuffix: android.telephony.mbms.vendor.MbmsGroupCallServiceBase:
+    
+
+
+EndsWithImpl: android.view.contentcapture.ViewNode.ViewStructureImpl:
+    
+
+
+Enum: android.view.inspector.InspectableProperty.ValueType:
+    
+
+
+EqualsAndHashCode: android.app.prediction.AppPredictionContext#equals(Object):
+    
+EqualsAndHashCode: android.app.prediction.AppTarget#equals(Object):
+    
+EqualsAndHashCode: android.app.prediction.AppTargetEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.apf.ApfCapabilities#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ApfProgramEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ApfStats#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.DhcpClientEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.IpManagerEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.IpReachabilityEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.NetworkEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.RaEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ValidationProbeEvent#equals(Object):
+    
+EqualsAndHashCode: android.os.IncidentManager.PendingReport#equals(Object):
+    
+EqualsAndHashCode: android.os.StrictMode.ViolationInfo#hashCode():
+    
+
+
+ExecutorRegistration: android.app.AppOpsManager#startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener):
+    
+ExecutorRegistration: android.app.AppOpsManager#stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener):
+    
+ExecutorRegistration: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler):
+    
+ExecutorRegistration: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
+    
+ExecutorRegistration: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyVolumeCallback(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback):
+    
+ExecutorRegistration: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener):
+    
+ExecutorRegistration: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener):
+    
+ExecutorRegistration: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler):
+    
+ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
+    
+
+
+ForbiddenSuperClass: android.app.AppDetailsActivity:
+    
+
+
+GenericException: android.app.ActivityView#finalize():
+    
+GenericException: android.app.prediction.AppPredictor#finalize():
+    
+GenericException: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.augmented.FillWindow#finalize():
+    
+
+
+GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByCriticalDeviceFunction():
+    
+GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByOEM():
+    
+GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
+    
+GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
+    
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
+    
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
+    
+GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
+    
+GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
+    
+GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
+    
+GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
+    
+GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
+    
+GetterSetterNames: android.os.IncidentReportArgs#isAll():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setDirectReplied():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setExpanded():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setSeen():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setSnoozed():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setViewedSettings():
+    
+GetterSetterNames: android.view.View#isAutofilled():
+    
+GetterSetterNames: android.view.View#isDefaultFocusHighlightEnabled():
+    
+
+
+IllegalStateException: android.media.audiopolicy.AudioMix.Builder#build():
+    
+
+
+IntentBuilderName: android.app.backup.BackupManager#getConfigurationIntent(String):
+    
+IntentBuilderName: android.app.backup.BackupManager#getDataManagementIntent(String):
+    
+
+
+IntentName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
+    
+IntentName: android.provider.Telephony.Sms.Intents#SMS_CARRIER_PROVISION_ACTION:
+    
+IntentName: android.service.notification.Adjustment#KEY_CONTEXTUAL_ACTIONS:
+    
+
+
+InterfaceConstant: android.service.autofill.AutofillFieldClassificationService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.autofill.augmented.AugmentedAutofillService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.contentcapture.ContentCaptureService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.notification.NotificationAssistantService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.telecom.PhoneAccountSuggestionService#SERVICE_INTERFACE:
+    
+
+
+KotlinOperator: android.os.WorkSource#get(int):
+    
+
+
+ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
+    
+ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener:
+    
+ListenerInterface: android.os.IncidentManager.AuthListener:
+    
+
+
+ListenerLast: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #4:
+    
+ListenerLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper) parameter #2:
+    
+ListenerLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler) parameter #2:
+    
+ListenerLast: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) parameter #1:
+    
+ListenerLast: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #1:
+    
+
+
+ManagerConstructor: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context):
+    
+
+
+MinMaxConstant: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS:
+    
+
+
+MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1:
+    
+MissingNullability: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#forceStopPackage(String) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#getPackageImportance(String) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int) parameter #0:
+    
+MissingNullability: android.app.ActivityManager.TaskDescription#getIconFilename():
+    
+MissingNullability: android.app.ActivityTaskManager#clearLaunchParamsForPackages(java.util.List<java.lang.String>) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#listAllStacks():
+    
+MissingNullability: android.app.ActivityTaskManager#moveTopActivityToPinnedStack(int, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeStack(int, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeStack(int, android.graphics.Rect, boolean) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeTask(int, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) parameter #4:
+    
+MissingNullability: android.app.ActivityTaskManager#supportsMultiWindow(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#supportsSplitScreenMultiWindow(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet) parameter #1:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int) parameter #1:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int, boolean) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int, boolean) parameter #1:
+    
+MissingNullability: android.app.ActivityView#gatherTransparentRegion(android.graphics.Region) parameter #0:
+    
+MissingNullability: android.app.ActivityView#onVisibilityChanged(android.view.View, int) parameter #0:
+    
+MissingNullability: android.app.ActivityView#setCallback(android.app.ActivityView.StateCallback) parameter #0:
+    
+MissingNullability: android.app.ActivityView#setForwardedInsets(android.graphics.Insets) parameter #0:
+    
+MissingNullability: android.app.ActivityView#startActivity(android.content.Intent, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onActivityViewDestroyed(android.app.ActivityView) parameter #0:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onActivityViewReady(android.app.ActivityView) parameter #0:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onTaskCreated(int, android.content.ComponentName) parameter #1:
+    
+MissingNullability: android.app.AppDetailsActivity#onCreate(android.os.Bundle) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#getOpStrs():
+    
+MissingNullability: android.app.AppOpsManager#isOperationActive(int, int, String) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#opToPermission(int):
+    
+MissingNullability: android.app.AppOpsManager#permissionToOpCode(String) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#setMode(int, int, String, int) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#setUidMode(String, int, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalOp#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalOps#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalUidOps#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.OnOpActiveChangedListener#onOpActiveChanged(int, int, String, boolean) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager.OpEntry#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#allowAssistantAdjustment(String) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#disallowAssistantAdjustment(String) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#getEffectsSuppressor():
+    
+MissingNullability: android.app.NotificationManager#matchesCallFilter(android.os.Bundle) parameter #0:
+    
+MissingNullability: android.app.PictureInPictureParams#getActions():
+    
+MissingNullability: android.app.PictureInPictureParams#getSourceRectHint():
+    
+MissingNullability: android.app.TimePickerDialog#getTimePicker():
+    
+MissingNullability: android.app.UiAutomation#executeShellCommandRw(String):
+    
+MissingNullability: android.app.UiAutomation#executeShellCommandRw(String) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.app.WallpaperManager#setWallpaperComponent(android.content.ComponentName) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#compareTo(android.app.WindowConfiguration) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#getAppBounds():
+    
+MissingNullability: android.app.WindowConfiguration#getBounds():
+    
+MissingNullability: android.app.WindowConfiguration#setAppBounds(android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#setBounds(android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#setTo(android.app.WindowConfiguration) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
+    
+MissingNullability: android.app.admin.SecurityLog.SecurityEvent#SecurityEvent(long, byte[]) parameter #1:
+    
+MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String):
+    
+MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String) parameter #0:
+    
+MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String):
+    
+MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String) parameter #0:
+    
+MissingNullability: android.app.backup.BackupManager#getDestinationString(String):
+    
+MissingNullability: android.app.backup.BackupManager#getDestinationString(String) parameter #0:
+    
+MissingNullability: android.app.prediction.AppPredictionSessionId#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppPredictor#getSessionId():
+    
+MissingNullability: android.app.prediction.AppTarget#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppTargetEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppTargetId#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.AutofillOptions#forWhitelistingItself():
+    
+MissingNullability: android.content.AutofillOptions#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.ContentCaptureOptions#forWhitelistingItself():
+    
+MissingNullability: android.content.ContentCaptureOptions#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int):
+    
+MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int) parameter #0:
+    
+MissingNullability: android.content.Context#createPackageContextAsUser(String, int, android.os.UserHandle):
+    
+MissingNullability: android.content.Context#createPackageContextAsUser(String, int, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.content.Context#createPackageContextAsUser(String, int, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.content.Context#getDisplay():
+    
+MissingNullability: android.content.Context#getUser():
+    
+MissingNullability: android.content.ContextWrapper#getDisplay():
+    
+MissingNullability: android.content.ContextWrapper#setContentCaptureOptions(android.content.ContentCaptureOptions) parameter #0:
+    
+MissingNullability: android.content.pm.ActivityInfo#isTranslucentOrFloating(android.content.res.TypedArray) parameter #0:
+    
+MissingNullability: android.content.pm.LauncherApps#LauncherApps(android.content.Context) parameter #0:
+    
+MissingNullability: android.content.pm.PackageInstaller.SessionParams#setGrantedRuntimePermissions(String[]) parameter #0:
+    
+MissingNullability: android.content.pm.PackageManager#getNamesForUids(int[]) parameter #0:
+    
+MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0:
+    
+MissingNullability: android.content.res.AssetManager#getOverlayableMap(String) parameter #0:
+    
+MissingNullability: android.content.res.Configuration#windowConfiguration:
+    
+MissingNullability: android.content.rollback.PackageRollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.rollback.RollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#getDatabaseInfo():
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#DbStats(String, long, long, int, int, int, int) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#cache:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#dbName:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #2:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #3:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#cursorRequeried(android.database.Cursor) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#setBindArguments(String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultJournalMode():
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultSyncMode():
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getWALSyncMode():
+    
+MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #0:
+    
+MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #1:
+    
+MissingNullability: android.graphics.drawable.AdaptiveIconDrawable#getSafeZone():
+    
+MissingNullability: android.graphics.drawable.ColorDrawable#getXfermode():
+    
+MissingNullability: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #0:
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getBucketBoundaries():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getLocalDate():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getStats():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#luxTimestamps:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#luxValues:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#packageName:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration#getCurve():
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #1:
+    
+MissingNullability: android.hardware.display.BrightnessCorrection#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.DisplayManager#getAmbientBrightnessStats():
+    
+MissingNullability: android.hardware.display.DisplayManager#getBrightnessConfiguration():
+    
+MissingNullability: android.hardware.display.DisplayManager#getBrightnessEvents():
+    
+MissingNullability: android.hardware.display.DisplayManager#getStableDisplaySize():
+    
+MissingNullability: android.hardware.display.DisplayManager#setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration) parameter #0:
+    
+MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
+    
+MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
+    
+MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
+    
+MissingNullability: android.location.LocationManager#getTestProviderCurrentRequests(String) parameter #0:
+    
+MissingNullability: android.location.LocationRequest#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.media.AudioFocusInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #3:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #4:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #6:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #3:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #4:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #6:
+    
+MissingNullability: android.media.PlaybackParams#setAudioStretchMode(int):
+    
+MissingNullability: android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL:
+    
+MissingNullability: android.media.audiofx.AudioEffect#byteArrayToInt(byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, int[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, short[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#intToByteArray(int):
+    
+MissingNullability: android.media.audiofx.AudioEffect#isEffectTypeAvailable(java.util.UUID) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int, byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#shortToByteArray(short):
+    
+MissingNullability: android.media.audiofx.AudioEffect.Descriptor#Descriptor(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.Descriptor#writeToParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #2:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #3:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#build():
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object) parameter #1:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#build():
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object) parameter #1:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#setRegistration(String) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#toLogFriendlyString():
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusAbandon(android.media.AudioFocusInfo) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusGrant(android.media.AudioFocusInfo, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusLoss(android.media.AudioFocusInfo, boolean) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(android.media.AudioFocusInfo, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener#onMixStateUpdate(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#Builder(android.content.Context) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object):
+    
+MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object) parameter #1:
+    
+MissingNullability: android.metrics.LogMaker#clearCategory():
+    
+MissingNullability: android.metrics.LogMaker#clearPackageName():
+    
+MissingNullability: android.metrics.LogMaker#clearSubtype():
+    
+MissingNullability: android.metrics.LogMaker#clearTaggedData(int):
+    
+MissingNullability: android.metrics.LogMaker#clearType():
+    
+MissingNullability: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#getCounterName():
+    
+MissingNullability: android.metrics.LogMaker#getPackageName():
+    
+MissingNullability: android.metrics.LogMaker#getTaggedData(int):
+    
+MissingNullability: android.metrics.LogMaker#isSubsetOf(android.metrics.LogMaker) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#isValidValue(Object) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#serialize():
+    
+MissingNullability: android.metrics.LogMaker#setCategory(int):
+    
+MissingNullability: android.metrics.LogMaker#setPackageName(String):
+    
+MissingNullability: android.metrics.LogMaker#setPackageName(String) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#setSubtype(int):
+    
+MissingNullability: android.metrics.LogMaker#setType(int):
+    
+MissingNullability: android.metrics.MetricsReader#next():
+    
+MissingNullability: android.net.NetworkCapabilities#getCapabilities():
+    
+MissingNullability: android.net.StaticIpConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.TestNetworkInterface#CREATOR:
+    
+MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #0:
+    
+MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #1:
+    
+MissingNullability: android.net.TestNetworkInterface#getFileDescriptor():
+    
+MissingNullability: android.net.TestNetworkInterface#getInterfaceName():
+    
+MissingNullability: android.net.TestNetworkInterface#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.TestNetworkManager#createTapInterface():
+    
+MissingNullability: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]):
+    
+MissingNullability: android.net.apf.ApfCapabilities#CREATOR:
+    
+MissingNullability: android.net.apf.ApfCapabilities#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.metrics.DhcpClientEvent.Builder#setMsg(String) parameter #0:
+    
+MissingNullability: android.os.Build#is64BitAbi(String) parameter #0:
+    
+MissingNullability: android.os.Build.VERSION#ACTIVE_CODENAMES:
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...):
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #0:
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #1:
+    
+MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #0:
+    
+MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #1:
+    
+MissingNullability: android.os.HwBinder#getService(String, String):
+    
+MissingNullability: android.os.HwBinder#getService(String, String) parameter #0:
+    
+MissingNullability: android.os.HwBinder#getService(String, String) parameter #1:
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean):
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #0:
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #1:
+    
+MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.HwBinder#registerService(String) parameter #0:
+    
+MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.HwBlob#copyToBoolArray(long, boolean[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToDoubleArray(long, double[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToFloatArray(long, float[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt16Array(long, short[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt32Array(long, int[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt64Array(long, long[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt8Array(long, byte[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#getString(long):
+    
+MissingNullability: android.os.HwBlob#putBlob(long, android.os.HwBlob) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putBoolArray(long, boolean[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putDoubleArray(long, double[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putFloatArray(long, float[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt16Array(long, short[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt32Array(long, int[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt64Array(long, long[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt8Array(long, byte[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putString(long, String) parameter #1:
+    
+MissingNullability: android.os.HwBlob#wrapArray(boolean[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(byte[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(double[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(float[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(int[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(long[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(short[]):
+    
+MissingNullability: android.os.HwParcel#enforceInterface(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#readBoolVector():
+    
+MissingNullability: android.os.HwParcel#readBuffer(long):
+    
+MissingNullability: android.os.HwParcel#readDoubleVector():
+    
+MissingNullability: android.os.HwParcel#readEmbeddedBuffer(long, long, long, boolean):
+    
+MissingNullability: android.os.HwParcel#readFloatVector():
+    
+MissingNullability: android.os.HwParcel#readInt16Vector():
+    
+MissingNullability: android.os.HwParcel#readInt32Vector():
+    
+MissingNullability: android.os.HwParcel#readInt64Vector():
+    
+MissingNullability: android.os.HwParcel#readInt8Vector():
+    
+MissingNullability: android.os.HwParcel#readString():
+    
+MissingNullability: android.os.HwParcel#readStringVector():
+    
+MissingNullability: android.os.HwParcel#readStrongBinder():
+    
+MissingNullability: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeBuffer(android.os.HwBlob) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInterfaceToken(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeString(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeStrongBinder(android.os.IHwBinder) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#queryLocalInterface(String):
+    
+MissingNullability: android.os.IHwBinder#queryLocalInterface(String) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.IHwBinder#unlinkToDeath(android.os.IHwBinder.DeathRecipient) parameter #0:
+    
+MissingNullability: android.os.IHwInterface#asBinder():
+    
+MissingNullability: android.os.IncidentManager#approveReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#deleteIncidentReports(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#denyReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getIncidentReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getIncidentReportList(String) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getPendingReports():
+    
+MissingNullability: android.os.IncidentManager#reportIncident(android.os.IncidentReportArgs) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #1:
+    
+MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #3:
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#getInputStream():
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#addHeader(byte[]) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#readFromParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor):
+    
+MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
+    
+MissingNullability: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener) parameter #0:
+    
+MissingNullability: android.os.RemoteCallback#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.StrictMode#setViolationLogger(android.os.StrictMode.ViolationLogger) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel, boolean) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #1:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getStackTrace():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getViolationClass():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getViolationDetails():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#tags:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationLogger#log(android.os.StrictMode.ViolationInfo) parameter #0:
+    
+MissingNullability: android.os.UserHandle#of(int):
+    
+MissingNullability: android.os.VibrationEffect#RINGTONES:
+    
+MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
+    
+MissingNullability: android.os.VibrationEffect#get(int):
+    
+MissingNullability: android.os.VibrationEffect#get(int, boolean):
+    
+MissingNullability: android.os.VibrationEffect.OneShot#OneShot(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.OneShot#scale(float, int):
+    
+MissingNullability: android.os.VibrationEffect.OneShot#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Prebaked#Prebaked(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Prebaked#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(long[], int[], int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(long[], int[], int) parameter #1:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#getAmplitudes():
+    
+MissingNullability: android.os.VibrationEffect.Waveform#getTimings():
+    
+MissingNullability: android.os.VibrationEffect.Waveform#scale(float, int):
+    
+MissingNullability: android.os.VibrationEffect.Waveform#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VintfObject#getHalNamesAndVersions():
+    
+MissingNullability: android.os.VintfObject#getSepolicyVersion():
+    
+MissingNullability: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
+    
+MissingNullability: android.os.VintfObject#getVndkSnapshots():
+    
+MissingNullability: android.os.VintfObject#report():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getCpuInfo():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getHardwareId():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getKernelVersion():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getNodeName():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsName():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsRelease():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsVersion():
+    
+MissingNullability: android.os.WorkSource#add(int, String) parameter #1:
+    
+MissingNullability: android.os.WorkSource#addReturningNewbs(android.os.WorkSource) parameter #0:
+    
+MissingNullability: android.os.WorkSource#getName(int):
+    
+MissingNullability: android.os.WorkSource#setReturningDiffs(android.os.WorkSource) parameter #0:
+    
+MissingNullability: android.os.health.HealthKeys.Constants#Constants(Class) parameter #0:
+    
+MissingNullability: android.os.health.HealthKeys.Constants#getDataType():
+    
+MissingNullability: android.os.health.HealthKeys.Constants#getKeys(int):
+    
+MissingNullability: android.os.health.HealthStats#HealthStats(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.health.HealthStatsWriter) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#getHealthStats():
+    
+MissingNullability: android.os.health.HealthStatsParceler#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsWriter#HealthStatsWriter(android.os.health.HealthKeys.Constants) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addMeasurements(int, String, long) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #2:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #2:
+    
+MissingNullability: android.os.health.HealthStatsWriter#flattenToParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.storage.StorageVolume#getPath():
+    
+MissingNullability: android.permission.RuntimePermissionPresentationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.provider.CalendarContract.Calendars#SYNC_WRITABLE_COLUMNS:
+    
+MissingNullability: android.provider.CalendarContract.Events#SYNC_WRITABLE_COLUMNS:
+    
+MissingNullability: android.provider.ContactsContract.CommonDataKinds.Phone#ENTERPRISE_CONTENT_URI:
+    
+MissingNullability: android.provider.ContactsContract.RawContactsEntity#CORP_CONTENT_URI:
+    
+MissingNullability: android.provider.DeviceConfig#getProperty(String, String):
+    
+MissingNullability: android.provider.DeviceConfig#getString(String, String, String):
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#waitForIdle(android.content.Context) parameter #0:
+    
+MissingNullability: android.security.KeyStoreException#KeyStoreException(int, String) parameter #1:
+    
+MissingNullability: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]) parameter #0:
+    
+MissingNullability: android.security.keystore.KeyProtection.Builder#setBoundToSpecificSecureUserId(long):
+    
+MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent):
+    
+MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.service.autofill.CompositeUserData#getCategoryIds():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getDefaultFieldClassificationArgs():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getValues():
+    
+MissingNullability: android.service.autofill.CompositeUserData#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.autofill.UserData#getFieldClassificationAlgorithms():
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #0:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #1:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #2:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #3:
+    
+MissingNullability: android.service.notification.Adjustment#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
+    
+MissingNullability: android.service.notification.NotificationStats#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #1:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #2:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getConfirmation():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getExplanation():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getId():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telecom.Call.Details#getTelecomCallId():
+    
+MissingNullability: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallFurther(boolean):
+    
+MissingNullability: android.telecom.Conference#getPrimaryConnection():
+    
+MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent):
+    
+MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.telephony.DataSpecificRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.LteVopsSupportInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.NetworkRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.ServiceState#addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo) parameter #0:
+    
+MissingNullability: android.telephony.ServiceState#setCellBandwidths(int[]) parameter #0:
+    
+MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #0:
+    
+MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#checkCarrierPrivilegesForPackage(String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag():
+    
+MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion():
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #2:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #3:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #4:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #5:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #6:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #2:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #3:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #4:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #5:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #6:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #7:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8:
+    
+MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
+    
+MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #2:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #3:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #4:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #5:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #6:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #0:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #1:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #2:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #3:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #4:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #5:
+    
+MissingNullability: android.telephony.mbms.UriPathPair#getContentUri():
+    
+MissingNullability: android.telephony.mbms.UriPathPair#getFilePathUri():
+    
+MissingNullability: android.telephony.mbms.UriPathPair#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#asBinder():
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent):
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#asBinder():
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String):
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #1:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#afterTextChanged(android.text.Editable) parameter #0:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#beforeTextChanged(CharSequence, int, int, int) parameter #0:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#onTextChanged(CharSequence, int, int, int) parameter #0:
+    
+MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene):
+    
+MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#getAllFeatureFlags():
+    
+MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #1:
+    
+MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #1:
+    
+MissingNullability: android.util.TimeUtils#formatDuration(long):
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpBuffers(String) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #2:
+    
+MissingNullability: android.util.proto.EncodedBuffer#getBytes(int):
+    
+MissingNullability: android.util.proto.EncodedBuffer#getDebugString():
+    
+MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[]) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[], int, int) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.OutputStream) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#dump(String) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#getBytes():
+    
+MissingNullability: android.util.proto.ProtoOutputStream#write(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#write(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeBytes(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeObject(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedBool(long, boolean[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedDouble(long, double[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedEnum(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFloat(long, float[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedBytes(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedObject(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedString(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeString(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoParseException#ProtoParseException(String) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldCountString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldIdString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldTypeString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getWireTypeString(int):
+    
+MissingNullability: android.util.proto.ProtoStream#token2String(long):
+    
+MissingNullability: android.util.proto.WireTypeMismatchException#WireTypeMismatchException(String) parameter #0:
+    
+MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #1:
+    
+MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #2:
+    
+MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #1:
+    
+MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #2:
+    
+MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #1:
+    
+MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #2:
+    
+MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
+    
+MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #3:
+    
+MissingNullability: android.view.KeyEvent#actionToString(int):
+    
+MissingNullability: android.view.View#getTooltipView():
+    
+MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
+    
+MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #0:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #2:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #0:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #2:
+    
+MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle:
+    
+MissingNullability: android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener#onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityNodeInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityNodeInfo#writeToParcelNoRecycle(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityWindowInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ContentCaptureEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode#getAutofillId():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getClassName():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getContentDescription():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getExtras():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getHint():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getIdEntry():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getIdPackage():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getIdType():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getLocaleList():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getText():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getTextIdEntry():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getTextLineBaselines():
+    
+MissingNullability: android.view.contentcapture.ViewNode#getTextLineCharOffsets():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#asyncNewChild(int):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getAutofillId():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getExtras():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getHint():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getNode():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getTempRect():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getText():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newChild(int):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillHints(String[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillValue(android.view.autofill.AutofillValue) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setClassName(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setContentDescription(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHint(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHtmlInfo(android.view.ViewStructure.HtmlInfo) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #1:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #2:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #3:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setLocaleList(android.os.LocaleList) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence, int, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextIdEntry(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #1:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTransformation(android.graphics.Matrix) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setWebDomain(String) parameter #0:
+    
+MissingNullability: android.widget.CalendarView#getBoundsForDate(long, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
+    
+MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
+    
+MissingNullability: android.widget.Magnifier#getMagnifierDefaultSize():
+    
+MissingNullability: android.widget.Magnifier#setOnOperationCompleteCallback(android.widget.Magnifier.Callback) parameter #0:
+    
+MissingNullability: android.widget.NumberPicker#getDisplayedValueForCurrentSelection():
+    
+MissingNullability: android.widget.PopupMenu#getMenuListView():
+    
+MissingNullability: android.widget.TimePicker#getAmView():
+    
+MissingNullability: android.widget.TimePicker#getHourView():
+    
+MissingNullability: android.widget.TimePicker#getMinuteView():
+    
+MissingNullability: android.widget.TimePicker#getPmView():
+    
+
+
+MutableBareField: android.content.AutofillOptions#appDisabledExpiration:
+    
+MutableBareField: android.content.AutofillOptions#augmentedAutofillEnabled:
+    
+MutableBareField: android.content.AutofillOptions#disabledActivities:
+    
+MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbSize:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#lookaside:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#pageSize:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#largestMemAlloc:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#memoryUsed:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#pageCacheOverflow:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#durationMillis:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#numAnimationsRunning:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#numInstances:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#tags:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#violationNumThisLoop:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#violationUptimeMillis:
+    
+
+
+NoByteOrShort: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]):
+    
+NoByteOrShort: android.media.audiofx.AudioEffect#setParameter(int, short) parameter #1:
+    
+NoByteOrShort: android.media.audiofx.AudioEffect#shortToByteArray(short) parameter #0:
+    
+NoByteOrShort: android.os.HwBlob#getInt16(long):
+    
+NoByteOrShort: android.os.HwBlob#getInt8(long):
+    
+NoByteOrShort: android.os.HwBlob#putInt16(long, short) parameter #1:
+    
+NoByteOrShort: android.os.HwBlob#putInt8(long, byte) parameter #1:
+    
+NoByteOrShort: android.os.HwParcel#readInt16():
+    
+NoByteOrShort: android.os.HwParcel#readInt8():
+    
+NoByteOrShort: android.os.HwParcel#writeInt16(short) parameter #0:
+    
+NoByteOrShort: android.os.HwParcel#writeInt8(byte) parameter #0:
+    
+NoByteOrShort: android.util.proto.EncodedBuffer#readRawByte():
+    
+NoByteOrShort: android.util.proto.EncodedBuffer#writeRawByte(byte) parameter #0:
+    
+
+
+NoClone: android.net.util.SocketUtils#bindSocketToInterface(java.io.FileDescriptor, String) parameter #0:
+    
+NoClone: android.net.util.SocketUtils#closeSocket(java.io.FileDescriptor) parameter #0:
+    
+NoClone: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor, boolean) parameter #0:
+    
+NoClone: android.os.NativeHandle#getFileDescriptor():
+    
+NoClone: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
+    
+NoClone: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+NoClone: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+
+
+NotCloseable: android.app.ActivityView:
+    
+NotCloseable: android.app.prediction.AppPredictor:
+    
+NotCloseable: android.os.HwParcel:
+    
+
+
+OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
+    
+OnNameExpected: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+OnNameExpected: android.service.notification.ConditionProviderService#isBound():
+    
+OnNameExpected: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+    
+OnNameExpected: android.service.quicksettings.TileService#isQuickSettingsSupported():
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#stopGroupCall(int, long):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>):
+    
+
+
+PackageLayering: android.util.FeatureFlagUtils:
+    
+
+
+ParcelConstructor: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel):
+    
+ParcelConstructor: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel):
+    
+ParcelConstructor: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.OneShot#OneShot(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.Prebaked#Prebaked(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.Waveform#Waveform(android.os.Parcel):
+    
+ParcelConstructor: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel):
+    
+ParcelConstructor: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel):
+    
+
+
+ParcelCreator: android.app.WindowConfiguration:
+    
+ParcelCreator: android.net.metrics.ApfProgramEvent:
+    
+ParcelCreator: android.net.metrics.ApfStats:
+    
+ParcelCreator: android.net.metrics.DhcpClientEvent:
+    
+ParcelCreator: android.net.metrics.DhcpErrorEvent:
+    
+ParcelCreator: android.net.metrics.IpConnectivityLog.Event:
+    
+ParcelCreator: android.net.metrics.IpManagerEvent:
+    
+ParcelCreator: android.net.metrics.IpReachabilityEvent:
+    
+ParcelCreator: android.net.metrics.NetworkEvent:
+    
+ParcelCreator: android.net.metrics.RaEvent:
+    
+ParcelCreator: android.net.metrics.ValidationProbeEvent:
+    
+ParcelCreator: android.os.VibrationEffect.OneShot:
+    
+ParcelCreator: android.os.VibrationEffect.Prebaked:
+    
+ParcelCreator: android.os.VibrationEffect.Waveform:
+    
+ParcelCreator: android.service.autofill.InternalOnClickAction:
+    
+ParcelCreator: android.service.autofill.InternalSanitizer:
+    
+ParcelCreator: android.service.autofill.InternalTransformation:
+    
+ParcelCreator: android.service.autofill.InternalValidator:
+    
+
+
+ParcelNotFinal: android.app.WindowConfiguration:
+    
+ParcelNotFinal: android.net.metrics.IpConnectivityLog.Event:
+    
+ParcelNotFinal: android.os.IncidentManager.IncidentReport:
+    
+ParcelNotFinal: android.os.VibrationEffect.OneShot:
+    
+ParcelNotFinal: android.os.VibrationEffect.Prebaked:
+    
+ParcelNotFinal: android.os.VibrationEffect.Waveform:
+    
+ParcelNotFinal: android.os.health.HealthStatsParceler:
+    
+ParcelNotFinal: android.service.autofill.InternalOnClickAction:
+    
+ParcelNotFinal: android.service.autofill.InternalSanitizer:
+    
+ParcelNotFinal: android.service.autofill.InternalTransformation:
+    
+ParcelNotFinal: android.service.autofill.InternalValidator:
+    
+
+
+ProtectedMember: android.app.ActivityView#onVisibilityChanged(android.view.View, int):
+    
+ProtectedMember: android.app.AppDetailsActivity#onCreate(android.os.Bundle):
+    
+ProtectedMember: android.os.VibrationEffect#scale(int, float, int):
+    
+ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+    
+ProtectedMember: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
+    
+ProtectedMember: android.view.View#resetResolvedDrawables():
+    
+ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
+    
+
+
+RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
+    
+RawAidl: android.telephony.mbms.vendor.MbmsStreamingServiceBase:
+    
+
+
+RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches():
+    
+RethrowRemoteException: android.os.HwBinder#getService(String, String):
+    
+RethrowRemoteException: android.os.HwBinder#getService(String, String, boolean):
+    
+RethrowRemoteException: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.os.HwBinder#registerService(String):
+    
+RethrowRemoteException: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#listPendingDownloads(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String):
+    
+
+
+SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
+    
+SamShouldBeLast: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+SamShouldBeLast: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+SamShouldBeLast: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]):
+    
+SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
+    
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
+    
+SamShouldBeLast: android.os.BugreportManager#startBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.os.BugreportParams, java.util.concurrent.Executor, android.os.BugreportManager.BugreportCallback):
+    
+SamShouldBeLast: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long):
+    
+SamShouldBeLast: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String):
+    
+SamShouldBeLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
+    
+SamShouldBeLast: android.permission.PermissionControllerManager#revokeRuntimePermissions(java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback):
+    
+SamShouldBeLast: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>):
+    
+SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object):
+    
+SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long):
+    
+SamShouldBeLast: android.view.Choreographer#removeCallbacks(int, Runnable, Object):
+    
+SamShouldBeLast: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>):
+    
+SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, android.os.Handler):
+    
+
+
+ServiceName: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
+    
+ServiceName: android.app.AppOpsManager#OPSTR_BIND_ACCESSIBILITY_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#AUTOFILL_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
+    
+
+
+SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
+    
+SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
+    
+
+
+StaticUtils: android.os.health.HealthKeys:
+    
+StaticUtils: android.service.autofill.InternalTransformation:
+    
+StaticUtils: android.telephony.mbms.vendor.VendorUtils:
+    
+StaticUtils: android.util.FeatureFlagUtils:
+    
+StaticUtils: android.util.proto.ProtoStream:
+    
+StaticUtils: android.view.inputmethod.InputMethodSystemProperty:
+    
+
+
+StreamFiles: android.os.Environment#buildPath(java.io.File, java.lang.String...):
+    
+StreamFiles: android.os.FileUtils#contains(java.io.File, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File):
+    
+
+
+UseParcelFileDescriptor: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+
+
+UserHandle: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.app.role.RoleManager#clearRoleHoldersAsUser(String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.app.role.RoleManager#getRoleHoldersAsUser(String, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#updatePermissionFlags(String, String, int, int, android.os.UserHandle):
+    
+UserHandle: android.location.LocationManager#setLocationEnabledForUser(boolean, android.os.UserHandle):
+    
+
+
+UserHandleName: android.app.ActivityView#startActivity(android.content.Intent, android.os.UserHandle):
+    
+UserHandleName: android.content.AutofillOptions:
+    
+UserHandleName: android.content.ContentCaptureOptions:
+    
+UserHandleName: android.os.IncidentReportArgs:
+    
+UserHandleName: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle):
+    
+UserHandleName: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle):
+    
+
+
+VisiblySynchronized: PsiClassObjectAccessExpression:
+    
+VisiblySynchronized: PsiThisExpression:
+    
+VisiblySynchronized: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
+    
+VisiblySynchronized: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener):
+    
+VisiblySynchronized: android.content.ContentProviderClient#setDetectNotResponding(long):
+    
+VisiblySynchronized: android.content.res.AssetManager#getApkPaths():
+    
+VisiblySynchronized: android.content.res.AssetManager#getOverlayableMap(String):
+    
+VisiblySynchronized: android.os.MessageQueue#removeSyncBarrier(int):
+    
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f0db1b0..313e16d 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -128,13 +128,13 @@
 
     std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
 
-    std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+    std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes;
 
     // Last time we sent a broadcast to this uid that the active configs had changed.
-    std::unordered_map<int, long> mLastActivationBroadcastTimes;
+    std::unordered_map<int, int64_t> mLastActivationBroadcastTimes;
 
     // Tracks when we last checked the bytes consumed for each config key.
-    std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
+    std::unordered_map<ConfigKey, int64_t> mLastByteSizeTimes;
 
     // Tracks which config keys has metric reports on disk
     std::set<ConfigKey> mOnDiskDataConfigs;
@@ -205,7 +205,7 @@
 
     int64_t mLastTimestampSeen = 0;
 
-    long mLastPullerCacheClearTimeSec = 0;
+    int64_t mLastPullerCacheClearTimeSec = 0;
 
     // Last time we wrote data to disk.
     int64_t mLastWriteTimeNs = 0;
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt
index 25d45b0..34339d7 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-greylist-max-p.txt
@@ -47,7 +47,6 @@
 Landroid/os/WorkSource;->updateLocked(Landroid/os/WorkSource;ZZ)Z
 Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
 Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
-Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
 Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats;
 Landroid/view/IWindowManager;->setInTouchMode(Z)V
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 3e00bfe..2611e96 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1468,283 +1468,4 @@
 Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V
 Lcom/google/android/gles_jni/EGLImpl;-><init>()V
 Lcom/google/android/gles_jni/GLImpl;-><init>()V
-Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>()V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B
-Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I
-Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
-Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J
-Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I
-Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I
-Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B
-Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V
-Lcom/google/android/mms/pdu/GenericPdu;-><init>()V
-Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
-Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>()V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I
-Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
-Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
-Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
-Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/PduBody;-><init>()V
-Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
-Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
-Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
-Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V
-Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I
-Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I
-Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V
-Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V
-Lcom/google/android/mms/pdu/PduComposer;->make()[B
-Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream;
-Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/PduComposer;->mPosition:I
-Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack;
-Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduHeaders;-><init>()V
-Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J
-Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I
-Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B
-Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V
-Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V
-Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z
-Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V
-Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B
-Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z
-Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B
-Lcom/google/android/mms/pdu/PduPart;-><init>()V
-Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPart;->getCharset()I
-Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentId()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
-Lcom/google/android/mms/pdu/PduPart;->getData()[B
-Lcom/google/android/mms/pdu/PduPart;->getDataLength()I
-Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
-Lcom/google/android/mms/pdu/PduPart;->getName()[B
-Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
-Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
-Lcom/google/android/mms/pdu/PduPart;->setData([B)V
-Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
-Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V
-Lcom/google/android/mms/pdu/PduPart;->setName([B)V
-Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I
-Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B
-Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
-Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer;
-Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
-Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
-Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V
-Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context;
-Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager;
-Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
-Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B
-Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/SendConf;-><init>()V
-Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
-Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;-><init>()V
-Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getContentType()[B
-Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/SendReq;->getExpiry()J
-Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B
-Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J
-Lcom/google/android/mms/pdu/SendReq;->getReadReport()I
-Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V
-Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V
-Lcom/google/android/mms/util/AbstractCache;-><init>()V
-Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purgeAll()V
-Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String;
-Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I
-Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B
-Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession;
-Lcom/google/android/mms/util/PduCache;-><init>()V
-Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
-Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
-Lcom/google/android/mms/util/PduCache;->purgeAll()V
-Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V
-Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I
-Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J
-Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V
-Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
-Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
-Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
-Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z
-Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
 Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type;
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 5d97c85..eb3879f 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -4835,7 +4835,6 @@
 com.android.internal.telephony.PhoneConstants$DataState
 com.android.internal.telephony.PhoneConstants$State
 com.android.internal.telephony.PhoneFactory
-com.android.internal.telephony.PhoneInternalInterface$DataActivityState
 com.android.internal.telephony.PhoneInternalInterface
 com.android.internal.telephony.PhoneNotifier
 com.android.internal.telephony.PhoneStateIntentReceiver
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b915473..69be171 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -72,6 +72,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStat;
+import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -1330,6 +1331,19 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, @Nullable Bundle initialExtras) {
+        int intAppOp = AppOpsManager.OP_NONE;
+        if (!TextUtils.isEmpty(receiverAppOp)) {
+            intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+        }
+        sendOrderedBroadcastAsUser(intent, getUser(),
+                receiverPermission, intAppOp, resultReceiver, scheduler, initialCode, initialData,
+                initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         warnIfCallingFromSystemProcess();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index cfe2cf0..646f0dc 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -157,6 +157,7 @@
 import android.os.image.DynamicSystemManager;
 import android.os.image.IDynamicSystemService;
 import android.os.storage.StorageManager;
+import android.os.telephony.TelephonyRegistryManager;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
@@ -172,6 +173,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
+import android.telephony.ims.ImsManager;
 import android.telephony.ims.RcsMessageManager;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -607,6 +609,13 @@
                 return new TelephonyManager(ctx.getOuterContext());
             }});
 
+        registerService(Context.TELEPHONY_REGISTRY_SERVICE, TelephonyRegistryManager.class,
+            new CachedServiceFetcher<TelephonyRegistryManager>() {
+                @Override
+                public TelephonyRegistryManager createService(ContextImpl ctx) {
+                    return new TelephonyRegistryManager();
+                }});
+
         registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
                 new CachedServiceFetcher<SubscriptionManager>() {
             @Override
@@ -622,6 +631,14 @@
                     }
                 });
 
+        registerService(Context.TELEPHONY_IMS_SERVICE, ImsManager.class,
+                new CachedServiceFetcher<ImsManager>() {
+                    @Override
+                    public ImsManager createService(ContextImpl ctx) {
+                        return new ImsManager(ctx.getOuterContext());
+                    }
+                });
+
         registerService(Context.CARRIER_CONFIG_SERVICE, CarrierConfigManager.class,
                 new CachedServiceFetcher<CarrierConfigManager>() {
             @Override
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e7ba85a..566b387 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1189,13 +1189,11 @@
     /**
      * Factory reset bluetooth settings.
      *
-     * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
-     * permission
-     *
      * @return true to indicate that the config file was successfully cleared
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
     public boolean factoryReset() {
         try {
             mServiceLock.readLock().lock();
@@ -1214,13 +1212,12 @@
     /**
      * Get the UUIDs supported by the local Bluetooth adapter.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
-     *
      * @return the UUIDs supported by the local Bluetooth Adapter.
      * @hide
      */
     @UnsupportedAppUsage
-    public ParcelUuid[] getUuids() {
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public @NonNull ParcelUuid[] getUuids() {
         if (getState() != STATE_ON) {
             return null;
         }
@@ -1476,7 +1473,6 @@
      * will return false. After turning on Bluetooth,
      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
      * to get the updated value.
-     * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
      * <p>Applications cannot set the scan mode. They should use
      * <code>startActivityForResult(
      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
@@ -1488,8 +1484,8 @@
      * @return true if the scan mode was set, false otherwise
      * @hide
      */
-    @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which "
-            + "shows UI that confirms the user wants to go into discoverable mode.")
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public boolean setScanMode(@ScanMode int mode, int duration) {
         if (getState() != STATE_ON) {
             return false;
@@ -1507,9 +1503,34 @@
         return false;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage
-    public boolean setScanMode(int mode) {
+    /**
+     * Set the Bluetooth scan mode of the local Bluetooth adapter.
+     * <p>The Bluetooth scan mode determines if the local adapter is
+     * connectable and/or discoverable from remote Bluetooth devices.
+     * <p>For privacy reasons, discoverable mode is automatically turned off
+     * after <code>duration</code> seconds. For example, 120 seconds should be
+     * enough for a remote device to initiate and complete its discovery
+     * process.
+     * <p>Valid scan mode values are:
+     * {@link #SCAN_MODE_NONE},
+     * {@link #SCAN_MODE_CONNECTABLE},
+     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
+     * <p>If Bluetooth state is not {@link #STATE_ON}, this API
+     * will return false. After turning on Bluetooth,
+     * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
+     * to get the updated value.
+     * <p>Applications cannot set the scan mode. They should use
+     * <code>startActivityForResult(
+     * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
+     * </code>instead.
+     *
+     * @param mode valid scan mode
+     * @return true if the scan mode was set, false otherwise
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
+    public boolean setScanMode(@ScanMode int mode) {
         if (getState() != STATE_ON) {
             return false;
         }
@@ -1562,6 +1583,8 @@
      * been called recently.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.BLUETOOTH)
     public long getDiscoveryEndMillis() {
         try {
             mServiceLock.readLock().lock();
@@ -2060,7 +2083,7 @@
      * BluetoothProfile}.
      * @hide
      */
-    public List<Integer> getSupportedProfiles() {
+    public @NonNull List<Integer> getSupportedProfiles() {
         final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
 
         try {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 51bb85a..a8c1216 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2393,6 +2393,44 @@
             @Nullable String initialData, @Nullable  Bundle initialExtras);
 
     /**
+     * Version of
+     * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
+     * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
+     * the broadcast will be sent to.
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param receiverPermission String naming a permissions that
+     *               a receiver must hold in order to receive your broadcast.
+     *               If null, no permission is required.
+     * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is
+     *                      required. If both receiverAppOp and receiverPermission are non-null,
+     *                      a receiver must have both of them to
+     *                      receive the broadcast
+     * @param resultReceiver Your own BroadcastReceiver to treat as the final
+     *                       receiver of the broadcast.
+     * @param scheduler A custom Handler with which to schedule the
+     *                  resultReceiver callback; if null it will be
+     *                  scheduled in the Context's main thread.
+     * @param initialCode An initial value for the result code.  Often
+     *                    Activity.RESULT_OK.
+     * @param initialData An initial value for the result data.  Often
+     *                    null.
+     * @param initialExtras An initial value for the result extras.  Often
+     *                      null.
+     *
+     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
@@ -4688,6 +4726,13 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.telephony.ims.ImsManager}.
+     * @hide
+     */
+    public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve an
      * {@link android.telephony.ims.RcsMessageManager}.
      * @hide
      */
@@ -4701,6 +4746,14 @@
     public static final String DYNAMIC_SYSTEM_SERVICE = "dynamic_system";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.os.telephony.TelephonyRegistryManager}.
+     * @hide
+     */
+    @SystemApi
+    public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 0859f97..6c33f6d 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,6 +16,9 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -61,12 +64,12 @@
     public ContextWrapper(Context base) {
         mBase = base;
     }
-    
+
     /**
      * Set the base context for this ContextWrapper.  All calls will then be
      * delegated to the base context.  Throws
      * IllegalStateException if a base context has already been set.
-     * 
+     *
      * @param base The new base context for this wrapper.
      */
     protected void attachBaseContext(Context base) {
@@ -117,7 +120,7 @@
     public Context getApplicationContext() {
         return mBase.getApplicationContext();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         mBase.setTheme(resid);
@@ -162,7 +165,7 @@
     public ApplicationInfo getApplicationInfo() {
         return mBase.getApplicationInfo();
     }
-    
+
     @Override
     public String getPackageResourcePath() {
         return mBase.getPackageResourcePath();
@@ -202,13 +205,13 @@
 
     @Override
     public FileInputStream openFileInput(String name)
-        throws FileNotFoundException {
+            throws FileNotFoundException {
         return mBase.openFileInput(name);
     }
 
     @Override
     public FileOutputStream openFileOutput(String name, int mode)
-        throws FileNotFoundException {
+            throws FileNotFoundException {
         return mBase.openFileOutput(name, mode);
     }
 
@@ -442,7 +445,7 @@
         mBase.startIntentSender(intent, fillInIntent, flagsMask,
                 flagsValues, extraFlags, options);
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         mBase.sendBroadcast(intent);
@@ -487,9 +490,9 @@
 
     @Override
     public void sendOrderedBroadcast(
-        Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
-        Handler scheduler, int initialCode, String initialData,
-        Bundle initialExtras) {
+            Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission,
                 resultReceiver, scheduler, initialCode,
                 initialData, initialExtras);
@@ -499,7 +502,8 @@
     @SystemApi
     @Override
     public void sendOrderedBroadcast(
-            Intent intent, String receiverPermission, Bundle options, BroadcastReceiver resultReceiver,
+            Intent intent, String receiverPermission, Bundle options,
+            BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
             Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission,
@@ -510,9 +514,9 @@
     /** @hide */
     @Override
     public void sendOrderedBroadcast(
-        Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
-        Handler scheduler, int initialCode, String initialData,
-        Bundle initialExtras) {
+            Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission, appOp,
                 resultReceiver, scheduler, initialCode,
                 initialData, initialExtras);
@@ -570,6 +574,15 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+        mBase.sendOrderedBroadcast(intent, receiverPermission, receiverAppOp, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f15b5d7..5c5c13d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -618,21 +618,6 @@
     }
 
     /**
-     * Generate and return the {@link PackageInfo} for a parsed package.
-     *
-     * @param p the parsed package.
-     * @param flags indicating which optional information is included.
-     */
-    @UnsupportedAppUsage
-    public static PackageInfo generatePackageInfo(PackageParser.Package p,
-            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
-            Set<String> grantedPermissions, PackageUserState state) {
-
-        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
-                grantedPermissions, state, UserHandle.getCallingUserId());
-    }
-
-    /**
      * Returns true if the package is installed and not hidden, or if the caller
      * explicitly wanted all uninstalled and hidden packages as well.
      * @param appInfo The applicationInfo of the app being checked.
@@ -658,8 +643,45 @@
         return checkUseInstalledOrHidden(0, state, null);
     }
 
+    /**
+     * Generate and return the {@link PackageInfo} for a parsed package.
+     *
+     * @param p the parsed package.
+     * @param flags indicating which optional information is included.
+     */
     @UnsupportedAppUsage
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
+            int[] gids, int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state) {
+
+        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, state, UserHandle.getCallingUserId());
+    }
+
+    @UnsupportedAppUsage
+    public static PackageInfo generatePackageInfo(PackageParser.Package p,
+            int[] gids, int flags, long firstInstallTime, long lastUpdateTime,
+            Set<String> grantedPermissions, PackageUserState state, int userId) {
+
+        return generatePackageInfo(p, null, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, state, userId);
+    }
+
+    /**
+     * PackageInfo generator specifically for apex files.
+     *
+     * @param pkg Package to generate info from. Should be derived from an apex.
+     * @param apexInfo Apex info relating to the package.
+     * @return PackageInfo
+     * @throws PackageParserException
+     */
+    public static PackageInfo generatePackageInfo(
+            PackageParser.Package pkg, ApexInfo apexInfo, int flags) {
+        return generatePackageInfo(pkg, apexInfo, EmptyArray.INT, flags, 0, 0,
+                Collections.emptySet(), new PackageUserState(), UserHandle.getCallingUserId());
+    }
+
+    private static PackageInfo generatePackageInfo(PackageParser.Package p, ApexInfo apexInfo,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             Set<String> grantedPermissions, PackageUserState state, int userId) {
         if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
@@ -806,8 +828,27 @@
                 }
             }
         }
+
+        if (apexInfo != null) {
+            File apexFile = new File(apexInfo.modulePath);
+
+            pi.applicationInfo.sourceDir = apexFile.getPath();
+            pi.applicationInfo.publicSourceDir = apexFile.getPath();
+            if (apexInfo.isFactory) {
+                pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+            } else {
+                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
+            }
+            if (apexInfo.isActive) {
+                pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+            } else {
+                pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+            }
+            pi.isApex = true;
+        }
+
         // deprecated method of getting signing certificates
-        if ((flags&PackageManager.GET_SIGNATURES) != 0) {
+        if ((flags & PackageManager.GET_SIGNATURES) != 0) {
             if (p.mSigningDetails.hasPastSigningCertificates()) {
                 // Package has included signing certificate rotation information.  Return the oldest
                 // cert so that programmatic checks keep working even if unaware of key rotation.
@@ -8379,61 +8420,4 @@
         }
     }
 
-    // TODO(b/129261524): Clean up API
-    /**
-     * PackageInfo parser specifically for apex files.
-     * NOTE: It will collect certificates
-     *
-     * @param apexInfo
-     * @return PackageInfo
-     * @throws PackageParserException
-     */
-    public static PackageInfo generatePackageInfoFromApex(ApexInfo apexInfo, int flags)
-            throws PackageParserException {
-        PackageParser pp = new PackageParser();
-        File apexFile = new File(apexInfo.modulePath);
-        final Package p = pp.parsePackage(apexFile, flags, false);
-        PackageUserState state = new PackageUserState();
-        PackageInfo pi = generatePackageInfo(p, EmptyArray.INT, flags, 0, 0,
-                Collections.emptySet(), state);
-        pi.applicationInfo.sourceDir = apexFile.getPath();
-        pi.applicationInfo.publicSourceDir = apexFile.getPath();
-        if (apexInfo.isFactory) {
-            pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        } else {
-            pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
-        }
-        if (apexInfo.isActive) {
-            pi.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
-        } else {
-            pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
-        }
-        pi.isApex = true;
-
-        // Collect certificates
-        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
-            collectCertificates(p, apexFile, false);
-            // Keep legacy mechanism for handling signatures. While this is deprecated, it's
-            // still part of the public API and needs to be maintained
-            if (p.mSigningDetails.hasPastSigningCertificates()) {
-                // Package has included signing certificate rotation information.  Return
-                // the oldest cert so that programmatic checks keep working even if unaware
-                // of key rotation.
-                pi.signatures = new Signature[1];
-                pi.signatures[0] = p.mSigningDetails.pastSigningCertificates[0];
-            } else if (p.mSigningDetails.hasSignatures()) {
-                // otherwise keep old behavior
-                int numberOfSigs = p.mSigningDetails.signatures.length;
-                pi.signatures = new Signature[numberOfSigs];
-                System.arraycopy(p.mSigningDetails.signatures, 0, pi.signatures, 0, numberOfSigs);
-            }
-            if (p.mSigningDetails != SigningDetails.UNKNOWN) {
-                // only return a valid SigningInfo if there is signing information to report
-                pi.signingInfo = new SigningInfo(p.mSigningDetails);
-            } else {
-                pi.signingInfo = null;
-            }
-        }
-        return pi;
-    }
 }
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 489a292..e9ea99f 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -77,7 +77,9 @@
 
     /**
      * Make a socket address that packet socket can send packets to.
+     * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead.
      */
+    @Deprecated
     @NonNull
     public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
         return new PacketSocketAddress(
@@ -87,6 +89,18 @@
     }
 
     /**
+     * Make a socket address that packet socket can send packets to.
+     */
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex,
+            @NonNull byte[] hwAddr) {
+        return new PacketSocketAddress(
+                protocol /* sll_protocol */,
+                ifIndex /* sll_ifindex */,
+                hwAddr /* sll_addr */);
+    }
+
+    /**
      * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
      */
     public static void closeSocket(@Nullable FileDescriptor fd) throws IOException {
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 97c0a13..c35b05f 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -241,32 +241,37 @@
             }
 
             Map<String, Integer> counts = new HashMap<>();
-            for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
-                if (a != null) {
-                    for (WeakReference<BinderProxy> weakRef : a) {
-                        BinderProxy bp = weakRef.get();
-                        String key;
-                        if (bp == null) {
-                            key = "<cleared weak-ref>";
-                        } else {
-                            try {
-                                key = bp.getInterfaceDescriptor();
-                                if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
-                                    key = "<proxy to dead node>";
-                                }
-                            } catch (Throwable t) {
-                                key = "<exception during getDescriptor>";
-                            }
-                        }
-                        Integer i = counts.get(key);
-                        if (i == null) {
-                            counts.put(key, 1);
-                        } else {
-                            counts.put(key, i + 1);
-                        }
+            final ArrayList<WeakReference<BinderProxy>> proxiesToQuery =
+                    new ArrayList<WeakReference<BinderProxy>>();
+            synchronized (sProxyMap) {
+                for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
+                    if (a != null) {
+                        proxiesToQuery.addAll(a);
                     }
                 }
             }
+            for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
+                BinderProxy bp = weakRef.get();
+                String key;
+                if (bp == null) {
+                    key = "<cleared weak-ref>";
+                } else {
+                    try {
+                        key = bp.getInterfaceDescriptor();
+                        if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
+                            key = "<proxy to dead node>";
+                        }
+                    } catch (Throwable t) {
+                        key = "<exception during getDescriptor>";
+                    }
+                }
+                Integer i = counts.get(key);
+                if (i == null) {
+                    counts.put(key, 1);
+                } else {
+                    counts.put(key, i + 1);
+                }
+            }
             Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
                     new Map.Entry[counts.size()]);
 
@@ -354,9 +359,7 @@
      * @hide
      */
     public static InterfaceCount[] getSortedInterfaceCounts(int num) {
-        synchronized (sProxyMap) {
-            return sProxyMap.getSortedInterfaceCounts(num);
-        }
+        return sProxyMap.getSortedInterfaceCounts(num);
     }
 
     /**
@@ -376,10 +379,8 @@
      */
     public static void dumpProxyDebugInfo() {
         if (Build.IS_DEBUGGABLE) {
-            synchronized (sProxyMap) {
-                sProxyMap.dumpProxyInterfaceCounts();
-                sProxyMap.dumpPerUidProxyCounts();
-            }
+            sProxyMap.dumpProxyInterfaceCounts();
+            sProxyMap.dumpPerUidProxyCounts();
         }
     }
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 154e8cd..4ed7b17 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1690,6 +1690,8 @@
      * such runtime statistic exists.
      *
      * <p>The following table lists the runtime statistics that the runtime supports.
+     * All statistics are approximate. Individual allocations may not be immediately reflected
+     * in the results.
      * Note runtime statistics may be added or removed in a future API level.</p>
      *
      * <table>
diff --git a/core/java/android/os/telephony/TelephonyRegistryManager.java b/core/java/android/os/telephony/TelephonyRegistryManager.java
new file mode 100644
index 0000000..b674099
--- /dev/null
+++ b/core/java/android/os/telephony/TelephonyRegistryManager.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2019 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.os.telephony;
+
+import android.annotation.SystemApi;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.Annotation;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataActivityType;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
+import android.telephony.Annotation.SrvccState;
+import android.telephony.CallQuality;
+import android.telephony.CellInfo;
+import android.telephony.DisconnectCause;
+import android.telephony.PhoneCapability;
+import android.telephony.PreciseCallState.State;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsReasonInfo;
+import com.android.internal.telephony.ITelephonyRegistry;
+import java.util.List;
+
+/**
+ * A centralized place to notify telephony related status changes, e.g, {@link ServiceState} update
+ * or {@link PhoneCapability} changed. This might trigger callback from applications side through
+ * {@link android.telephony.PhoneStateListener}
+ *
+ * TODO: limit API access to only carrier apps with certain permissions or apps running on
+ * privileged UID.
+ *
+ * @hide
+ */
+@SystemApi
+public class TelephonyRegistryManager {
+
+    private static final String TAG = "TelephonyRegistryManager";
+    private static ITelephonyRegistry sRegistry;
+
+    /** @hide **/
+    public TelephonyRegistryManager() {
+        if (sRegistry == null) {
+            sRegistry = ITelephonyRegistry.Stub.asInterface(
+                ServiceManager.getService("telephony.registry"));
+        }
+    }
+
+    /**
+     * Informs the system of an intentional upcoming carrier network change by a carrier app.
+     * This call only used to allow the system to provide alternative UI while telephony is
+     * performing an action that may result in intentional, temporary network lack of connectivity.
+     * <p>
+     * Based on the active parameter passed in, this method will either show or hide the alternative
+     * UI. There is no timeout associated with showing this UX, so a carrier app must be sure to
+     * call with active set to false sometime after calling with it set to {@code true}.
+     * <p>
+     * Requires Permission: calling app has carrier privileges.
+     *
+     * @param active Whether the carrier network change is or shortly will be
+     * active. Set this value to true to begin showing alternative UI and false to stop.
+     * @see TelephonyManager#hasCarrierPrivileges
+     */
+    public void notifyCarrierNetworkChange(boolean active) {
+        try {
+            sRegistry.notifyCarrierNetworkChange(active);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
+     * Notify call state changed on certain subscription.
+     *
+     * @param subId for which call state changed.
+     * @param slotIndex for which call state changed. Can be derived from subId except when subId is
+     * invalid.
+     * @param state latest call state. e.g, offhook, ringing
+     * @param incomingNumer incoming phone number.
+     *
+     * @hide
+     */
+    public void notifyCallStateChanged(int subId, int slotIndex, @CallState int state,
+        String incomingNumer) {
+        try {
+          sRegistry.notifyCallState(slotIndex, subId, state, incomingNumer);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
+     * Notify {@link ServiceState} update on certain subscription.
+     *
+     * @param subId for which the service state changed.
+     * @param slotIndex for which the service state changed. Can be derived from subId except
+     * subId is invalid.
+     * @param state service state e.g, in service, out of service or roaming status.
+     *
+     * @hide
+     */
+    public void notifyServiceStateChanged(int subId, int slotIndex, ServiceState state) {
+        try {
+            sRegistry.notifyServiceStateForPhoneId(slotIndex, subId, state);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
+     * Notify {@link SignalStrength} update on certain subscription.
+     *
+     * @param subId for which the signalstrength changed.
+     * @param slotIndex for which the signalstrength changed. Can be derived from subId except when
+     * subId is invalid.
+     * @param signalStrength e.g, signalstrength level {@see SignalStrength#getLevel()}
+     *
+     * @hide
+     */
+    public void notifySignalStrengthChanged(int subId, int slotIndex,
+        SignalStrength signalStrength) {
+        try {
+            sRegistry.notifySignalStrengthForPhoneId(slotIndex, subId, signalStrength);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
+     * Notify changes to the message-waiting indicator on certain subscription. e.g, The status bar
+     * uses message waiting indicator to determine when to display the voicemail icon.
+     *
+     * @param subId for which message waiting indicator changed.
+     * @param slotIndex for which message waiting indicator changed. Can be derived from subId
+     * except when subId is invalid.
+     * @param msgWaitingInd {@code true} indicates there is message-waiting indicator, {@code false}
+     * otherwise.
+     *
+     * @hide
+     */
+    public void notifyMessageWaitingChanged(int subId, int slotIndex, boolean msgWaitingInd) {
+        try {
+            sRegistry.notifyMessageWaitingChangedForPhoneId(slotIndex, subId, msgWaitingInd);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify changes to the call-forwarding status on certain subscription.
+     *
+     * @param subId for which call forwarding status changed.
+     * @param callForwardInd {@code true} indicates there is call forwarding, {@code false}
+     * otherwise.
+     *
+     * @hide
+     */
+    public void notifyCallForwardingChanged(int subId, boolean callForwardInd) {
+        try {
+            sRegistry.notifyCallForwardingChangedForSubscriber(subId, callForwardInd);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify changes to activity state changes on certain subscription.
+     *
+     * @param subId for which data activity state changed.
+     * @param dataActivityType indicates the latest data activity type e.g, {@link
+     * TelephonyManager#DATA_ACTIVITY_IN}
+     *
+     * @hide
+     */
+    public void notifyDataActivityChanged(int subId, @DataActivityType int dataActivityType) {
+        try {
+            sRegistry.notifyDataActivityForSubscriber(subId, dataActivityType);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify changes to default (Internet) data connection state on certain subscription.
+     *
+     * @param subId for which data connection state changed.
+     * @param slotIndex for which data connections state changed. Can be derived from subId except
+     * when subId is invalid.
+     * @param state latest data connection state, e.g,
+     * @param isDataConnectivityPossible indicates if data is allowed
+     * @param apn the APN {@link ApnSetting#getApnName()} of this data connection.
+     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN.
+     * @param linkProperties {@link LinkProperties} associated with this data connection.
+     * @param networkCapabilities {@link NetworkCapabilities} associated with this data connection.
+     * @param networkType associated with this data connection.
+     * @param roaming {@code true} indicates in roaming, {@false} otherwise.
+     * @see TelephonyManager#DATA_DISCONNECTED
+     * @see TelephonyManager#isDataConnectivityPossible()
+     *
+     * @hide
+     */
+    public void notifyDataConnectionForSubscriber(int slotIndex, int subId, @DataState int state,
+        boolean isDataConnectivityPossible,
+        @ApnType String apn, String apnType, LinkProperties linkProperties,
+        NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+        try {
+            sRegistry.notifyDataConnectionForSubscriber(slotIndex, subId, state,
+                isDataConnectivityPossible,
+                apn, apnType, linkProperties, networkCapabilities, networkType, roaming);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify {@link CallQuality} change on certain subscription.
+     *
+     * @param subId for which call quality state changed.
+     * @param slotIndex for which call quality state changed. Can be derived from subId except when
+     * subId is invalid.
+     * @param callQuality Information about call quality e.g, call quality level
+     * @param networkType associated with this data connection. e.g, LTE
+     *
+     * @hide
+     */
+    public void notifyCallQualityChanged(int subId, int slotIndex, CallQuality callQuality,
+        @NetworkType int networkType) {
+        try {
+            sRegistry.notifyCallQualityChanged(callQuality, slotIndex, subId, networkType);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify emergency number list changed on certain subscription.
+     *
+     * @param subId for which emergency number list changed.
+     * @param slotIndex for which emergency number list changed. Can be derived from subId except
+     * when subId is invalid.
+     *
+     * @hide
+     */
+    public void notifyEmergencyNumberList(int subId, int slotIndex) {
+        try {
+            sRegistry.notifyEmergencyNumberList(slotIndex, subId);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify radio power state changed on certain subscription.
+     *
+     * @param subId for which radio power state changed.
+     * @param slotIndex for which radio power state changed. Can be derived from subId except when
+     * subId is invalid.
+     * @param radioPowerState the current modem radio state.
+     *
+     * @hide
+     */
+    public void notifyRadioPowerStateChanged(int subId, int slotIndex,
+        @RadioPowerState int radioPowerState) {
+        try {
+            sRegistry.notifyRadioPowerStateChanged(slotIndex, subId, radioPowerState);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify {@link PhoneCapability} changed.
+     *
+     * @param phoneCapability the capability of the modem group.
+     *
+     * @hide
+     */
+    public void notifyPhoneCapabilityChanged(PhoneCapability phoneCapability) {
+        try {
+            sRegistry.notifyPhoneCapabilityChanged(phoneCapability);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify data activation state changed on certain subscription.
+     * @see TelephonyManager#getDataActivationState()
+     *
+     * @param subId for which data activation state changed.
+     * @param slotIndex for which data activation state changed. Can be derived from subId except
+     * when subId is invalid.
+     * @param activationState sim activation state e.g, activated.
+     *
+     * @hide
+     */
+    public void notifyDataActivationStateChanged(int subId, int slotIndex,
+        @SimActivationState int activationState) {
+        try {
+            sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
+                TelephonyManager.SIM_ACTIVATION_TYPE_DATA, activationState);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify voice activation state changed on certain subscription.
+     * @see TelephonyManager#getVoiceActivationState()
+     *
+     * @param subId for which voice activation state changed.
+     * @param slotIndex for which voice activation state changed. Can be derived from subId except
+     * subId is invalid.
+     * @param activationState sim activation state e.g, activated.
+     *
+     * @hide
+     */
+    public void notifyVoiceActivationStateChanged(int subId, int slotIndex,
+        @SimActivationState int activationState) {
+        try {
+            sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId,
+                TelephonyManager.SIM_ACTIVATION_TYPE_VOICE, activationState);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify User mobile data state changed on certain subscription. e.g, mobile data is enabled
+     * or disabled.
+     *
+     * @param subId for which mobile data state has changed.
+     * @param slotIndex for which mobile data state has changed. Can be derived from subId except
+     * when subId is invalid.
+     * @param state {@code true} indicates mobile data is enabled/on. {@code false} otherwise.
+     *
+     * @hide
+     */
+    public void notifyUserMobileDataStateChanged(int slotIndex, int subId, boolean state) {
+        try {
+            sRegistry.notifyUserMobileDataStateChangedForPhoneId(slotIndex, subId, state);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * TODO: this is marked as deprecated, can we move this one safely?
+     *
+     * @param subId
+     * @param slotIndex
+     * @param rawData
+     *
+     * @hide
+     */
+    public void notifyOemHookRawEventForSubscriber(int subId, int slotIndex, byte[] rawData) {
+        try {
+            sRegistry.notifyOemHookRawEventForSubscriber(slotIndex, subId, rawData);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify IMS call disconnect causes which contains {@link android.telephony.ims.ImsReasonInfo}.
+     *
+     * @param subId for which ims call disconnect.
+     * @param imsReasonInfo the reason for ims call disconnect.
+     *
+     * @hide
+     */
+    public void notifyImsDisconnectCause(int subId, ImsReasonInfo imsReasonInfo) {
+        try {
+            sRegistry.notifyImsDisconnectCause(subId, imsReasonInfo);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify precise data connection failed cause on certain subscription.
+     *
+     * @param subId for which data connection failed.
+     * @param slotIndex for which data conenction failed. Can be derived from subId except when
+     * subId is invalid.
+     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN.
+     * @param apn the APN {@link ApnSetting#getApnName()} of this data connection.
+     * @param failCause data fail cause.
+     *
+     * @hide
+     */
+    public void notifyPreciseDataConnectionFailed(int subId, int slotIndex, String apnType,
+        String apn, @DataFailureCause int failCause) {
+        try {
+            sRegistry.notifyPreciseDataConnectionFailed(slotIndex, subId, apnType, apn, failCause);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify single Radio Voice Call Continuity (SRVCC) state change for the currently active call
+     * on certain subscription.
+     *
+     * @param subId for which srvcc state changed.
+     * @param state srvcc state
+     *
+     * @hide
+     */
+    public void notifySrvccStateChanged(int subId, @SrvccState int state) {
+        try {
+            sRegistry.notifySrvccStateChanged(subId, state);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify over the air sim provisioning(OTASP) mode changed on certain subscription.
+     *
+     * @param subId for which otasp mode changed.
+     * @param otaspMode latest mode for OTASP e.g, OTASP needed.
+     *
+     * @hide
+     */
+    public void notifyOtaspChanged(int subId, int otaspMode) {
+        try {
+            sRegistry.notifyOtaspChanged(subId, otaspMode);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify precise call state changed on certain subscription, including foreground, background
+     * and ringcall states.
+     *
+     * @param subId for which precise call state changed.
+     * @param slotIndex for which precise call state changed. Can be derived from subId except when
+     * subId is invalid.
+     * @param ringCallPreciseState ringCall state.
+     * @param foregroundCallPreciseState foreground call state.
+     * @param backgroundCallPreciseState background call state.
+     *
+     * @hide
+     */
+    public void notifyPreciseCallState(int subId, int slotIndex, @State int ringCallPreciseState,
+        @State int foregroundCallPreciseState, @State int backgroundCallPreciseState) {
+        try {
+            sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
+                foregroundCallPreciseState, backgroundCallPreciseState);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify call disconnect causes which contains {@link DisconnectCause} and {@link
+     * android.telephony.PreciseDisconnectCause}.
+     *
+     * @param subId for which call disconnected.
+     * @param slotIndex for which call disconnected. Can be derived from subId except when subId is
+     * invalid.
+     * @param cause {@link DisconnectCause} for the disconnected call.
+     * @param preciseCause {@link android.telephony.PreciseDisconnectCause} for the disconnected
+     * call.
+     *
+     * @hide
+     */
+    public void notifyDisconnectCause(int slotIndex, int subId, int cause, int preciseCause) {
+        try {
+            sRegistry.notifyDisconnectCause(slotIndex, subId, cause, preciseCause);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify data connection failed on certain subscription.
+     *
+     * @param subId for which data connection failed.
+     * @param slotIndex for which data conenction faled. Can be derived from subId except when subId
+     * is invalid.
+     * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN. Note each data
+     * connection can support multiple anyTypes.
+     *
+     * @hide
+     */
+    public void notifyDataConnectionFailed(int subId, int slotIndex, String apnType) {
+        try {
+            sRegistry.notifyDataConnectionFailedForSubscriber(slotIndex, subId, apnType);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * TODO change from bundle to CellLocation?
+     * @hide
+     */
+    public void notifyCellLocation(int subId, Bundle cellLocation) {
+        try {
+            sRegistry.notifyCellLocationForSubscriber(subId, cellLocation);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
+    /**
+     * Notify {@link CellInfo} changed on certain subscription. e.g, when an observed cell info has
+     * changed or new cells have been added or removed on the given subscription.
+     *
+     * @param subId for which cellinfo changed.
+     * @param cellInfo A list of cellInfo associated with the given subscription.
+     *
+     * @hide
+     */
+    public void notifyCellInfoChanged(int subId, List<CellInfo> cellInfo) {
+        try {
+            sRegistry.notifyCellInfoForSubscriber(subId, cellInfo);
+        } catch (RemoteException ex) {
+
+        }
+    }
+
+}
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
new file mode 100644
index 0000000..de90b94
--- /dev/null
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.carrier;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Provides basic structure for platform to connect to the carrier messaging service.
+ * <p>
+ * <code>
+ * CarrierMessagingServiceWrapper carrierMessagingServiceWrapper =
+ *     new CarrierMessagingServiceWrapperImpl();
+ * if (carrierMessagingServiceWrapper.bindToCarrierMessagingService(context, carrierPackageName)) {
+ *   // wait for onServiceReady callback
+ * } else {
+ *   // Unable to bind: handle error.
+ * }
+ * </code>
+ * <p> Upon completion {@link #disposeConnection} should be called to unbind the
+ * CarrierMessagingService.
+ * @hide
+ */
+@SystemApi
+public abstract class CarrierMessagingServiceWrapper {
+    // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
+    // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
+    private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
+
+    private volatile ICarrierMessagingService mICarrierMessagingService;
+
+    /**
+     * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
+     * should be called exactly once.
+     *
+     * @param context the context
+     * @param carrierPackageName the carrier package name
+     * @return true upon successfully binding to a carrier messaging service, false otherwise
+     * @hide
+     */
+    @SystemApi
+    public boolean bindToCarrierMessagingService(@NonNull Context context,
+            @NonNull String carrierPackageName) {
+        Preconditions.checkState(mCarrierMessagingServiceConnection == null);
+
+        Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
+        intent.setPackage(carrierPackageName);
+        mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+        return context.bindService(intent, mCarrierMessagingServiceConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    /**
+     * Unbinds the carrier messaging service. This method should be called exactly once.
+     *
+     * @param context the context
+     * @hide
+     */
+    @SystemApi
+    public void disposeConnection(@NonNull Context context) {
+        Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
+        context.unbindService(mCarrierMessagingServiceConnection);
+        mCarrierMessagingServiceConnection = null;
+    }
+
+    /**
+     * Implemented by subclasses to use the carrier messaging service once it is ready.
+     * @hide
+     */
+    @SystemApi
+    public abstract void onServiceReady();
+
+    /**
+     * Called when connection with service is established.
+     *
+     * @param carrierMessagingService the carrier messaing service interface
+     */
+    private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+        mICarrierMessagingService = carrierMessagingService;
+        onServiceReady();
+    }
+
+    /**
+     * Request filtering an incoming SMS message.
+     * The service will call callback.onFilterComplete with the filtering result.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a data SMS. It will be -1 for text SMS
+     * @param subId SMS subscription ID of the SIM
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
+            int subId, @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param text the text to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
+            int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new data SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param data the data to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort port number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
+            int destPort, int sendSmsFlag,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
+                        sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new multi-part text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMultipartSmsComplete}
+     * with the send status.
+     *
+     * @param parts the parts of the multi-part text SMS to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
+            @NonNull String destAddress, int sendSmsFlag,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
+                        sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new MMS PDU from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMmsComplete} with the send
+     * status.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param subId SMS subscription ID of the SIM
+     * @param location the optional URI to send this MMS PDU. If this is {code null},
+     *        the PDU should be sent to the default MMSC URL.
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendMms(pduUri, subId, location,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request downloading a new MMS.
+     * The service will call {@link ICarrierMessagingCallback#onDownloadMmsComplete} with the
+     * download status.
+     *
+     * @param pduUri the content provider URI of the PDU to be downloaded.
+     * @param subId SMS subscription ID of the SIM
+     * @param location the URI of the message to be downloaded.
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.downloadMms(pduUri, subId, location,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * A basic {@link ServiceConnection}.
+     */
+    private final class CarrierMessagingServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+
+    /**
+     * Callback wrapper used for response to requests exposed by
+     * {@link CarrierMessagingServiceWrapper}.
+     * @hide
+     */
+    @SystemApi
+    public abstract static class CarrierMessagingCallbackWrapper {
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#filterSms}.
+         * @param result a bitmask integer to indicate how the incoming text SMS should be handled
+         *               by the platform. Bits set can be
+         *               {@link CarrierMessagingService#RECEIVE_OPTIONS_DROP} and
+         *               {@link CarrierMessagingService#
+         *               RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE}.
+         *               {@see CarrierMessagingService#onReceiveTextSms}.
+         * @hide
+         */
+        @SystemApi
+        public void onFilterComplete(int result) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendTextSms} and
+         * {@link CarrierMessagingServiceWrapper#sendDataSms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param messageRef message reference of the just-sent message. This field is applicable
+         *                   only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendSmsComplete(int result, int messageRef) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendMultipartTextSms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param messageRefs an array of message references, one for each part of the
+         *                    multipart SMS. This field is applicable only if result is
+         *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendMms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
+         *                    was sent. sendConfPdu is ignored if the {@code result} is not
+         *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#downloadMms}.
+         * @param result download status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @hide
+         */
+        @SystemApi
+        public void onDownloadMmsComplete(int result) {
+
+        }
+    }
+
+    private final class CarrierMessagingCallbackWrapperInternal
+            extends ICarrierMessagingCallback.Stub {
+        CarrierMessagingCallbackWrapper mCarrierMessagingCallbackWrapper;
+
+        CarrierMessagingCallbackWrapperInternal(CarrierMessagingCallbackWrapper callback) {
+            mCarrierMessagingCallbackWrapper = callback;
+        }
+
+        @Override
+        public void onFilterComplete(int result) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onFilterComplete(result);
+        }
+
+        @Override
+        public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendSmsComplete(result, messageRef);
+        }
+
+        @Override
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs)
+                throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendMultipartSmsComplete(result, messageRefs);
+        }
+
+        @Override
+        public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendMmsComplete(result, sendConfPdu);
+        }
+
+        @Override
+        public void onDownloadMmsComplete(int result) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onDownloadMmsComplete(result);
+        }
+    }
+}
diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java
index aeb186b..9184d6d 100644
--- a/core/java/android/service/carrier/CarrierService.java
+++ b/core/java/android/service/carrier/CarrierService.java
@@ -16,17 +16,15 @@
 
 import android.annotation.CallSuper;
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PersistableBundle;
-import android.os.RemoteException;
 import android.os.ResultReceiver;
-import android.os.ServiceManager;
+import android.os.telephony.TelephonyRegistryManager;
 import android.util.Log;
 
-import com.android.internal.telephony.ITelephonyRegistry;
-
 /**
  * A service that exposes carrier-specific functionality to the system.
  * <p>
@@ -55,16 +53,10 @@
 
     public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
 
-    private static ITelephonyRegistry sRegistry;
-
     private final ICarrierService.Stub mStubWrapper;
 
     public CarrierService() {
         mStubWrapper = new ICarrierServiceWrapper();
-        if (sRegistry == null) {
-            sRegistry = ITelephonyRegistry.Stub.asInterface(
-                    ServiceManager.getService("telephony.registry"));
-        }
     }
 
     /**
@@ -122,9 +114,12 @@
      * @see android.telephony.TelephonyManager#hasCarrierPrivileges
      */
     public final void notifyCarrierNetworkChange(boolean active) {
-        try {
-            if (sRegistry != null) sRegistry.notifyCarrierNetworkChange(active);
-        } catch (RemoteException | NullPointerException ex) {}
+        TelephonyRegistryManager telephonyRegistryMgr =
+            (TelephonyRegistryManager) this.getSystemService(
+                Context.TELEPHONY_REGISTRY_SERVICE);
+        if (telephonyRegistryMgr != null) {
+            telephonyRegistryMgr.notifyCarrierNetworkChange(active);
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 46e041b..3d91c37 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -114,6 +114,13 @@
      */
     public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
 
+    /**
+     * Disable runtime access to {@link android.annotation.TestApi} annotated members.
+     *
+     * <p>This only takes effect if Hidden API access restrictions are enabled as well.
+     */
+    public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
+
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9aacbe6..1f20d7a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -497,6 +497,7 @@
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED" />
     <protected-broadcast android:name="android.telephony.action.SECRET_CODE" />
     <protected-broadcast android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
     <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_PLANS_CHANGED" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 05f78d4..fc93fe1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -448,7 +448,7 @@
     </string-array>
 
     <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
-    <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastreceiver
+    <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastservice
     </string>
 
     <!-- If the mobile hotspot feature requires provisioning, a package name and class name
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 58c43ac2..5e41355 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -508,7 +508,12 @@
         apexInfo.modulePath = apexFile.getPath();
         apexInfo.versionCode = 191000070;
         int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
-        PackageInfo pi = PackageParser.generatePackageInfoFromApex(apexInfo, flags);
+
+        PackageParser pp = new PackageParser();
+        Package p = pp.parsePackage(apexFile, flags, false);
+        PackageParser.collectCertificates(p, false);
+        PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags);
+
         assertEquals("com.google.android.tzdata", pi.applicationInfo.packageName);
         assertTrue(pi.applicationInfo.enabled);
         assertEquals(28, pi.applicationInfo.targetSdkVersion);
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 1401137..80f3cc6 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -49,6 +49,12 @@
         <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.cellbroadcastservice">
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.externalstorage">
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
diff --git a/mms/OWNERS b/mms/OWNERS
new file mode 100644
index 0000000..ba00d5d
--- /dev/null
+++ b/mms/OWNERS
@@ -0,0 +1,14 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
+shuoq@google.com
+refuhoo@google.com
+nazaninb@google.com
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
new file mode 100644
index 0000000..4bcf046
--- /dev/null
+++ b/mms/java/android/telephony/MmsManager.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.app.ActivityThread;
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.IMms;
+
+/**
+ * Manages MMS operations such as sending multimedia messages.
+ * Get this object by calling the static method {@link #getInstance()}.
+ * @hide
+ */
+public class MmsManager {
+    private static final String TAG = "MmsManager";
+
+    /** Singleton object constructed during class initialization. */
+    private static final MmsManager sInstance = new MmsManager();
+
+    /**
+     * Get the MmsManager singleton instance.
+     *
+     * @return the {@link MmsManager} singleton instance.
+     */
+    public static MmsManager getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * Send an MMS message
+     *
+     * @param subId the subscription id
+     * @param contentUri the content Uri from which the message pdu will be read
+     * @param locationUrl the optional location url where message should be sent to
+     * @param configOverrides the carrier-specific messaging configuration values to override for
+     *                        sending the message.
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message
+     *                   is successfully sent, or failed
+     */
+    public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl,
+            Bundle configOverrides, PendingIntent sentIntent) {
+        try {
+            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms == null) {
+                return;
+            }
+
+            iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri,
+                    locationUrl, configOverrides, sentIntent);
+        } catch (RemoteException e) {
+            // Ignore it
+        }
+    }
+
+    /**
+     * Download an MMS message from carrier by a given location URL
+     *
+     * @param subId the subscription id
+     * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
+     *  from the MMS WAP push notification
+     * @param contentUri the content uri to which the downloaded pdu will be written
+     * @param configOverrides the carrier-specific messaging configuration values to override for
+     *  downloading the message.
+     * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is downloaded, or the download is failed
+     * @throws IllegalArgumentException if locationUrl or contentUri is empty
+     */
+    public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri,
+            Bundle configOverrides, PendingIntent downloadedIntent) {
+        try {
+            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms == null) {
+                return;
+            }
+            iMms.downloadMessage(subId, ActivityThread.currentPackageName(),
+                    locationUrl, contentUri, configOverrides, downloadedIntent);
+        } catch (RemoteException e) {
+            // Ignore it
+        }
+    }
+
+    /**
+     * Get carrier-dependent configuration values.
+     *
+     * @param subId the subscription id
+     * @return bundle key/values pairs of configuration values
+     */
+    public Bundle getCarrierConfigValues(int subId) {
+        try {
+            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms != null) {
+                return iMms.getCarrierConfigValues(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return null;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl
similarity index 100%
rename from telephony/java/com/android/internal/telephony/IMms.aidl
rename to mms/java/com/android/internal/telephony/IMms.aidl
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 998572f..61bfb92 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -27,6 +27,7 @@
         "androidx.annotation_annotation",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
+        "android.hardware.tetheroffload.control-V1.0-java",
         "tethering-client",
     ],
     manifest: "AndroidManifestBase.xml",
@@ -38,11 +39,39 @@
     defaults: ["TetheringAndroidLibraryDefaults"],
 }
 
+cc_library_shared {
+    name: "libtetheroffloadjni",
+    srcs: [
+        "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+    ],
+    shared_libs: [
+        "libnativehelper",
+        "libcutils",
+        "android.hardware.tetheroffload.config@1.0",
+    ],
+    static_libs: [
+        "liblog",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+}
+
 // Common defaults for compiling the actual APK.
 java_defaults {
     name: "TetheringAppDefaults",
     platform_apis: true,
     privileged: true,
+    jni_libs: [
+        "libtetheroffloadjni",
+    ],
     resource_dirs: [
         "res",
     ],
@@ -71,6 +100,8 @@
     name: "tethering-servicescore-srcs",
     srcs: [
         "src/com/android/server/connectivity/tethering/EntitlementManager.java",
+        "src/com/android/server/connectivity/tethering/OffloadController.java",
+        "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java",
         "src/com/android/server/connectivity/tethering/TetheringConfiguration.java",
         "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java",
     ],
@@ -88,3 +119,11 @@
         "src/android/net/util/PrefixUtils.java",
     ],
 }
+
+// This group would be removed when tethering migration is done.
+filegroup {
+    name: "tethering-jni-srcs",
+    srcs: [
+        "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+    ],
+}
diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
similarity index 100%
rename from services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
rename to packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
similarity index 97%
rename from services/core/java/com/android/server/connectivity/tethering/OffloadController.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index a3c2998..16734d8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -36,8 +36,8 @@
 import android.net.util.IpUtils;
 import android.net.util.SharedLog;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.INetworkManagementService;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -60,7 +60,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
 
 /**
  * A class to encapsulate the business logic of programming the tethering
@@ -74,7 +73,7 @@
     private static final String ANYIP = "0.0.0.0";
     private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
 
-    private static enum UpdateType { IF_NEEDED, FORCE };
+    private enum UpdateType { IF_NEEDED, FORCE };
 
     private final Handler mHandler;
     private final OffloadHardwareInterface mHwInterface;
@@ -128,6 +127,7 @@
         }
     }
 
+    /** Start hardware offload. */
     public boolean start() {
         if (started()) return true;
 
@@ -235,6 +235,7 @@
         return isStarted;
     }
 
+    /** Stop hardware offload. */
     public void stop() {
         // Completely stops tethering offload. After this method is called, it is no longer safe to
         // call any HAL method, no callbacks from the hardware will be delivered, and any in-flight
@@ -258,7 +259,9 @@
             // getTetherStats() is the only function in OffloadController that can be called from
             // a different thread. Do not attempt to update stats by querying the offload HAL
             // synchronously from a different thread than our Handler thread. http://b/64771555.
-            Runnable updateStats = () -> { updateStatsForCurrentUpstream(); };
+            Runnable updateStats = () -> {
+                updateStatsForCurrentUpstream();
+            };
             if (Looper.myLooper() == mHandler.getLooper()) {
                 updateStats.run();
             } else {
@@ -358,6 +361,7 @@
         }
     }
 
+    /** Set current tethering upstream LinkProperties. */
     public void setUpstreamLinkProperties(LinkProperties lp) {
         if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
 
@@ -376,6 +380,7 @@
         pushUpstreamParameters(prevUpstream);
     }
 
+    /** Set local prefixes. */
     public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
         mExemptPrefixes = localPrefixes;
 
@@ -383,6 +388,7 @@
         computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
     }
 
+    /** Update current downstream LinkProperties. */
     public void notifyDownstreamLinkProperties(LinkProperties lp) {
         final String ifname = lp.getInterfaceName();
         final LinkProperties oldLp = mDownstreams.put(ifname, new LinkProperties(lp));
@@ -421,6 +427,7 @@
         }
     }
 
+    /** Remove downstream interface from offload hardware. */
     public void removeDownstreamInterface(String ifname) {
         final LinkProperties lp = mDownstreams.remove(ifname);
         if (lp == null) return;
@@ -481,7 +488,7 @@
                 iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
 
         if (!success) {
-           return success;
+            return success;
         }
 
         // Update stats after we've told the hardware to change routing so we don't miss packets.
@@ -545,6 +552,7 @@
         return false;
     }
 
+    /** Dump information. */
     public void dump(IndentingPrintWriter pw) {
         if (isOffloadDisabled()) {
             pw.println("Offload disabled");
@@ -630,7 +638,7 @@
             if (ip instanceof Inet4Address) {
                 return (Inet4Address) ip;
             }
-        } catch (IllegalArgumentException iae) {}
+        } catch (IllegalArgumentException iae) { }
         return null;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
similarity index 81%
rename from services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 207f867..01339a4 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -23,9 +23,9 @@
 import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
 import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
 import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.net.util.SharedLog;
 import android.system.OsConstants;
 
 import java.util.ArrayList;
@@ -55,18 +55,34 @@
     private TetheringOffloadCallback mTetheringOffloadCallback;
     private ControlCallback mControlCallback;
 
+    /** The callback to notify status of offload management process. */
     public static class ControlCallback {
+        /** Offload started. */
         public void onStarted() {}
+        /**
+         * Offload stopped because an error has occurred in lower layer.
+         */
         public void onStoppedError() {}
+        /**
+         * Offload stopped because the device has moved to a bearer on which hardware offload is
+         * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
+         * likely fail and cannot be presumed to be saved inside of the hardware management process.
+         * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
+         * offload again.
+         */
         public void onStoppedUnsupported() {}
+        /** Indicate that offload is able to proivde support for this time. */
         public void onSupportAvailable() {}
+        /** Offload stopped because of usage limit reached. */
         public void onStoppedLimitReached() {}
 
+        /** Indicate to update NAT timeout. */
         public void onNatTimeoutUpdate(int proto,
                                        String srcAddr, int srcPort,
                                        String dstAddr, int dstPort) {}
     }
 
+    /** The object which records Tx/Rx forwarded bytes. */
     public static class ForwardedStats {
         public long rxBytes;
         public long txBytes;
@@ -76,11 +92,13 @@
             txBytes = 0;
         }
 
+        /** Add Tx/Rx bytes. */
         public void add(ForwardedStats other) {
             rxBytes += other.rxBytes;
             txBytes += other.txBytes;
         }
 
+        /** Returns the string representation of this object. */
         public String toString() {
             return String.format("rx:%s tx:%s", rxBytes, txBytes);
         }
@@ -91,14 +109,17 @@
         mLog = log.forSubComponent(TAG);
     }
 
+    /** Get default value indicating whether offload is supported. */
     public int getDefaultTetherOffloadDisabled() {
         return DEFAULT_TETHER_OFFLOAD_DISABLED;
     }
 
+    /** Configure offload management process. */
     public boolean initOffloadConfig() {
         return configOffload();
     }
 
+    /** Initialize the tethering offload HAL. */
     public boolean initOffloadControl(ControlCallback controlCb) {
         mControlCallback = controlCb;
 
@@ -125,8 +146,8 @@
             mOffloadControl.initOffload(
                     mTetheringOffloadCallback,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -134,9 +155,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Stop IOffloadControl. */
     public void stopOffloadControl() {
         if (mOffloadControl != null) {
             try {
@@ -154,6 +176,7 @@
         mLog.log("stopOffloadControl()");
     }
 
+    /** Get Tx/Rx usage from last query. */
     public ForwardedStats getForwardedStats(String upstream) {
         final String logmsg = String.format("getForwardedStats(%s)",  upstream);
 
@@ -174,6 +197,7 @@
         return stats;
     }
 
+    /** Set local prefixes to offload management process. */
     public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
         final String logmsg = String.format("setLocalPrefixes([%s])",
                 String.join(",", localPrefixes));
@@ -182,8 +206,8 @@
         try {
             mOffloadControl.setLocalPrefixes(localPrefixes,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -191,9 +215,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Set data limit value to offload management process. */
     public boolean setDataLimit(String iface, long limit) {
 
         final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
@@ -203,8 +228,8 @@
             mOffloadControl.setDataLimit(
                     iface, limit,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -212,9 +237,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Set upstream parameters to offload management process. */
     public boolean setUpstreamParameters(
             String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
         iface = (iface != null) ? iface : NO_INTERFACE_NAME;
@@ -230,8 +256,8 @@
             mOffloadControl.setUpstreamParameters(
                     iface, v4addr, v4gateway, v6gws,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -239,9 +265,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Add downstream prefix to offload management process. */
     public boolean addDownstreamPrefix(String ifname, String prefix) {
         final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
 
@@ -249,8 +276,8 @@
         try {
             mOffloadControl.addDownstream(ifname, prefix,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -258,9 +285,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Remove downstream prefix from offload management process. */
     public boolean removeDownstreamPrefix(String ifname, String prefix) {
         final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
 
@@ -268,8 +296,8 @@
         try {
             mOffloadControl.removeDownstream(ifname, prefix,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -277,7 +305,7 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
     private void record(String msg, Throwable t) {
@@ -286,7 +314,7 @@
 
     private void record(String msg, CbResults results) {
         final String logmsg = msg + YIELDS + results;
-        if (!results.success) {
+        if (!results.mSuccess) {
             mLog.e(logmsg);
         } else {
             mLog.log(logmsg);
@@ -298,7 +326,7 @@
         public final ControlCallback controlCb;
         public final SharedLog log;
 
-        public TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
+        TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
             handler = h;
             controlCb = cb;
             log = sharedLog;
@@ -332,7 +360,7 @@
         @Override
         public void updateTimeout(NatTimeoutUpdate params) {
             handler.post(() -> {
-                    controlCb.onNatTimeoutUpdate(
+                controlCb.onNatTimeoutUpdate(
                         networkProtocolToOsConstant(params.proto),
                         params.src.addr, uint16(params.src.port),
                         params.dst.addr, uint16(params.dst.port));
@@ -352,15 +380,15 @@
     }
 
     private static class CbResults {
-        boolean success;
-        String errMsg;
+        boolean mSuccess;
+        String mErrMsg;
 
         @Override
         public String toString() {
-            if (success) {
+            if (mSuccess) {
                 return "ok";
             } else {
-                return "fail: " + errMsg;
+                return "fail: " + mErrMsg;
             }
         }
     }
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 7c06e5f..363be18 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -25,6 +25,7 @@
     static_libs: [
         "androidx.test.rules",
         "frameworks-base-testutils",
+        "net-tests-utils",
         "mockito-target-extended-minus-junit4",
         "TetheringApiCurrentLib",
         "testables",
@@ -46,6 +47,7 @@
     name: "tethering-tests-src",
     srcs: [
         "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java",
+        "src/com/android/server/connectivity/tethering/OffloadControllerTest.java",
         "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java",
         "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java",
         "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java",
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
similarity index 98%
rename from tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 9931aec..8574f54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -26,10 +26,10 @@
 
 import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
 import static com.android.testutils.MiscAssertsKt.assertContainsAll;
+import static com.android.testutils.MiscAssertsKt.assertThrows;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
@@ -148,10 +148,8 @@
     public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
         setupFunctioningHardwareInterface();
         when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
-        try {
-            Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
-            fail();
-        } catch (SettingNotFoundException expected) {}
+        assertThrows(SettingNotFoundException.class, () ->
+                Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
 
         final OffloadController offload = makeOffloadController();
         offload.start();
@@ -168,10 +166,8 @@
     public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
         setupFunctioningHardwareInterface();
         when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
-        try {
-            Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
-            fail();
-        } catch (SettingNotFoundException expected) {}
+        assertThrows(SettingNotFoundException.class, () ->
+                Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
 
         final OffloadController offload = makeOffloadController();
         offload.start();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index fc0e286..ed68f32 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -54,7 +54,6 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
-        "netd_aidl_interface-java",
         "netd_event_listener_interface-java",
     ],
 }
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 3a7b5d6..207e007 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -700,14 +700,16 @@
                 Slog.d(TAG,"onAppIdleStateChanged: " + packageName + " u" + userId
                         + (idle ? " idle" : " active") + " " + bucket);
             }
-            final boolean changed;
-            if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
-                changed = mExemptedPackages.add(userId, packageName);
-            } else {
-                changed = mExemptedPackages.remove(userId, packageName);
-            }
-            if (changed) {
-                mHandler.notifyExemptChanged();
+            synchronized (mLock) {
+                final boolean changed;
+                if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
+                    changed = mExemptedPackages.add(userId, packageName);
+                } else {
+                    changed = mExemptedPackages.remove(userId, packageName);
+                }
+                if (changed) {
+                    mHandler.notifyExemptChanged();
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 1467888..447ed59 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,6 +33,9 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SrvccState;
 import android.telephony.CallAttributes;
 import android.telephony.CallQuality;
 import android.telephony.CellInfo;
@@ -245,7 +248,7 @@
 
     private int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-    @TelephonyManager.RadioPowerState
+    @RadioPowerState
     private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
     private final LocalLog mLocalLog = new LocalLog(100);
@@ -961,13 +964,13 @@
         }
     }
 
-    public void notifyCallState(int state, String phoneNumber) {
+    public void notifyCallStateForAllSubs(int state, String phoneNumber) {
         if (!checkNotifyPermission("notifyCallState()")) {
             return;
         }
 
         if (VDBG) {
-            log("notifyCallState: state=" + state + " phoneNumber=" + phoneNumber);
+            log("notifyCallStateForAllSubs: state=" + state + " phoneNumber=" + phoneNumber);
         }
 
         synchronized (mRecords) {
@@ -994,13 +997,12 @@
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
-    public void notifyCallStateForPhoneId(int phoneId, int subId, int state,
-                String incomingNumber) {
+    public void notifyCallState(int phoneId, int subId, int state, String incomingNumber) {
         if (!checkNotifyPermission("notifyCallState()")) {
             return;
         }
         if (VDBG) {
-            log("notifyCallStateForPhoneId: subId=" + subId
+            log("notifyCallState: subId=" + subId
                 + " state=" + state + " incomingNumber=" + incomingNumber);
         }
         synchronized (mRecords) {
@@ -1094,10 +1096,10 @@
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 switch (activationType) {
-                    case PhoneConstants.SIM_ACTIVATION_TYPE_VOICE:
+                    case TelephonyManager.SIM_ACTIVATION_TYPE_VOICE:
                         mVoiceActivationState[phoneId] = activationState;
                         break;
-                    case PhoneConstants.SIM_ACTIVATION_TYPE_DATA:
+                    case TelephonyManager.SIM_ACTIVATION_TYPE_DATA:
                         mDataActivationState[phoneId] = activationState;
                         break;
                     default:
@@ -1110,7 +1112,7 @@
                                 + " state=" + activationState);
                     }
                     try {
-                        if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_VOICE) &&
+                        if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_VOICE) &&
                                 r.matchPhoneStateListenerEvent(
                                         PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
                                 idMatch(r.subId, subId, phoneId)) {
@@ -1121,7 +1123,7 @@
                             }
                             r.callback.onVoiceActivationStateChanged(activationState);
                         }
-                        if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_DATA) &&
+                        if ((activationType == TelephonyManager.SIM_ACTIVATION_TYPE_DATA) &&
                                 r.matchPhoneStateListenerEvent(
                                         PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
                                 idMatch(r.subId, subId, phoneId)) {
@@ -1241,7 +1243,7 @@
     }
 
     public void notifyCellInfoForSubscriber(int subId, List<CellInfo> cellInfo) {
-        if (!checkNotifyPermission("notifyCellInfo()")) {
+        if (!checkNotifyPermission("notifyCellInfoForSubscriber()")) {
             return;
         }
         if (VDBG) {
@@ -1258,7 +1260,8 @@
                             checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
                         try {
                             if (DBG_LOC) {
-                                log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+                                log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo
+                                    + " r=" + r);
                             }
                             r.callback.onCellInfoChanged(cellInfo);
                         } catch (RemoteException ex) {
@@ -1718,7 +1721,7 @@
     }
 
     public void notifyPreciseDataConnectionFailed(int phoneId, int subId, String apnType,
-            String apn, @DataFailCause.FailCause int failCause) {
+            String apn, @DataFailureCause int failCause) {
         if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
             return;
         }
@@ -1748,7 +1751,7 @@
     }
 
     @Override
-    public void notifySrvccStateChanged(int subId, @TelephonyManager.SrvccState int state) {
+    public void notifySrvccStateChanged(int subId, @SrvccState int state) {
         if (!checkNotifyPermission("notifySrvccStateChanged()")) {
             return;
         }
@@ -1855,8 +1858,7 @@
         }
     }
 
-    public void notifyRadioPowerStateChanged(int phoneId, int subId,
-                                             @TelephonyManager.RadioPowerState int state) {
+    public void notifyRadioPowerStateChanged(int phoneId, int subId, @RadioPowerState int state) {
         if (!checkNotifyPermission("notifyRadioPowerStateChanged()")) {
             return;
         }
@@ -2227,7 +2229,7 @@
 
     private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
             String apnType, String apn, LinkProperties linkProperties,
-            @DataFailCause.FailCause int failCause) {
+            @DataFailureCause int failCause) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
         intent.putExtra(PhoneConstants.STATE_KEY, state);
         intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76bfc97..7609632 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7786,10 +7786,18 @@
                 false /* mountExtStorageFull */, abiOverride);
     }
 
-    // TODO: Move to ProcessList?
     @GuardedBy("this")
     final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
             boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) {
+        return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks,
+                false /* disableTestApiChecks */, mountExtStorageFull, abiOverride);
+    }
+
+    // TODO: Move to ProcessList?
+    @GuardedBy("this")
+    final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
+            boolean disableHiddenApiChecks, boolean disableTestApiChecks,
+            boolean mountExtStorageFull, String abiOverride) {
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -7824,7 +7832,7 @@
             mPersistentStartingProcesses.add(app);
             mProcessList.startProcessLocked(app, new HostingRecord("added application",
                     customProcess != null ? customProcess : app.processName),
-                    disableHiddenApiChecks, mountExtStorageFull, abiOverride);
+                    disableHiddenApiChecks, disableTestApiChecks, mountExtStorageFull, abiOverride);
         }
 
         return app;
@@ -15765,6 +15773,10 @@
                 enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
                         "disable hidden API checks");
             }
+            // Allow instrumented processes access to test APIs.
+            // TODO(satayev): make this configurable via testing framework.
+            boolean disableTestApiChecks = true;
+
             final boolean mountExtStorageFull = isCallerShell()
                     && (flags & INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL) != 0;
 
@@ -15779,7 +15791,7 @@
             }
 
             ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
-                    mountExtStorageFull, abiOverride);
+                    disableTestApiChecks, mountExtStorageFull, abiOverride);
             app.setActiveInstrumentation(activeInstr);
             activeInstr.mFinished = false;
             activeInstr.mRunningProcesses.add(app);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3d598dd..4692fd4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1419,15 +1419,11 @@
 
     /**
      * @return {@code true} if process start is successful, false otherwise.
-     * @param app
-     * @param hostingRecord
-     * @param disableHiddenApiChecks
-     * @param abiOverride
      */
     @GuardedBy("mService")
     boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
-            boolean disableHiddenApiChecks, boolean mountExtStorageFull,
-            String abiOverride) {
+            boolean disableHiddenApiChecks, boolean disableTestApiChecks,
+            boolean mountExtStorageFull, String abiOverride) {
         if (app.pendingStart) {
             return true;
         }
@@ -1572,6 +1568,10 @@
                     throw new IllegalStateException("Invalid API policy: " + policy);
                 }
                 runtimeFlags |= policyBits;
+
+                if (disableTestApiChecks) {
+                    runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY;
+                }
             }
 
             String useAppImageCache = SystemProperties.get(
@@ -1845,7 +1845,8 @@
     final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
             String abiOverride) {
         return startProcessLocked(app, hostingRecord,
-                false /* disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride);
+                false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
+                false /* mountExtStorageFull */, abiOverride);
     }
 
     @GuardedBy("mService")
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 055a4bd..24569a6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1582,12 +1582,13 @@
         setMicrophoneMuteNoCallerCheck(currentUser);
     }
 
-    private int rescaleIndex(int index, int srcStream, int dstStream) {
-        int srcRange =
-                mStreamStates[srcStream].getMaxIndex() - mStreamStates[srcStream].getMinIndex();
-        int dstRange =
-                mStreamStates[dstStream].getMaxIndex() - mStreamStates[dstStream].getMinIndex();
+    private int getIndexRange(int streamType) {
+        return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex());
+    }
 
+    private int rescaleIndex(int index, int srcStream, int dstStream) {
+        int srcRange = getIndexRange(srcStream);
+        int dstRange = getIndexRange(dstStream);
         if (srcRange == 0) {
             Log.e(TAG, "rescaleIndex : index range should not be zero");
             return mStreamStates[dstStream].getMinIndex();
@@ -1598,6 +1599,17 @@
                 / srcRange;
     }
 
+    private int rescaleStep(int step, int srcStream, int dstStream) {
+        int srcRange = getIndexRange(srcStream);
+        int dstRange = getIndexRange(dstStream);
+        if (srcRange == 0) {
+            Log.e(TAG, "rescaleStep : index range should not be zero");
+            return 0;
+        }
+
+        return ((step * dstRange + srcRange / 2) / srcRange);
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // IPC methods
     ///////////////////////////////////////////////////////////////////////////
@@ -1774,7 +1786,7 @@
             }
         } else {
             // convert one UI step (+/-1) into a number of internal units on the stream alias
-            step = rescaleIndex(10, streamType, streamTypeAlias);
+            step = rescaleStep(10, streamType, streamTypeAlias);
         }
 
         // If either the client forces allowing ringer modes for this adjustment,
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a0c00f8..fd44cbb 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -11,7 +11,7 @@
  * 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.s
+ * limitations under the License.
  */
 
 package com.android.server.pm;
@@ -29,17 +29,17 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.sysprop.ApexProperties;
-import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.File;
@@ -56,117 +56,33 @@
  * ApexManager class handles communications with the apex service to perform operation and queries,
  * as well as providing caching to avoid unnecessary calls to the service.
  */
-class ApexManager {
-    static final String TAG = "ApexManager";
-    private final IApexService mApexService;
-    private final Context mContext;
-    private final Object mLock = new Object();
-    /**
-     * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
-     * AndroidManifest.xml}
-     *
-     * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
-     * AndroidManifest.xml}.
-      */
-    @GuardedBy("mLock")
-    private List<PackageInfo> mAllPackagesCache;
-    /**
-     * A map from {@code apexName} to the {@Link PackageInfo} generated from the {@code
-     * AndroidManifest.xml}.
-     *
-     * <p>Note that key of this map is {@code apexName} field which corresponds to the {@code name}
-     * field of {@code apex_manifest.json}.
-     */
-    // TODO(b/132324953): remove.
-    @GuardedBy("mLock")
-    private ArrayMap<String, PackageInfo> mApexNameToPackageInfoCache;
+abstract class ApexManager {
 
-
-    ApexManager(Context context) {
-        mContext = context;
-        if (!isApexSupported()) {
-            mApexService = null;
-            return;
-        }
-        try {
-            mApexService = IApexService.Stub.asInterface(
-                ServiceManager.getServiceOrThrow("apexservice"));
-        } catch (ServiceNotFoundException e) {
-            throw new IllegalStateException("Required service apexservice not available");
-        }
-    }
+    private static final String TAG = "ApexManager";
 
     static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
     static final int MATCH_FACTORY_PACKAGE = 1 << 1;
-    @IntDef(
-            flag = true,
-            prefix = { "MATCH_"},
-            value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
-    @Retention(RetentionPolicy.SOURCE)
-    @interface PackageInfoFlags{}
 
-    void systemReady() {
-        if (!isApexSupported()) return;
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                onBootCompleted();
-                mContext.unregisterReceiver(this);
-            }
-        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
-    }
-
-    private void populateAllPackagesCacheIfNeeded() {
-        synchronized (mLock) {
-            if (mAllPackagesCache != null) {
-                return;
-            }
-            mApexNameToPackageInfoCache = new ArrayMap<>();
+    /**
+     * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
+     * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
+     * {@code true}.
+     */
+    static ApexManager create(Context systemContext) {
+        if (ApexProperties.updatable().orElse(false)) {
             try {
-                mAllPackagesCache = new ArrayList<>();
-                HashSet<String> activePackagesSet = new HashSet<>();
-                HashSet<String> factoryPackagesSet = new HashSet<>();
-                final ApexInfo[] allPkgs = mApexService.getAllPackages();
-                for (ApexInfo ai : allPkgs) {
-                    // If the device is using flattened APEX, don't report any APEX
-                    // packages since they won't be managed or updated by PackageManager.
-                    if ((new File(ai.modulePath)).isDirectory()) {
-                        break;
-                    }
-                    try {
-                        final PackageInfo pkg = PackageParser.generatePackageInfoFromApex(
-                                ai, PackageManager.GET_META_DATA
-                                        | PackageManager.GET_SIGNING_CERTIFICATES);
-                        mAllPackagesCache.add(pkg);
-                        if (ai.isActive) {
-                            if (activePackagesSet.contains(pkg.packageName)) {
-                                throw new IllegalStateException(
-                                        "Two active packages have the same name: "
-                                                + pkg.packageName);
-                            }
-                            activePackagesSet.add(pkg.packageName);
-                            // TODO(b/132324953): remove.
-                            mApexNameToPackageInfoCache.put(ai.moduleName, pkg);
-                        }
-                        if (ai.isFactory) {
-                            if (factoryPackagesSet.contains(pkg.packageName)) {
-                                throw new IllegalStateException(
-                                        "Two factory packages have the same name: "
-                                                + pkg.packageName);
-                            }
-                            factoryPackagesSet.add(pkg.packageName);
-                        }
-                    } catch (PackageParserException pe) {
-                        throw new IllegalStateException("Unable to parse: " + ai, pe);
-                    }
-                }
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
-                throw new RuntimeException(re);
+                return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow("apexservice")));
+            } catch (ServiceManager.ServiceNotFoundException e) {
+                throw new IllegalStateException("Required service apexservice not available");
             }
+        } else {
+            return new ApexManagerNoOp();
         }
     }
 
+    abstract void systemReady();
+
     /**
      * Retrieves information about an APEX package.
      *
@@ -179,35 +95,8 @@
      * @return a PackageInfo object with the information about the package, or null if the package
      *         is not found.
      */
-    @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
-        if (!isApexSupported()) return null;
-        populateAllPackagesCacheIfNeeded();
-        boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
-        boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
-        for (PackageInfo packageInfo: mAllPackagesCache) {
-            if (!packageInfo.packageName.equals(packageName)) {
-                continue;
-            }
-            if ((!matchActive || isActive(packageInfo))
-                    && (!matchFactory || isFactory(packageInfo))) {
-                return packageInfo;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns a {@link PackageInfo} for an active APEX package keyed by it's {@code apexName}.
-     *
-     * @deprecated this API will soon be deleted, please don't depend on it.
-     */
-    // TODO(b/132324953): delete.
-    @Deprecated
-    @Nullable PackageInfo getPackageInfoForApexName(String apexName) {
-        if (!isApexSupported()) return null;
-        populateAllPackagesCacheIfNeeded();
-        return mApexNameToPackageInfoCache.get(apexName);
-    }
+    @Nullable
+    abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
 
     /**
      * Retrieves information about all active APEX packages.
@@ -215,14 +104,7 @@
      * @return a List of PackageInfo object, each one containing information about a different
      *         active package.
      */
-    List<PackageInfo> getActivePackages() {
-        if (!isApexSupported()) return Collections.emptyList();
-        populateAllPackagesCacheIfNeeded();
-        return mAllPackagesCache
-                .stream()
-                .filter(item -> isActive(item))
-                .collect(Collectors.toList());
-    }
+    abstract List<PackageInfo> getActivePackages();
 
     /**
      * Retrieves information about all active pre-installed APEX packages.
@@ -230,14 +112,7 @@
      * @return a List of PackageInfo object, each one containing information about a different
      *         active pre-installed package.
      */
-    List<PackageInfo> getFactoryPackages() {
-        if (!isApexSupported()) return Collections.emptyList();
-        populateAllPackagesCacheIfNeeded();
-        return mAllPackagesCache
-                .stream()
-                .filter(item -> isFactory(item))
-                .collect(Collectors.toList());
-    }
+    abstract List<PackageInfo> getFactoryPackages();
 
     /**
      * Retrieves information about all inactive APEX packages.
@@ -245,14 +120,7 @@
      * @return a List of PackageInfo object, each one containing information about a different
      *         inactive package.
      */
-    List<PackageInfo> getInactivePackages() {
-        if (!isApexSupported()) return Collections.emptyList();
-        populateAllPackagesCacheIfNeeded();
-        return mAllPackagesCache
-                .stream()
-                .filter(item -> !isActive(item))
-                .collect(Collectors.toList());
-    }
+    abstract List<PackageInfo> getInactivePackages();
 
     /**
      * Checks if {@code packageName} is an apex package.
@@ -260,16 +128,7 @@
      * @param packageName package to check.
      * @return {@code true} if {@code packageName} is an apex package.
      */
-    boolean isApexPackage(String packageName) {
-        if (!isApexSupported()) return false;
-        populateAllPackagesCacheIfNeeded();
-        for (PackageInfo packageInfo : mAllPackagesCache) {
-            if (packageInfo.packageName.equals(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
+    abstract boolean isApexPackage(String packageName);
 
     /**
      * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
@@ -278,19 +137,8 @@
      * @param sessionId the identifier of the session.
      * @return an ApexSessionInfo object, or null if the session is not known.
      */
-    @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
-        if (!isApexSupported()) return null;
-        try {
-            ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
-            if (apexSessionInfo.isUnknown) {
-                return null;
-            }
-            return apexSessionInfo;
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            throw new RuntimeException(re);
-        }
-    }
+    @Nullable
+    abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
 
     /**
      * Submit a staged session to apex service. This causes the apex service to perform some initial
@@ -302,47 +150,19 @@
      * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
      *                        an array of identifiers of all the child sessions. Otherwise it should
      *                        be an empty array.
-     * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller
-     *                     and will be filled with a list of {@link ApexInfo} objects, each of which
-     *                     contains metadata about one of the packages being submitted as part of
-     *                     the session.
-     * @return whether the submission of the session was successful.
+     * @throws PackageManagerException if call to apexd fails
      */
-    boolean submitStagedSession(
-            int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) {
-        if (!isApexSupported()) return false;
-        try {
-            mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
-            return true;
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            throw new RuntimeException(re);
-        } catch (Exception e) {
-            Slog.e(TAG, "apexd verification failed", e);
-            return false;
-        }
-    }
+    abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+            throws PackageManagerException;
 
     /**
      * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
      * applied at next reboot.
      *
      * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
-     * @return true upon success, false if the session is unknown.
+     * @throws PackageManagerException if call to apexd fails
      */
-    boolean markStagedSessionReady(int sessionId) {
-        if (!isApexSupported()) return false;
-        try {
-            mApexService.markStagedSessionReady(sessionId);
-            return true;
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            throw new RuntimeException(re);
-        } catch (Exception e) {
-            Slog.e(TAG, "Failed to mark session " + sessionId + " ready", e);
-            return false;
-        }
-    }
+    abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
 
     /**
      * Marks a staged session as successful.
@@ -352,44 +172,21 @@
      * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
      *                  successful.
      */
-    void markStagedSessionSuccessful(int sessionId) {
-        if (!isApexSupported()) return;
-        try {
-            mApexService.markStagedSessionSuccessful(sessionId);
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            throw new RuntimeException(re);
-        } catch (Exception e) {
-            // It is fine to just log an exception in this case. APEXd will be able to recover in
-            // case markStagedSessionSuccessful fails.
-            Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
-        }
-    }
+    abstract void markStagedSessionSuccessful(int sessionId);
 
     /**
      * Whether the current device supports the management of APEX packages.
      *
      * @return true if APEX packages can be managed on this device, false otherwise.
      */
-    boolean isApexSupported() {
-        return ApexProperties.updatable().orElse(false);
-    }
+    abstract boolean isApexSupported();
 
     /**
      * Abandons the (only) active session previously submitted.
      *
      * @return {@code true} upon success, {@code false} if any remote exception occurs
      */
-    boolean abortActiveSession() {
-        if (!isApexSupported()) return false;
-        try {
-            mApexService.abortActiveSession();
-            return true;
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to contact apexservice", re);
-            return false;
-        }
-    }
+    abstract boolean abortActiveSession();
 
     /**
      * Uninstalls given {@code apexPackage}.
@@ -399,64 +196,7 @@
      * @param apexPackagePath package to uninstall.
      * @return {@code true} upon successful uninstall, {@code false} otherwise.
      */
-    boolean uninstallApex(String apexPackagePath) {
-        if (!isApexSupported()) return false;
-        try {
-            mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
-            return true;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    /**
-     * Whether an APEX package is active or not.
-     *
-     * @param packageInfo the package to check
-     * @return {@code true} if this package is active, {@code false} otherwise.
-     */
-    private static boolean isActive(PackageInfo packageInfo) {
-        return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
-    }
-
-    /**
-     * Whether the APEX package is pre-installed or not.
-     *
-     * @param packageInfo the package to check
-     * @return {@code true} if this package is pre-installed, {@code false} otherwise.
-     */
-    private static boolean isFactory(PackageInfo packageInfo) {
-        return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-    }
-
-    /**
-     * Dump information about the packages contained in a particular cache
-     * @param packagesCache the cache to print information about.
-     * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
-     *                    information about that specific package will be dumped.
-     * @param ipw the {@link IndentingPrintWriter} object to send information to.
-     */
-    void dumpFromPackagesCache(
-            List<PackageInfo> packagesCache,
-            @Nullable String packageName,
-            IndentingPrintWriter ipw) {
-        ipw.println();
-        ipw.increaseIndent();
-        for (PackageInfo pi : packagesCache) {
-            if (packageName != null && !packageName.equals(pi.packageName)) {
-                continue;
-            }
-            ipw.println(pi.packageName);
-            ipw.increaseIndent();
-            ipw.println("Version: " + pi.versionCode);
-            ipw.println("Path: " + pi.applicationInfo.sourceDir);
-            ipw.println("IsActive: " + isActive(pi));
-            ipw.println("IsFactory: " + isFactory(pi));
-            ipw.decreaseIndent();
-        }
-        ipw.decreaseIndent();
-        ipw.println();
-    }
+    abstract boolean uninstallApex(String apexPackagePath);
 
     /**
      * Dumps various state information to the provided {@link PrintWriter} object.
@@ -465,54 +205,422 @@
      * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
      *                    information about that specific package will be dumped.
      */
-    void dump(PrintWriter pw, @Nullable String packageName) {
-        if (!isApexSupported()) return;
-        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
-        try {
-            populateAllPackagesCacheIfNeeded();
-            ipw.println();
-            ipw.println("Active APEX packages:");
-            dumpFromPackagesCache(getActivePackages(), packageName, ipw);
-            ipw.println("Inactive APEX packages:");
-            dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
-            ipw.println("Factory APEX packages:");
-            dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
-            ipw.increaseIndent();
-            ipw.println("APEX session state:");
-            ipw.increaseIndent();
-            final ApexSessionInfo[] sessions = mApexService.getSessions();
-            for (ApexSessionInfo si : sessions) {
-                ipw.println("Session ID: " + si.sessionId);
-                ipw.increaseIndent();
-                if (si.isUnknown) {
-                    ipw.println("State: UNKNOWN");
-                } else if (si.isVerified) {
-                    ipw.println("State: VERIFIED");
-                } else if (si.isStaged) {
-                    ipw.println("State: STAGED");
-                } else if (si.isActivated) {
-                    ipw.println("State: ACTIVATED");
-                } else if (si.isActivationFailed) {
-                    ipw.println("State: ACTIVATION FAILED");
-                } else if (si.isSuccess) {
-                    ipw.println("State: SUCCESS");
-                } else if (si.isRollbackInProgress) {
-                    ipw.println("State: ROLLBACK IN PROGRESS");
-                } else if (si.isRolledBack) {
-                    ipw.println("State: ROLLED BACK");
-                } else if (si.isRollbackFailed) {
-                    ipw.println("State: ROLLBACK FAILED");
+    abstract void dump(PrintWriter pw, @Nullable String packageName);
+
+    @IntDef(
+            flag = true,
+            prefix = { "MATCH_"},
+            value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface PackageInfoFlags{}
+
+    /**
+     * An implementation of {@link ApexManager} that should be used in case device supports updating
+     * APEX packages.
+     */
+    @VisibleForTesting
+    static class ApexManagerImpl extends ApexManager {
+        private final IApexService mApexService;
+        private final Context mContext;
+        private final Object mLock = new Object();
+        /**
+         * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
+         * AndroidManifest.xml}
+         *
+         * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
+         * AndroidManifest.xml}.
+          */
+        @GuardedBy("mLock")
+        private List<PackageInfo> mAllPackagesCache;
+
+        ApexManagerImpl(Context context, IApexService apexService) {
+            mContext = context;
+            mApexService = apexService;
+        }
+
+        /**
+         * Whether an APEX package is active or not.
+         *
+         * @param packageInfo the package to check
+         * @return {@code true} if this package is active, {@code false} otherwise.
+         */
+        private static boolean isActive(PackageInfo packageInfo) {
+            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
+        }
+
+        /**
+         * Whether the APEX package is pre-installed or not.
+         *
+         * @param packageInfo the package to check
+         * @return {@code true} if this package is pre-installed, {@code false} otherwise.
+         */
+        private static boolean isFactory(PackageInfo packageInfo) {
+            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        }
+
+        @Override
+        void systemReady() {
+            mContext.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
+                    // expensive to run it in broadcast handler thread.
+                    BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
+                    mContext.unregisterReceiver(this);
                 }
+            }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+        }
+
+        private void populateAllPackagesCacheIfNeeded() {
+            synchronized (mLock) {
+                if (mAllPackagesCache != null) {
+                    return;
+                }
+                try {
+                    mAllPackagesCache = new ArrayList<>();
+                    HashSet<String> activePackagesSet = new HashSet<>();
+                    HashSet<String> factoryPackagesSet = new HashSet<>();
+                    final ApexInfo[] allPkgs = mApexService.getAllPackages();
+                    for (ApexInfo ai : allPkgs) {
+                        // If the device is using flattened APEX, don't report any APEX
+                        // packages since they won't be managed or updated by PackageManager.
+                        if ((new File(ai.modulePath)).isDirectory()) {
+                            break;
+                        }
+                        int flags = PackageManager.GET_META_DATA
+                                | PackageManager.GET_SIGNING_CERTIFICATES
+                                | PackageManager.GET_SIGNATURES;
+                        PackageParser.Package pkg;
+                        try {
+                            File apexFile = new File(ai.modulePath);
+                            PackageParser pp = new PackageParser();
+                            pkg = pp.parsePackage(apexFile, flags, false);
+                            PackageParser.collectCertificates(pkg, false);
+                        } catch (PackageParser.PackageParserException pe) {
+                            throw new IllegalStateException("Unable to parse: " + ai, pe);
+                        }
+
+                        final PackageInfo packageInfo =
+                                PackageParser.generatePackageInfo(pkg, ai, flags);
+                        mAllPackagesCache.add(packageInfo);
+                        if (ai.isActive) {
+                            if (activePackagesSet.contains(packageInfo.packageName)) {
+                                throw new IllegalStateException(
+                                        "Two active packages have the same name: "
+                                                + packageInfo.packageName);
+                            }
+                            activePackagesSet.add(packageInfo.packageName);
+                        }
+                        if (ai.isFactory) {
+                            if (factoryPackagesSet.contains(packageInfo.packageName)) {
+                                throw new IllegalStateException(
+                                        "Two factory packages have the same name: "
+                                                + packageInfo.packageName);
+                            }
+                            factoryPackagesSet.add(packageInfo.packageName);
+                        }
+
+                    }
+                } catch (RemoteException re) {
+                    Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+                    throw new RuntimeException(re);
+                }
+            }
+        }
+
+        @Override
+        @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
+            populateAllPackagesCacheIfNeeded();
+            boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
+            boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
+            for (PackageInfo packageInfo: mAllPackagesCache) {
+                if (!packageInfo.packageName.equals(packageName)) {
+                    continue;
+                }
+                if ((matchActive && isActive(packageInfo))
+                        || (matchFactory && isFactory(packageInfo))) {
+                    return packageInfo;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        List<PackageInfo> getActivePackages() {
+            populateAllPackagesCacheIfNeeded();
+            return mAllPackagesCache
+                    .stream()
+                    .filter(item -> isActive(item))
+                    .collect(Collectors.toList());
+        }
+
+        @Override
+        List<PackageInfo> getFactoryPackages() {
+            populateAllPackagesCacheIfNeeded();
+            return mAllPackagesCache
+                    .stream()
+                    .filter(item -> isFactory(item))
+                    .collect(Collectors.toList());
+        }
+
+        @Override
+        List<PackageInfo> getInactivePackages() {
+            populateAllPackagesCacheIfNeeded();
+            return mAllPackagesCache
+                    .stream()
+                    .filter(item -> !isActive(item))
+                    .collect(Collectors.toList());
+        }
+
+        @Override
+        boolean isApexPackage(String packageName) {
+            if (!isApexSupported()) return false;
+            populateAllPackagesCacheIfNeeded();
+            for (PackageInfo packageInfo : mAllPackagesCache) {
+                if (packageInfo.packageName.equals(packageName)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
+            try {
+                ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
+                if (apexSessionInfo.isUnknown) {
+                    return null;
+                }
+                return apexSessionInfo;
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to contact apexservice", re);
+                throw new RuntimeException(re);
+            }
+        }
+
+        @Override
+        ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+                throws PackageManagerException {
+            try {
+                final ApexInfoList apexInfoList = new ApexInfoList();
+                mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+                return apexInfoList;
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to contact apexservice", re);
+                throw new RuntimeException(re);
+            } catch (Exception e) {
+                throw new PackageManagerException(
+                        PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        "apexd verification failed : " + e.getMessage());
+            }
+        }
+
+        @Override
+        void markStagedSessionReady(int sessionId) throws PackageManagerException {
+            try {
+                mApexService.markStagedSessionReady(sessionId);
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to contact apexservice", re);
+                throw new RuntimeException(re);
+            } catch (Exception e) {
+                throw new PackageManagerException(
+                        PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        "Failed to mark apexd session as ready : " + e.getMessage());
+            }
+        }
+
+        @Override
+        void markStagedSessionSuccessful(int sessionId) {
+            try {
+                mApexService.markStagedSessionSuccessful(sessionId);
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to contact apexservice", re);
+                throw new RuntimeException(re);
+            } catch (Exception e) {
+                // It is fine to just log an exception in this case. APEXd will be able to recover
+                // in case markStagedSessionSuccessful fails.
+                Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
+            }
+        }
+
+        @Override
+        boolean isApexSupported() {
+            return true;
+        }
+
+        @Override
+        boolean abortActiveSession() {
+            try {
+                mApexService.abortActiveSession();
+                return true;
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to contact apexservice", re);
+                return false;
+            }
+        }
+
+        @Override
+        boolean uninstallApex(String apexPackagePath) {
+            try {
+                mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
+                return true;
+            } catch (Exception e) {
+                return false;
+            }
+        }
+
+        /**
+         * Dump information about the packages contained in a particular cache
+         * @param packagesCache the cache to print information about.
+         * @param packageName a {@link String} containing a package name, or {@code null}. If set,
+         *                    only information about that specific package will be dumped.
+         * @param ipw the {@link IndentingPrintWriter} object to send information to.
+         */
+        void dumpFromPackagesCache(
+                List<PackageInfo> packagesCache,
+                @Nullable String packageName,
+                IndentingPrintWriter ipw) {
+            ipw.println();
+            ipw.increaseIndent();
+            for (PackageInfo pi : packagesCache) {
+                if (packageName != null && !packageName.equals(pi.packageName)) {
+                    continue;
+                }
+                ipw.println(pi.packageName);
+                ipw.increaseIndent();
+                ipw.println("Version: " + pi.versionCode);
+                ipw.println("Path: " + pi.applicationInfo.sourceDir);
+                ipw.println("IsActive: " + isActive(pi));
+                ipw.println("IsFactory: " + isFactory(pi));
                 ipw.decreaseIndent();
             }
             ipw.decreaseIndent();
-        } catch (RemoteException e) {
-            ipw.println("Couldn't communicate with apexd.");
+            ipw.println();
+        }
+
+        @Override
+        void dump(PrintWriter pw, @Nullable String packageName) {
+            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
+            try {
+                populateAllPackagesCacheIfNeeded();
+                ipw.println();
+                ipw.println("Active APEX packages:");
+                dumpFromPackagesCache(getActivePackages(), packageName, ipw);
+                ipw.println("Inactive APEX packages:");
+                dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
+                ipw.println("Factory APEX packages:");
+                dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
+                ipw.increaseIndent();
+                ipw.println("APEX session state:");
+                ipw.increaseIndent();
+                final ApexSessionInfo[] sessions = mApexService.getSessions();
+                for (ApexSessionInfo si : sessions) {
+                    ipw.println("Session ID: " + si.sessionId);
+                    ipw.increaseIndent();
+                    if (si.isUnknown) {
+                        ipw.println("State: UNKNOWN");
+                    } else if (si.isVerified) {
+                        ipw.println("State: VERIFIED");
+                    } else if (si.isStaged) {
+                        ipw.println("State: STAGED");
+                    } else if (si.isActivated) {
+                        ipw.println("State: ACTIVATED");
+                    } else if (si.isActivationFailed) {
+                        ipw.println("State: ACTIVATION FAILED");
+                    } else if (si.isSuccess) {
+                        ipw.println("State: SUCCESS");
+                    } else if (si.isRollbackInProgress) {
+                        ipw.println("State: ROLLBACK IN PROGRESS");
+                    } else if (si.isRolledBack) {
+                        ipw.println("State: ROLLED BACK");
+                    } else if (si.isRollbackFailed) {
+                        ipw.println("State: ROLLBACK FAILED");
+                    }
+                    ipw.decreaseIndent();
+                }
+                ipw.decreaseIndent();
+            } catch (RemoteException e) {
+                ipw.println("Couldn't communicate with apexd.");
+            }
         }
     }
 
-    public void onBootCompleted() {
-        if (!isApexSupported()) return;
-        populateAllPackagesCacheIfNeeded();
+    /**
+     * An implementation of {@link ApexManager} that should be used in case device does not support
+     * updating APEX packages.
+     */
+    private static final class ApexManagerNoOp extends ApexManager {
+
+        @Override
+        void systemReady() {
+            // No-op
+        }
+
+        @Override
+        PackageInfo getPackageInfo(String packageName, int flags) {
+            return null;
+        }
+
+        @Override
+        List<PackageInfo> getActivePackages() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        List<PackageInfo> getFactoryPackages() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        List<PackageInfo> getInactivePackages() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        boolean isApexPackage(String packageName) {
+            return false;
+        }
+
+        @Override
+        ApexSessionInfo getStagedSessionInfo(int sessionId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
+                throws PackageManagerException {
+            throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                    "Device doesn't support updating APEX");
+        }
+
+        @Override
+        void markStagedSessionReady(int sessionId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        void markStagedSessionSuccessful(int sessionId) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        boolean isApexSupported() {
+            return false;
+        }
+
+        @Override
+        boolean abortActiveSession() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        boolean uninstallApex(String apexPackagePath) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        void dump(PrintWriter pw, String packageName) {
+            // No-op
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0460a80..868b90a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2474,7 +2474,8 @@
 
         mProtectedPackages = new ProtectedPackages(mContext);
 
-        mApexManager = new ApexManager(context);
+        mApexManager = ApexManager.create(context);
+        // CHECKSTYLE:OFF IndentationCheck
         synchronized (mInstallLock) {
         // writer
         synchronized (mPackages) {
@@ -4262,7 +4263,7 @@
                 }
                 return generatePackageInfo(ps, flags, userId);
             }
-            if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
+            if ((flags & MATCH_APEX) != 0) {
                 return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
             }
         }
@@ -9334,6 +9335,16 @@
             pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
             pkgAlreadyExists = pkgSetting != null;
             final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+            if (scanSystemPartition && !pkgAlreadyExists
+                    && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
+                // The updated-package data for /system apk remains inconsistently
+                // after the package data for /data apk is lost accidentally.
+                // To recover it, enable /system apk and install it as non-updated system app.
+                Slog.w(TAG, "Inconsistent package setting of updated system app for "
+                        + disabledPkgName + ". To recover it, enable the system app"
+                        + "and install it as non-updated system app.");
+                mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
+            }
             disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
             isSystemPkgUpdated = disabledPkgSetting != null;
 
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 88d681f..2705455 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
@@ -43,6 +44,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.apk.ApkSignatureVerifier;
@@ -104,21 +106,22 @@
         return new ParceledListSlice<>(result);
     }
 
-    private boolean validateApexSignature(String apexPath, String apexModuleName) {
+    private void validateApexSignature(String apexPath, String packageName)
+            throws PackageManagerException {
         final SigningDetails signingDetails;
         try {
             signingDetails = ApkSignatureVerifier.verify(apexPath, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
-            Slog.e(TAG, "Unable to parse APEX package: " + apexPath, e);
-            return false;
+            throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    "Failed to parse APEX package " + apexPath, e);
         }
 
-        final PackageInfo packageInfo = mApexManager.getPackageInfoForApexName(apexModuleName);
-
+        final PackageInfo packageInfo = mApexManager.getPackageInfo(packageName,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
         if (packageInfo == null) {
-            // Don't allow installation of new APEX.
-            Slog.e(TAG, "Attempted to install a new apex " + apexModuleName + ". Rejecting");
-            return false;
+            // This should never happen, because submitSessionToApexService ensures that no new
+            // apexes were installed.
+            throw new IllegalStateException("Unknown apex package " + packageName);
         }
 
         final SigningDetails existingSigningDetails;
@@ -126,73 +129,99 @@
             existingSigningDetails = ApkSignatureVerifier.verify(
                 packageInfo.applicationInfo.sourceDir, SignatureSchemeVersion.JAR);
         } catch (PackageParserException e) {
-            Slog.e(TAG, "Unable to parse APEX package: "
-                    + packageInfo.applicationInfo.sourceDir, e);
-            return false;
+            throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    "Failed to parse APEX package " + packageInfo.applicationInfo.sourceDir, e);
         }
 
         // Now that we have both sets of signatures, demand that they're an exact match.
         if (Signature.areExactMatch(existingSigningDetails.signatures, signingDetails.signatures)) {
-            return true;
+            return;
         }
 
-        return false;
+        throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                "APK-container signature verification failed for package "
+                        + packageName + ". Signature of file "
+                        + apexPath + " does not match the signature of "
+                        + " the package already installed.");
     }
 
-    private boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
-                                               List<PackageInstallerSession> childSessions,
-                                               ApexInfoList apexInfoList) {
-        boolean submittedToApexd = mApexManager.submitStagedSession(
-                session.sessionId,
-                childSessions != null
-                        ? childSessions.stream().mapToInt(s -> s.sessionId).toArray() :
-                        new int[]{},
-                apexInfoList);
-        if (!submittedToApexd) {
-            session.setStagedSessionFailed(
-                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                    "APEX staging failed, check logcat messages from apexd for more details.");
-            return false;
-        }
-        for (ApexInfo newModule : apexInfoList.apexInfos) {
-            PackageInfo activePackage = mApexManager.getPackageInfoForApexName(
-                    newModule.moduleName);
-            if (activePackage == null) {
-                continue;
+    private List<PackageInfo> submitSessionToApexService(
+            @NonNull PackageInstallerSession session) throws PackageManagerException {
+        final IntArray childSessionsIds = new IntArray();
+        if (session.isMultiPackage()) {
+            for (int id : session.getChildSessionIds()) {
+                if (isApexSession(mStagedSessions.get(id))) {
+                    childSessionsIds.add(id);
+                }
             }
-            long activeVersion = activePackage.applicationInfo.longVersionCode;
-            if (session.params.requiredInstalledVersionCode
-                    != PackageManager.VERSION_CODE_HIGHEST) {
-                if (activeVersion != session.params.requiredInstalledVersionCode) {
-                    session.setStagedSessionFailed(
-                            SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                            "Installed version of APEX package " + activePackage.packageName
+        }
+        // submitStagedSession will throw a PackageManagerException if apexd verification fails,
+        // which will be propagated to populate stagedSessionErrorMessage of this session.
+        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
+                childSessionsIds.toArray());
+        final List<PackageInfo> result = new ArrayList<>();
+        for (ApexInfo apexInfo : apexInfoList.apexInfos) {
+            final PackageInfo packageInfo;
+            int flags = PackageManager.GET_META_DATA;
+            PackageParser.Package pkg;
+            try {
+                File apexFile = new File(apexInfo.modulePath);
+                PackageParser pp = new PackageParser();
+                pkg = pp.parsePackage(apexFile, flags, false);
+            } catch (PackageParserException e) {
+                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        "Failed to parse APEX package " + apexInfo.modulePath, e);
+            }
+            packageInfo = PackageParser.generatePackageInfo(pkg, apexInfo, flags);
+            final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
+                    ApexManager.MATCH_ACTIVE_PACKAGE);
+            if (activePackage == null) {
+                Slog.w(TAG, "Attempting to install new APEX package " + packageInfo.packageName);
+                throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                        "It is forbidden to install new APEX packages.");
+            }
+            checkRequiredVersionCode(session, activePackage);
+            checkDowngrade(session, activePackage, packageInfo);
+            result.add(packageInfo);
+        }
+        return result;
+    }
+
+    private void checkRequiredVersionCode(final PackageInstallerSession session,
+            final PackageInfo activePackage) throws PackageManagerException {
+        if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) {
+            return;
+        }
+        final long activeVersion = activePackage.applicationInfo.longVersionCode;
+        if (activeVersion != session.params.requiredInstalledVersionCode) {
+            if (!mApexManager.abortActiveSession()) {
+                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+            }
+            throw new PackageManagerException(
+                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    "Installed version of APEX package " + activePackage.packageName
                             + " does not match required. Active version: " + activeVersion
                             + " required: " + session.params.requiredInstalledVersionCode);
-
-                    if (!mApexManager.abortActiveSession()) {
-                        Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
-                    }
-                    return false;
-                }
-            }
-
-            boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
-                    session.params.installFlags, activePackage.applicationInfo.flags);
-            if (activeVersion > newModule.versionCode && !allowsDowngrade) {
-                session.setStagedSessionFailed(
-                        SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                        "Downgrade of APEX package " + activePackage.packageName
-                                + " is not allowed. Active version: " + activeVersion
-                                + " attempted: " + newModule.versionCode);
-
-                if (!mApexManager.abortActiveSession()) {
-                    Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
-                }
-                return false;
-            }
         }
-        return true;
+    }
+
+    private void checkDowngrade(final PackageInstallerSession session,
+            final PackageInfo activePackage, final PackageInfo newPackage)
+            throws PackageManagerException {
+        final long activeVersion = activePackage.applicationInfo.longVersionCode;
+        final long newVersionCode = newPackage.applicationInfo.longVersionCode;
+        boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
+                session.params.installFlags, activePackage.applicationInfo.flags);
+        if (activeVersion > newVersionCode && !allowsDowngrade) {
+            if (!mApexManager.abortActiveSession()) {
+                Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+            }
+            throw new PackageManagerException(
+                    SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+                    "Downgrade of APEX package " + newPackage.packageName
+                            + " is not allowed. Active version: " + activeVersion
+                            + " attempted: " + newVersionCode);
+        }
     }
 
     private static boolean isApexSession(@NonNull PackageInstallerSession session) {
@@ -200,31 +229,20 @@
     }
 
     private void preRebootVerification(@NonNull PackageInstallerSession session) {
-        boolean success = true;
-
-        final ApexInfoList apexInfoList = new ApexInfoList();
+        final boolean hasApex = sessionContainsApex(session);
         // APEX checks. For single-package sessions, check if they contain an APEX. For
         // multi-package sessions, find all the child sessions that contain an APEX.
-        if (!session.isMultiPackage()
-                && isApexSession(session)) {
-            success = submitSessionToApexService(session, null, apexInfoList);
-
-        } else if (session.isMultiPackage()) {
-            List<PackageInstallerSession> childSessions =
-                    Arrays.stream(session.getChildSessionIds())
-                            // Retrieve cached sessions matching ids.
-                            .mapToObj(i -> mStagedSessions.get(i))
-                            // Filter only the ones containing APEX.
-                            .filter(childSession -> isApexSession(childSession))
-                            .collect(Collectors.toList());
-            if (!childSessions.isEmpty()) {
-                success = submitSessionToApexService(session, childSessions, apexInfoList);
-            } // else this is a staged multi-package session with no APEX files.
-        }
-
-        if (!success) {
-            // submitSessionToApexService will populate error.
-            return;
+        if (hasApex) {
+            try {
+                final List<PackageInfo> apexPackages = submitSessionToApexService(session);
+                for (PackageInfo apexPackage : apexPackages) {
+                    validateApexSignature(apexPackage.applicationInfo.sourceDir,
+                            apexPackage.packageName);
+                }
+            } catch (PackageManagerException e) {
+                session.setStagedSessionFailed(e.error, e.getMessage());
+                return;
+            }
         }
 
         if (sessionContainsApk(session)) {
@@ -237,25 +255,6 @@
             }
         }
 
-        if (apexInfoList.apexInfos != null && apexInfoList.apexInfos.length > 0) {
-            // For APEXes, we validate the signature here before we mark the session as ready,
-            // so we fail the session early if there is a signature mismatch. For APKs, the
-            // signature verification will be done by the package manager at the point at which
-            // it applies the staged install.
-            for (ApexInfo apexModule : apexInfoList.apexInfos) {
-                if (!validateApexSignature(apexModule.modulePath,
-                        apexModule.moduleName)) {
-                    session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                            "APK-container signature verification failed for package "
-                                    + apexModule.moduleName + ". Signature of file "
-                                    + apexModule.modulePath + " does not match the signature of "
-                                    + " the package already installed.");
-                    // TODO(b/118865310): abort the session on apexd.
-                    return;
-                }
-            }
-        }
-
         if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
             // If rollback is enabled for this session, we call through to the RollbackManager
             // with the list of sessions it must enable rollback for. Note that notifyStagedSession
@@ -273,12 +272,24 @@
             }
         }
 
+        // Proactively mark session as ready before calling apexd. Although this call order looks
+        // counter-intuitive, this is the easiest way to ensure that session won't end up in the
+        // inconsistent state:
+        //  - If device gets rebooted right before call to apexd, then apexd will never activate
+        //      apex files of this staged session. This will result in StagingManager failing the
+        //      session.
+        // On the other hand, if the order of the calls was inverted (first call apexd, then mark
+        // session as ready), then if a device gets rebooted right after the call to apexd, only
+        // apex part of the train will be applied, leaving device in an inconsistent state.
         session.setStagedSessionReady();
-        if (sessionContainsApex(session)
-                && !mApexManager.markStagedSessionReady(session.sessionId)) {
-            session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
-                            "APEX staging failed, check logcat messages from apexd for more "
-                            + "details.");
+        if (!hasApex) {
+            // Session doesn't contain apex, nothing to do.
+            return;
+        }
+        try {
+            mApexManager.markStagedSessionReady(session.sessionId);
+        } catch (PackageManagerException e) {
+            session.setStagedSessionFailed(e.error, e.getMessage());
         }
     }
 
diff --git a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
index 852f707..cb0b45c 100644
--- a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.telephony.TelephonyManager;
 import android.util.Slog;
 
 /**
@@ -34,6 +35,11 @@
     @Override
     protected void postInstall(Context context, Intent intent) {
         Slog.i(TAG, "Emergency number database is updated in file partition");
-        // TODO Send a notification to EmergencyNumberTracker for updating of emergency number db.
+
+        // Notify EmergencyNumberTracker for emergency number installation complete.
+        Intent notifyInstallComplete = new Intent(
+                TelephonyManager.ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED);
+        context.sendBroadcast(
+                notifyInstallComplete, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
     }
 }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 248baf7..6175d41 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -23,7 +23,6 @@
         "com_android_server_AlarmManagerService.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_connectivity_Vpn.cpp",
-        "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
         "com_android_server_ConsumerIrService.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
@@ -54,6 +53,7 @@
         "com_android_server_am_LowMemDetector.cpp",
         "onload.cpp",
         ":lib_networkStatsFactory_native",
+        ":tethering-jni-srcs",
     ],
 
     include_dirs: [
@@ -136,6 +136,7 @@
         "android.frameworks.sensorservice@1.0",
         "android.system.suspend@1.0",
         "suspend_control_aidl_interface-cpp",
+        "vintf-vibrator-cpp",
     ],
 
     static_libs: [
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 64c7935..51bea1f 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -17,6 +17,9 @@
 #define LOG_TAG "VibratorService"
 
 #include <android/hardware/vibrator/1.4/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -41,11 +44,155 @@
 namespace V1_2 = android::hardware::vibrator::V1_2;
 namespace V1_3 = android::hardware::vibrator::V1_3;
 namespace V1_4 = android::hardware::vibrator::V1_4;
+namespace aidl = android::hardware::vibrator;
 
 namespace android {
 
 static jmethodID sMethodIdOnComplete;
 
+// TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove
+// shim
+class VibratorShim : public V1_4::IVibrator {
+  public:
+    VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {}
+
+    Return<V1_0::Status> on(uint32_t timeoutMs) override {
+        return on_1_4(timeoutMs, nullptr);
+    }
+
+    Return<V1_0::Status> off() override {
+        return toHidlStatus(mVib->off());
+    }
+
+    Return<bool> supportsAmplitudeControl() override {
+        int32_t cap = 0;
+        if (!mVib->getCapabilities(&cap).isOk()) return false;
+        return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
+    }
+
+    Return<V1_0::Status> setAmplitude(uint8_t amplitude) override {
+        return toHidlStatus(mVib->setAmplitude(amplitude));
+    }
+
+    Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength,
+                         perform_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength,
+                             perform_1_1_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength,
+                             perform_1_2_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<bool> supportsExternalControl() override {
+        int32_t cap = 0;
+        if (!mVib->getCapabilities(&cap).isOk()) return false;
+        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
+    }
+
+    Return<V1_0::Status> setExternalControl(bool enabled) override {
+        return toHidlStatus(mVib->setExternalControl(enabled));
+    }
+
+    Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength,
+                             perform_1_3_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<uint32_t> getCapabilities() override {
+        static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) ==
+                      static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK));
+        static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) ==
+                      static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK));
+
+        int32_t cap;
+        if (!mVib->getCapabilities(&cap).isOk()) return 0;
+        return (cap & (aidl::IVibrator::CAP_ON_CALLBACK |
+                       aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0;
+    }
+
+    Return<V1_0::Status> on_1_4(uint32_t timeoutMs,
+                                const sp<V1_4::IVibratorCallback>& callback) override {
+        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
+        return toHidlStatus(mVib->on(timeoutMs, cb));
+    }
+
+    Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength,
+                             const sp<V1_4::IVibratorCallback>& callback,
+                             perform_1_4_cb _hidl_cb) override {
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
+                      static_cast<uint8_t>(aidl::Effect::TICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
+                      static_cast<uint8_t>(aidl::Effect::THUD));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
+                      static_cast<uint8_t>(aidl::Effect::POP));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+                      static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+
+        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
+        int timeoutMs = 0;
+        Return<V1_0::Status> status = toHidlStatus(
+            mVib->perform(static_cast<aidl::Effect>(effect),
+                          static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs));
+
+        if (status.isOk()) {
+            _hidl_cb(status, timeoutMs);
+            return android::hardware::Status::ok();
+        } else {
+            return android::hardware::details::StatusOf<V1_0::Status, void>(status);
+        }
+    }
+  private:
+    sp<aidl::IVibrator> mVib;
+
+    Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) {
+        switch(status.exceptionCode()) {
+            using android::hardware::Status;
+            case Status::EX_NONE: return V1_0::Status::OK;
+            case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE;
+            case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION;
+            case Status::EX_TRANSACTION_FAILED: {
+                return Status::fromStatusT(status.transactionError());
+            }
+        }
+        return V1_0::Status::UNKNOWN_ERROR;
+    }
+
+    class CallbackShim : public aidl::BnVibratorCallback {
+      public:
+        CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {}
+        binder::Status onComplete() {
+            mCb->onComplete();
+            return binder::Status::ok(); // oneway, local call
+        }
+      private:
+        sp<V1_4::IVibratorCallback> mCb;
+    };
+};
+
 class VibratorCallback : public V1_4::IVibratorCallback {
     public:
         VibratorCallback(JNIEnv *env, jobject vibration) :
@@ -79,6 +226,11 @@
 class HalWrapper {
   public:
     static std::unique_ptr<HalWrapper> Create() {
+        sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>();
+        if (aidlVib) {
+            return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib)));
+        }
+
         // Assume that if getService returns a nullptr, HAL is not available on the
         // device.
         auto hal = I::getService();
@@ -103,8 +255,14 @@
             }
 
             ALOGE("Failed to issue command to vibrator HAL. Retrying.");
+
             // Restoring connection to the HAL.
-            mHal = I::tryGetService();
+            sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>();
+            if (aidlVib) {
+                mHal = new VibratorShim(aidlVib);
+            } else {
+                mHal = I::tryGetService();
+            }
         }
         return ret;
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f465855..16c60ca 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -24,6 +24,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityThread;
+import android.app.AppCompatCallbacks;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
@@ -644,6 +645,7 @@
         ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
         ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
                 new PlatformCompatNative(platformCompat));
+        AppCompatCallbacks.install(new long[0]);
         traceEnd();
 
         // Wait for installd to finish starting up so that it has a chance to
diff --git a/services/net/Android.bp b/services/net/Android.bp
index e24dec5..c56ecd6 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -29,6 +29,7 @@
         "java/android/net/ConnectivityModuleConnector.java",
         "java/android/net/NetworkStackClient.java",
         "java/android/net/ip/InterfaceController.java",
+        "java/android/net/netlink/*.java",
         "java/android/net/util/InterfaceParams.java",
         "java/android/net/util/NetdService.java",
         "java/android/net/util/NetworkConstants.java",
diff --git a/services/tests/servicestests/res/raw/apex_test.apex b/services/tests/servicestests/res/raw/apex_test.apex
new file mode 100644
index 0000000..19b1c5e
--- /dev/null
+++ b/services/tests/servicestests/res/raw/apex_test.apex
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
new file mode 100644
index 0000000..6bb4202
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.apex.ApexInfo;
+import android.apex.ApexSessionInfo;
+import android.apex.IApexService;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.servicestests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ApexManagerTest {
+    private static final String TEST_APEX_PKG = "com.android.apex.test";
+    private static final int TEST_SESSION_ID = 99999999;
+    private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
+    private ApexManager mApexManager;
+    private Context mContext;
+
+    private IApexService mApexService = mock(IApexService.class);
+
+    @Before
+    public void setUp() throws RemoteException {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+
+        assertThat(activePkgPi).isNotNull();
+        assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG);
+
+        final PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_FACTORY_PACKAGE);
+
+        assertThat(factoryPkgPi).isNull();
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_FACTORY_PACKAGE);
+
+        assertThat(factoryPkgPi).isNotNull();
+        assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG);
+
+        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+
+        assertThat(activePkgPi).isNull();
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsNone() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
+    }
+
+    @Test
+    public void testGetActivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+
+        assertThat(mApexManager.getActivePackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetActivePackages_noneActivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getActivePackages()).isEmpty();
+    }
+
+    @Test
+    public void testGetFactoryPackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+
+        assertThat(mApexManager.getFactoryPackages()).isEmpty();
+    }
+
+    @Test
+    public void testGetInactivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getInactivePackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+
+        assertThat(mApexManager.getInactivePackages()).isEmpty();
+    }
+
+    @Test
+    public void testIsApexPackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
+    }
+
+    @Test
+    public void testIsApexSupported() {
+        assertThat(mApexManager.isApexSupported()).isTrue();
+    }
+
+    @Test
+    public void testGetStagedSessionInfo() throws RemoteException {
+        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
+                getFakeStagedSessionInfo());
+
+        mApexManager.getStagedSessionInfo(TEST_SESSION_ID);
+        verify(mApexService, times(1)).getStagedSessionInfo(TEST_SESSION_ID);
+    }
+
+    @Test
+    public void testGetStagedSessionInfo_unKnownStagedSessionId() throws RemoteException {
+        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
+                getFakeUnknownSessionInfo());
+
+        assertThat(mApexManager.getStagedSessionInfo(TEST_SESSION_ID)).isNull();
+    }
+
+    @Test
+    public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).submitStagedSession(anyInt(), any(), any());
+
+        assertThrows(PackageManagerException.class,
+                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+    }
+
+    @Test
+    public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(),
+                any());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+    }
+
+    @Test
+    public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).markStagedSessionReady(anyInt());
+
+        assertThrows(PackageManagerException.class,
+                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testAbortActiveSession_remoteException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).abortActiveSession();
+
+        try {
+            assertThat(mApexManager.abortActiveSession()).isFalse();
+        } catch (Exception e) {
+            throw new AssertionError("ApexManager should not raise Exception");
+        }
+    }
+
+    @Test
+    public void testMarkStagedSessionSuccessful_throwRemoteException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).markStagedSessionSuccessful(anyInt());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.markStagedSessionSuccessful(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testUninstallApex_throwException_returnFalse() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).unstagePackages(any());
+
+        assertThat(mApexManager.uninstallApex(TEST_APEX_PKG)).isFalse();
+    }
+
+    private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) {
+        File apexFile = copyRawResourceToFile(TEST_APEX_PKG, R.raw.apex_test);
+        ApexInfo apexInfo = new ApexInfo();
+        apexInfo.isActive = isActive;
+        apexInfo.isFactory = isFactory;
+        apexInfo.moduleName = TEST_APEX_PKG;
+        apexInfo.modulePath = apexFile.getPath();
+        apexInfo.versionCode = 191000070;
+
+        return new ApexInfo[]{apexInfo};
+    }
+
+    private ApexSessionInfo getFakeStagedSessionInfo() {
+        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
+        stagedSessionInfo.sessionId = TEST_SESSION_ID;
+        stagedSessionInfo.isStaged = true;
+
+        return stagedSessionInfo;
+    }
+
+    private ApexSessionInfo getFakeUnknownSessionInfo() {
+        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
+        stagedSessionInfo.sessionId = TEST_SESSION_ID;
+        stagedSessionInfo.isUnknown = true;
+
+        return stagedSessionInfo;
+    }
+
+    /**
+     * Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy
+     * succeeded
+     */
+    File copyRawResourceToFile(String baseName, int resourceId) {
+        File outFile;
+        try {
+            outFile = File.createTempFile(baseName, ".apex");
+        } catch (IOException e) {
+            throw new AssertionError("CreateTempFile IOException" + e);
+        }
+
+        try (InputStream is = mContext.getResources().openRawResource(resourceId);
+             FileOutputStream os = new FileOutputStream(outFile)) {
+            assertThat(FileUtils.copy(is, os)).isGreaterThan(0L);
+        } catch (FileNotFoundException e) {
+            throw new AssertionError("File not found exception " + e);
+        } catch (IOException e) {
+            throw new AssertionError("IOException" + e);
+        }
+
+        return outFile;
+    }
+}
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index c380d29..7cc233b 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -16,7 +16,6 @@
 
 cc_defaults {
     name: "viewcompiler_defaults",
-    defaults: ["libdexfile_static_defaults"],
     header_libs: [
         "libbase_headers",
     ],
@@ -30,6 +29,7 @@
         "liblog",
         "libutils",
         "libziparchive",
+        "libz",
     ],
     cppflags: ["-std=c++17"],
     target: {
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 48b44d0..50cf5a5 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -16,8 +16,6 @@
 
 #include "dex_builder.h"
 
-#include "dex/descriptors_names.h"
-
 #include <fstream>
 #include <memory>
 
@@ -30,8 +28,6 @@
 using ::dex::kAccPublic;
 using Op = Instruction::Op;
 
-using Opcode = ::art::Instruction::Code;
-
 const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
 const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
 
@@ -43,22 +39,31 @@
 constexpr size_t kMaxEncodedStringLength{5};
 
 // Converts invoke-* to invoke-*/range
-constexpr Opcode InvokeToInvokeRange(Opcode opcode) {
+constexpr ::dex::Opcode InvokeToInvokeRange(::dex::Opcode opcode) {
   switch (opcode) {
-    case ::art::Instruction::INVOKE_VIRTUAL:
-      return ::art::Instruction::INVOKE_VIRTUAL_RANGE;
-    case ::art::Instruction::INVOKE_DIRECT:
-      return ::art::Instruction::INVOKE_DIRECT_RANGE;
-    case ::art::Instruction::INVOKE_STATIC:
-      return ::art::Instruction::INVOKE_STATIC_RANGE;
-    case ::art::Instruction::INVOKE_INTERFACE:
-      return ::art::Instruction::INVOKE_INTERFACE_RANGE;
+    case ::dex::Opcode::OP_INVOKE_VIRTUAL:
+      return ::dex::Opcode::OP_INVOKE_VIRTUAL_RANGE;
+    case ::dex::Opcode::OP_INVOKE_DIRECT:
+      return ::dex::Opcode::OP_INVOKE_DIRECT_RANGE;
+    case ::dex::Opcode::OP_INVOKE_STATIC:
+      return ::dex::Opcode::OP_INVOKE_STATIC_RANGE;
+    case ::dex::Opcode::OP_INVOKE_INTERFACE:
+      return ::dex::Opcode::OP_INVOKE_INTERFACE_RANGE;
     default:
       LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
-      UNREACHABLE();
+      __builtin_unreachable();
   }
 }
 
+std::string DotToDescriptor(const char* class_name) {
+  std::string descriptor(class_name);
+  std::replace(descriptor.begin(), descriptor.end(), '.', '/');
+  if (descriptor.length() > 0 && descriptor[0] != '[') {
+    descriptor = "L" + descriptor + ";";
+  }
+  return descriptor;
+}
+
 }  // namespace
 
 std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
@@ -178,7 +183,7 @@
 }
 
 TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
-  return TypeDescriptor{art::DotToDescriptor(name.c_str())};
+  return TypeDescriptor{DotToDescriptor(name.c_str())};
 }
 
 DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
@@ -219,11 +224,11 @@
 
 ClassBuilder DexBuilder::MakeClass(const std::string& name) {
   auto* class_def = Alloc<ir::Class>();
-  ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
+  ir::Type* type_def = GetOrAddType(DotToDescriptor(name.c_str()));
   type_def->class_def = class_def;
 
   class_def->type = type_def;
-  class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
+  class_def->super_class = GetOrAddType(DotToDescriptor("java.lang.Object"));
   class_def->access_flags = kAccPublic;
   return ClassBuilder{this, name, class_def};
 }
@@ -378,26 +383,26 @@
 void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
   switch (instruction.opcode()) {
     case Instruction::Op::kReturn:
-      return EncodeReturn(instruction, ::art::Instruction::RETURN);
+      return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN);
     case Instruction::Op::kReturnObject:
-      return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
+      return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN_OBJECT);
     case Instruction::Op::kMove:
     case Instruction::Op::kMoveObject:
       return EncodeMove(instruction);
     case Instruction::Op::kInvokeVirtual:
-      return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
+      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_VIRTUAL);
     case Instruction::Op::kInvokeDirect:
-      return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
+      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_DIRECT);
     case Instruction::Op::kInvokeStatic:
-      return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
+      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_STATIC);
     case Instruction::Op::kInvokeInterface:
-      return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
+      return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_INTERFACE);
     case Instruction::Op::kBindLabel:
       return BindLabel(instruction.args()[0]);
     case Instruction::Op::kBranchEqz:
-      return EncodeBranch(art::Instruction::IF_EQZ, instruction);
+      return EncodeBranch(::dex::Opcode::OP_IF_EQZ, instruction);
     case Instruction::Op::kBranchNEqz:
-      return EncodeBranch(art::Instruction::IF_NEZ, instruction);
+      return EncodeBranch(::dex::Opcode::OP_IF_NEZ, instruction);
     case Instruction::Op::kNew:
       return EncodeNew(instruction);
     case Instruction::Op::kCheckCast:
@@ -410,10 +415,10 @@
   }
 }
 
-void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
+void MethodBuilder::EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode) {
   CHECK(!instruction.dest().has_value());
   if (instruction.args().size() == 0) {
-    Encode10x(art::Instruction::RETURN_VOID);
+    Encode10x(::dex::Opcode::OP_RETURN_VOID);
   } else {
     CHECK_EQ(1, instruction.args().size());
     size_t source = RegisterValue(instruction.args()[0]);
@@ -433,27 +438,27 @@
   if (source.is_immediate()) {
     // TODO: support more registers
     CHECK_LT(RegisterValue(*instruction.dest()), 16);
-    Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
+    Encode11n(::dex::Opcode::OP_CONST_4, RegisterValue(*instruction.dest()), source.value());
   } else if (source.is_string()) {
     constexpr size_t kMaxRegisters = 256;
     CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
     CHECK_LT(source.value(), 65536);  // make sure we don't need a jumbo string
-    Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
+    Encode21c(::dex::Opcode::OP_CONST_STRING, RegisterValue(*instruction.dest()), source.value());
   } else if (source.is_variable()) {
     // For the moment, we only use this when we need to reshuffle registers for
     // an invoke instruction, meaning we are too big for the 4-bit version.
     // We'll err on the side of caution and always generate the 16-bit form of
     // the instruction.
-    Opcode opcode = instruction.opcode() == Instruction::Op::kMove
-                        ? ::art::Instruction::MOVE_16
-                        : ::art::Instruction::MOVE_OBJECT_16;
+    auto opcode = instruction.opcode() == Instruction::Op::kMove
+                        ? ::dex::Opcode::OP_MOVE_16
+                        : ::dex::Opcode::OP_MOVE_OBJECT_16;
     Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
   } else {
     UNIMPLEMENTED(FATAL);
   }
 }
 
-void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
+void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode) {
   constexpr size_t kMaxArgs = 5;
 
   // Currently, we only support up to 5 arguments.
@@ -480,8 +485,8 @@
 
     for (size_t i = 0; i < instruction.args().size(); ++i) {
       Instruction::Op move_op;
-      if (opcode == ::art::Instruction::INVOKE_VIRTUAL ||
-          opcode == ::art::Instruction::INVOKE_DIRECT) {
+      if (opcode == ::dex::Opcode::OP_INVOKE_VIRTUAL ||
+          opcode == ::dex::Opcode::OP_INVOKE_DIRECT) {
         // In this case, there is an implicit `this` argument, which is always an object.
         if (i == 0) {
           move_op = Instruction::Op::kMoveObject;
@@ -514,8 +519,8 @@
 
   // If there is a return value, add a move-result instruction
   if (instruction.dest().has_value()) {
-    Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
-                                             : art::Instruction::MOVE_RESULT,
+    Encode11x(instruction.result_is_object() ? ::dex::Opcode::OP_MOVE_RESULT_OBJECT
+                                             : ::dex::Opcode::OP_MOVE_RESULT,
               RegisterValue(*instruction.dest()));
   }
 
@@ -523,7 +528,7 @@
 }
 
 // Encodes a conditional branch that tests a single argument.
-void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) {
+void MethodBuilder::EncodeBranch(::dex::Opcode op, const Instruction& instruction) {
   const auto& args = instruction.args();
   const auto& test_value = args[0];
   const auto& branch_target = args[1];
@@ -546,7 +551,7 @@
   const Value& type = instruction.args()[0];
   CHECK_LT(RegisterValue(*instruction.dest()), 256);
   CHECK(type.is_type());
-  Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
+  Encode21c(::dex::Opcode::OP_NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
 }
 
 void MethodBuilder::EncodeCast(const Instruction& instruction) {
@@ -558,7 +563,7 @@
   const Value& type = instruction.args()[0];
   CHECK_LT(RegisterValue(*instruction.dest()), 256);
   CHECK(type.is_type());
-  Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
+  Encode21c(::dex::Opcode::OP_CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
 }
 
 void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
@@ -569,7 +574,7 @@
       CHECK(instruction.dest()->is_variable());
       CHECK_EQ(0, instruction.args().size());
 
-      Encode21c(::art::Instruction::SGET,
+      Encode21c(::dex::Opcode::OP_SGET,
                 RegisterValue(*instruction.dest()),
                 instruction.index_argument());
       break;
@@ -579,7 +584,7 @@
       CHECK_EQ(1, args.size());
       CHECK(args[0].is_variable());
 
-      Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument());
+      Encode21c(::dex::Opcode::OP_SPUT, RegisterValue(args[0]), instruction.index_argument());
       break;
     }
     case Instruction::Op::kGetInstanceField: {
@@ -587,7 +592,7 @@
       CHECK(instruction.dest()->is_variable());
       CHECK_EQ(1, instruction.args().size());
 
-      Encode22c(::art::Instruction::IGET,
+      Encode22c(::dex::Opcode::OP_IGET,
                 RegisterValue(*instruction.dest()),
                 RegisterValue(args[0]),
                 instruction.index_argument());
@@ -599,7 +604,7 @@
       CHECK(args[0].is_variable());
       CHECK(args[1].is_variable());
 
-      Encode22c(::art::Instruction::IPUT,
+      Encode22c(::dex::Opcode::OP_IPUT,
                 RegisterValue(args[1]),
                 RegisterValue(args[0]),
                 instruction.index_argument());
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 3924e77..eb2dc88 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -24,7 +24,9 @@
 #include <unordered_map>
 #include <vector>
 
-#include "dex/dex_instruction.h"
+#include "android-base/logging.h"
+
+#include "slicer/dex_bytecode.h"
 #include "slicer/dex_ir.h"
 #include "slicer/writer.h"
 
@@ -364,11 +366,11 @@
   // Encodes a return instruction. For instructions with no return value, the opcode field is
   // ignored. Otherwise, this specifies which return instruction will be used (return,
   // return-object, etc.)
-  void EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode);
+  void EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode);
 
   void EncodeMove(const Instruction& instruction);
-  void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode);
-  void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
+  void EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode);
+  void EncodeBranch(::dex::Opcode op, const Instruction& instruction);
   void EncodeNew(const Instruction& instruction);
   void EncodeCast(const Instruction& instruction);
   void EncodeFieldOp(const Instruction& instruction);
@@ -377,17 +379,23 @@
   // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
   // formats.
 
-  inline void Encode10x(art::Instruction::Code opcode) {
+  inline uint8_t ToBits(::dex::Opcode opcode) {
+    static_assert(sizeof(uint8_t) == sizeof(::dex::Opcode));
+    return static_cast<uint8_t>(opcode);
+  }
+
+  inline void Encode10x(::dex::Opcode opcode) {
     // 00|op
-    buffer_.push_back(opcode);
+    static_assert(sizeof(uint8_t) == sizeof(::dex::Opcode));
+    buffer_.push_back(ToBits(opcode));
   }
 
-  inline void Encode11x(art::Instruction::Code opcode, uint8_t a) {
+  inline void Encode11x(::dex::Opcode opcode, uint8_t a) {
     // aa|op
-    buffer_.push_back((a << 8) | opcode);
+    buffer_.push_back((a << 8) | ToBits(opcode));
   }
 
-  inline void Encode11n(art::Instruction::Code opcode, uint8_t a, int8_t b) {
+  inline void Encode11n(::dex::Opcode opcode, uint8_t a, int8_t b) {
     // b|a|op
 
     // Make sure the fields are in bounds (4 bits for a, 4 bits for b).
@@ -395,30 +403,30 @@
     CHECK_LE(-8, b);
     CHECK_LT(b, 8);
 
-    buffer_.push_back(((b & 0xf) << 12) | (a << 8) | opcode);
+    buffer_.push_back(((b & 0xf) << 12) | (a << 8) | ToBits(opcode));
   }
 
-  inline void Encode21c(art::Instruction::Code opcode, uint8_t a, uint16_t b) {
+  inline void Encode21c(::dex::Opcode opcode, uint8_t a, uint16_t b) {
     // aa|op|bbbb
-    buffer_.push_back((a << 8) | opcode);
+    buffer_.push_back((a << 8) | ToBits(opcode));
     buffer_.push_back(b);
   }
 
-  inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) {
+  inline void Encode22c(::dex::Opcode opcode, uint8_t a, uint8_t b, uint16_t c) {
     // b|a|op|bbbb
     CHECK(IsShortRegister(a));
     CHECK(IsShortRegister(b));
-    buffer_.push_back((b << 12) | (a << 8) | opcode);
+    buffer_.push_back((b << 12) | (a << 8) | ToBits(opcode));
     buffer_.push_back(c);
   }
 
-  inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
-    buffer_.push_back(opcode);
+  inline void Encode32x(::dex::Opcode opcode, uint16_t a, uint16_t b) {
+    buffer_.push_back(ToBits(opcode));
     buffer_.push_back(a);
     buffer_.push_back(b);
   }
 
-  inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
+  inline void Encode35c(::dex::Opcode opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
                         uint8_t e, uint8_t f, uint8_t g) {
     // a|g|op|bbbb|f|e|d|c
 
@@ -428,14 +436,14 @@
     CHECK(IsShortRegister(e));
     CHECK(IsShortRegister(f));
     CHECK(IsShortRegister(g));
-    buffer_.push_back((a << 12) | (g << 8) | opcode);
+    buffer_.push_back((a << 12) | (g << 8) | ToBits(opcode));
     buffer_.push_back(b);
     buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c);
   }
 
-  inline void Encode3rc(art::Instruction::Code opcode, size_t a, uint16_t b, uint16_t c) {
+  inline void Encode3rc(::dex::Opcode opcode, size_t a, uint16_t b, uint16_t c) {
     CHECK_LE(a, 255);
-    buffer_.push_back((a << 8) | opcode);
+    buffer_.push_back((a << 8) | ToBits(opcode));
     buffer_.push_back(b);
     buffer_.push_back(c);
   }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 12066c4..2bc20d5 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.telephony.Annotation.CallState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -1412,7 +1413,7 @@
      * @hide
      */
     @SystemApi
-    public @TelephonyManager.CallState int getCallState() {
+    public @CallState int getCallState() {
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCallState();
diff --git a/telephony/common/com/android/internal/telephony/HbpcdLookup.java b/telephony/common/com/android/internal/telephony/HbpcdLookup.java
new file mode 100644
index 0000000..d9a3e72
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/HbpcdLookup.java
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package com.android.internal.telephony;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * @hide
+ */
+public class HbpcdLookup {
+    public static final String AUTHORITY = "hbpcd_lookup";
+
+    public static final Uri CONTENT_URI =
+        Uri.parse("content://" + AUTHORITY);
+
+    public static final String PATH_MCC_IDD = "idd";
+    public static final String PATH_MCC_LOOKUP_TABLE = "lookup";
+    public static final String PATH_MCC_SID_CONFLICT = "conflict";
+    public static final String PATH_MCC_SID_RANGE = "range";
+    public static final String PATH_NANP_AREA_CODE = "nanp";
+    public static final String PATH_ARBITRARY_MCC_SID_MATCH = "arbitrary";
+    public static final String PATH_USERADD_COUNTRY = "useradd";
+
+    public static final String ID = "_id";
+    public static final int IDINDEX = 0;
+
+    /**
+     * @hide
+     */
+    public static class MccIdd implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_IDD);
+        public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+        public static final String MCC = "MCC";
+        public static final String IDD = "IDD";
+
+    }
+
+    /**
+     * @hide
+     */
+    public static class MccLookup implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_LOOKUP_TABLE);
+        public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+        public static final String MCC = "MCC";
+        public static final String COUNTRY_CODE = "Country_Code";
+        public static final String COUNTRY_NAME = "Country_Name";
+        public static final String NDD = "NDD";
+        public static final String NANPS = "NANPS";
+        public static final String GMT_OFFSET_LOW = "GMT_Offset_Low";
+        public static final String GMT_OFFSET_HIGH = "GMT_Offset_High";
+        public static final String GMT_DST_LOW = "GMT_DST_Low";
+        public static final String GMT_DST_HIGH = "GMT_DST_High";
+
+    }
+
+    /**
+     * @hide
+     */
+    public static class MccSidConflicts implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_SID_CONFLICT);
+        public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+        public static final String MCC = "MCC";
+        public static final String SID_CONFLICT = "SID_Conflict";
+
+    }
+
+    /**
+     * @hide
+     */
+    public static class MccSidRange implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_MCC_SID_RANGE);
+        public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+        public static final String MCC = "MCC";
+        public static final String RANGE_LOW = "SID_Range_Low";
+        public static final String RANGE_HIGH = "SID_Range_High";
+    }
+
+    /**
+     * @hide
+     */
+    public static class ArbitraryMccSidMatch implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_ARBITRARY_MCC_SID_MATCH);
+        public static final String DEFAULT_SORT_ORDER = "MCC ASC";
+
+        public static final String MCC = "MCC";
+        public static final String SID = "SID";
+
+    }
+
+    /**
+     * @hide
+     */
+    public static class NanpAreaCode implements BaseColumns {
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://" + AUTHORITY + "/" + PATH_NANP_AREA_CODE);
+        public static final String DEFAULT_SORT_ORDER = "Area_Code ASC";
+
+        public static final String AREA_CODE = "Area_Code";
+    }
+}
diff --git a/telephony/common/com/android/internal/telephony/HbpcdUtils.java b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
new file mode 100644
index 0000000..2f31942
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/HbpcdUtils.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.telephony.Rlog;
+
+import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
+import com.android.internal.telephony.HbpcdLookup.MccIdd;
+import com.android.internal.telephony.HbpcdLookup.MccLookup;
+import com.android.internal.telephony.HbpcdLookup.MccSidConflicts;
+import com.android.internal.telephony.HbpcdLookup.MccSidRange;
+
+public final class HbpcdUtils {
+    private static final String LOG_TAG = "HbpcdUtils";
+    private static final boolean DBG = false;
+    private ContentResolver resolver = null;
+
+    public HbpcdUtils(Context context) {
+        resolver = context.getContentResolver();
+    }
+
+    /**
+     *  Resolves the unknown MCC with SID and Timezone information.
+    */
+    public int getMcc(int sid, int tz, int DSTflag, boolean isNitzTimeZone) {
+        int tmpMcc = 0;
+
+        // check if SID exists in arbitrary_mcc_sid_match table.
+        // these SIDs are assigned to more than 1 operators, but they are known to
+        // be used by a specific operator, other operators having the same SID are
+        // not using it currently, if that SID is in this table, we don't need to
+        // check other tables.
+        String projection2[] = {ArbitraryMccSidMatch.MCC};
+        Cursor c2 = resolver.query(ArbitraryMccSidMatch.CONTENT_URI, projection2,
+                            ArbitraryMccSidMatch.SID + "=" + sid, null, null);
+
+        if (c2 != null) {
+            int c2Counter = c2.getCount();
+            if (DBG) {
+                Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
+            }
+            if (c2Counter == 1) {
+                if (DBG) {
+                    Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
+                }
+                c2.moveToFirst();
+                tmpMcc = c2.getInt(0);
+                if (DBG) {
+                    Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
+                }
+                c2.close();
+                return tmpMcc;
+            }
+            c2.close();
+        }
+
+        // Then check if SID exists in mcc_sid_conflict table.
+        // and use the timezone in mcc_lookup table to check which MCC matches.
+        String projection3[] = {MccSidConflicts.MCC};
+        Cursor c3 = resolver.query(MccSidConflicts.CONTENT_URI, projection3,
+                MccSidConflicts.SID_CONFLICT + "=" + sid + " and (((" +
+                MccLookup.GMT_OFFSET_LOW + "<=" + tz + ") and (" + tz + "<=" +
+                MccLookup.GMT_OFFSET_HIGH + ") and (" + "0=" + DSTflag + ")) or ((" +
+                MccLookup.GMT_DST_LOW + "<=" + tz + ") and (" + tz + "<=" +
+                MccLookup.GMT_DST_HIGH + ") and (" + "1=" + DSTflag + ")))",
+                        null, null);
+        if (c3 != null) {
+            int c3Counter = c3.getCount();
+            if (c3Counter > 0) {
+                if (c3Counter > 1) {
+                    Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
+                }
+                if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
+                c3.moveToFirst();
+                tmpMcc = c3.getInt(0);
+                if (DBG) {
+                    Rlog.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
+                }
+                if (!isNitzTimeZone) {
+                    // time zone is not accurate, it may get wrong mcc, ignore it.
+                    if (DBG) {
+                        Rlog.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc);
+                    }
+                    tmpMcc = 0;
+                }
+                c3.close();
+                return tmpMcc;
+            } else {
+                c3.close();
+            }
+        }
+
+        // if there is no conflict, then check if SID is in mcc_sid_range.
+        String projection5[] = {MccSidRange.MCC};
+        Cursor c5 = resolver.query(MccSidRange.CONTENT_URI, projection5,
+                MccSidRange.RANGE_LOW + "<=" + sid + " and " +
+                MccSidRange.RANGE_HIGH + ">=" + sid,
+                null, null);
+        if (c5 != null) {
+            if (c5.getCount() > 0) {
+                if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5);
+                c5.moveToFirst();
+                tmpMcc = c5.getInt(0);
+                if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
+                c5.close();
+                return tmpMcc;
+            }
+            c5.close();
+        }
+        if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
+
+        if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc =  " + tmpMcc);
+        // If unknown MCC still could not be resolved,
+        return tmpMcc;
+    }
+
+    /**
+     *  Gets country information with given MCC.
+    */
+    public String getIddByMcc(int mcc) {
+        if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
+        String idd = "";
+
+        Cursor c = null;
+
+        String projection[] = {MccIdd.IDD};
+        Cursor cur = resolver.query(MccIdd.CONTENT_URI, projection,
+                MccIdd.MCC + "=" + mcc, null, null);
+        if (cur != null) {
+            if (cur.getCount() > 0) {
+                if (DBG) Rlog.d(LOG_TAG, "Query Idd returned the cursor " + cur);
+                // TODO: for those country having more than 1 IDDs, need more information
+                // to decide which IDD would be used. currently just use the first 1.
+                cur.moveToFirst();
+                idd = cur.getString(0);
+                if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd);
+
+            }
+            cur.close();
+        }
+        if (c != null) c.close();
+
+        if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
+        return idd;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
similarity index 99%
rename from telephony/java/com/android/internal/telephony/SmsApplication.java
rename to telephony/common/com/android/internal/telephony/SmsApplication.java
index f17a1a5..5dcc751 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -40,7 +40,6 @@
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.Rlog;
-import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
@@ -1037,9 +1036,6 @@
      * Caller must pass in the correct user context if calling from a singleton service.
      */
     public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
-        if (SmsManager.getDefault().getAutoPersisting()) {
-            return true;
-        }
         return !isDefaultSmsApplication(context, packageName);
     }
 
diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
new file mode 100644
index 0000000..0d33af6
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telephony.HbpcdLookup.MccIdd;
+import com.android.internal.telephony.HbpcdLookup.MccLookup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+/**
+ * This class implements handle the MO SMS target address before sending.
+ * This is special for VZW requirement. Follow the specifications of assisted dialing
+ * of MO SMS while traveling on VZW CDMA, international CDMA or GSM markets.
+ * {@hide}
+ */
+public class SmsNumberUtils {
+    private static final String TAG = "SmsNumberUtils";
+    private static final boolean DBG = Build.IS_DEBUGGABLE;
+
+    private static final String PLUS_SIGN = "+";
+
+    private static final int NANP_SHORT_LENGTH = 7;
+    private static final int NANP_MEDIUM_LENGTH = 10;
+    private static final int NANP_LONG_LENGTH = 11;
+
+    private static final int NANP_CC = 1;
+    private static final String NANP_NDD = "1";
+    private static final String NANP_IDD = "011";
+
+    private static final int MIN_COUNTRY_AREA_LOCAL_LENGTH = 10;
+
+    private static final int GSM_UMTS_NETWORK = 0;
+    private static final int CDMA_HOME_NETWORK = 1;
+    private static final int CDMA_ROAMING_NETWORK = 2;
+
+    private static final int NP_NONE = 0;
+    private static final int NP_NANP_BEGIN = 1;
+
+    /* <Phone Number>, <NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_LOCAL = NP_NANP_BEGIN;
+
+    /* <Area_code>-<Phone Number>, <NXX>-<NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_AREA_LOCAL = NP_NANP_BEGIN + 1;
+
+    /* <1>-<Area_code>-<Phone Number>, 1-<NXX>-<NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_NDD_AREA_LOCAL = NP_NANP_BEGIN + 2;
+
+    /* <+><U.S.Country_code><Area_code><Phone Number>, +1-<NXX>-<NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_NBPCD_CC_AREA_LOCAL = NP_NANP_BEGIN + 3;
+
+    /* <Local_IDD><Country_code><Area_code><Phone Number>, 001-1-<NXX>-<NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_LOCALIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 4;
+
+    /* <+><Home_IDD><Country_code><Area_code><Phone Number>, +011-1-<NXX>-<NXX>-<XXXX> N[2-9] */
+    private static final int NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_NANP_BEGIN + 5;
+
+    private static final int NP_INTERNATIONAL_BEGIN = 100;
+    /* <+>-<Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, +011-86-25-86281234 */
+    private static final int NP_NBPCD_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN;
+
+    /* <Home_IDD>-<Country_code>-<Area_code>-<Phone Number>, 011-86-25-86281234 */
+    private static final int NP_HOMEIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 1;
+
+    /* <NBPCD>-<Country_code>-<Area_code>-<Phone Number>, +1-86-25-86281234 */
+    private static final int NP_NBPCD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 2;
+
+    /* <Local_IDD>-<Country_code>-<Area_code>-<Phone Number>, 00-86-25-86281234 */
+    private static final int NP_LOCALIDD_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 3;
+
+    /* <Country_code>-<Area_code>-<Phone Number>, 86-25-86281234*/
+    private static final int NP_CC_AREA_LOCAL = NP_INTERNATIONAL_BEGIN + 4;
+
+    private static int[] ALL_COUNTRY_CODES = null;
+    private static int MAX_COUNTRY_CODES_LENGTH;
+    private static HashMap<String, ArrayList<String>> IDDS_MAPS =
+            new HashMap<String, ArrayList<String>>();
+
+    private static class NumberEntry {
+        public String number;
+        public String IDD;
+        public int countryCode;
+        public NumberEntry(String number) {
+            this.number = number;
+        }
+    }
+
+    /**
+     * Breaks the given number down and formats it according to the rules
+     * for different number plans and different network.
+     *
+     * @param number destination number which need to be format
+     * @param activeMcc current network's mcc
+     * @param networkType current network type
+     *
+     * @return the number after formatting.
+     */
+    private static String formatNumber(Context context, String number,
+                               String activeMcc,
+                               int networkType) {
+        if (number == null ) {
+            throw new IllegalArgumentException("number is null");
+        }
+
+        if (activeMcc == null || activeMcc.trim().length() == 0) {
+            throw new IllegalArgumentException("activeMcc is null or empty!");
+        }
+
+        String networkPortionNumber = PhoneNumberUtils.extractNetworkPortion(number);
+        if (networkPortionNumber == null || networkPortionNumber.length() == 0) {
+            throw new IllegalArgumentException("Number is invalid!");
+        }
+
+        NumberEntry numberEntry = new NumberEntry(networkPortionNumber);
+        ArrayList<String> allIDDs = getAllIDDs(context, activeMcc);
+
+        // First check whether the number is a NANP number.
+        int nanpState = checkNANP(numberEntry, allIDDs);
+        if (DBG) Rlog.d(TAG, "NANP type: " + getNumberPlanType(nanpState));
+
+        if ((nanpState == NP_NANP_LOCAL)
+            || (nanpState == NP_NANP_AREA_LOCAL)
+            || (nanpState == NP_NANP_NDD_AREA_LOCAL)) {
+            return networkPortionNumber;
+        } else if (nanpState == NP_NANP_NBPCD_CC_AREA_LOCAL) {
+            if (networkType == CDMA_HOME_NETWORK
+                    || networkType == CDMA_ROAMING_NETWORK) {
+                // Remove "+"
+                return networkPortionNumber.substring(1);
+            } else {
+                return networkPortionNumber;
+            }
+        } else if (nanpState == NP_NANP_LOCALIDD_CC_AREA_LOCAL) {
+            if (networkType == CDMA_HOME_NETWORK) {
+                return networkPortionNumber;
+            } else if (networkType == GSM_UMTS_NETWORK) {
+                // Remove the local IDD and replace with "+"
+                int iddLength  =  numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+                return PLUS_SIGN + networkPortionNumber.substring(iddLength);
+            } else if (networkType == CDMA_ROAMING_NETWORK) {
+                // Remove the local IDD
+                int iddLength  =  numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+                return  networkPortionNumber.substring(iddLength);
+            }
+        }
+
+        int internationalState = checkInternationalNumberPlan(context, numberEntry, allIDDs,
+                NANP_IDD);
+        if (DBG) Rlog.d(TAG, "International type: " + getNumberPlanType(internationalState));
+        String returnNumber = null;
+
+        switch (internationalState) {
+            case NP_NBPCD_HOMEIDD_CC_AREA_LOCAL:
+                if (networkType == GSM_UMTS_NETWORK) {
+                    // Remove "+"
+                    returnNumber = networkPortionNumber.substring(1);
+                }
+                break;
+
+            case NP_NBPCD_CC_AREA_LOCAL:
+                // Replace "+" with "011"
+                returnNumber = NANP_IDD + networkPortionNumber.substring(1);
+                break;
+
+            case NP_LOCALIDD_CC_AREA_LOCAL:
+                if (networkType == GSM_UMTS_NETWORK || networkType == CDMA_ROAMING_NETWORK) {
+                    int iddLength  =  numberEntry.IDD != null ? numberEntry.IDD.length() : 0;
+                    // Replace <Local IDD> to <Home IDD>("011")
+                    returnNumber = NANP_IDD + networkPortionNumber.substring(iddLength);
+                }
+                break;
+
+            case NP_CC_AREA_LOCAL:
+                int countryCode = numberEntry.countryCode;
+
+                if (!inExceptionListForNpCcAreaLocal(numberEntry)
+                    && networkPortionNumber.length() >= 11 && countryCode != NANP_CC) {
+                    // Add "011"
+                    returnNumber = NANP_IDD + networkPortionNumber;
+                }
+                break;
+
+            case NP_HOMEIDD_CC_AREA_LOCAL:
+                returnNumber = networkPortionNumber;
+                break;
+
+            default:
+                // Replace "+" with 011 in CDMA network if the number's country
+                // code is not in the HbpcdLookup database.
+                if (networkPortionNumber.startsWith(PLUS_SIGN)
+                    && (networkType == CDMA_HOME_NETWORK || networkType == CDMA_ROAMING_NETWORK)) {
+                    if (networkPortionNumber.startsWith(PLUS_SIGN + NANP_IDD)) {
+                        // Only remove "+"
+                        returnNumber = networkPortionNumber.substring(1);
+                    } else {
+                        // Replace "+" with "011"
+                        returnNumber = NANP_IDD + networkPortionNumber.substring(1);
+                    }
+                }
+        }
+
+        if (returnNumber == null) {
+            returnNumber = networkPortionNumber;
+        }
+        return returnNumber;
+    }
+
+    /**
+     * Query International direct dialing from HbpcdLookup.db
+     * for specified country code
+     *
+     * @param mcc current network's country code
+     *
+     * @return the IDD array list.
+     */
+    private static ArrayList<String> getAllIDDs(Context context, String mcc) {
+        ArrayList<String> allIDDs = IDDS_MAPS.get(mcc);
+        if (allIDDs != null) {
+            return allIDDs;
+        } else {
+            allIDDs = new ArrayList<String>();
+        }
+
+        String projection[] = {MccIdd.IDD, MccIdd.MCC};
+        String where = null;
+
+        // if mcc is null         : return all rows
+        // if mcc is empty-string : return those rows whose mcc is emptry-string
+        String[] selectionArgs = null;
+        if (mcc != null) {
+            where = MccIdd.MCC + "=?";
+            selectionArgs = new String[] {mcc};
+        }
+
+        Cursor cursor = null;
+        try {
+            cursor = context.getContentResolver().query(MccIdd.CONTENT_URI, projection,
+                    where, selectionArgs, null);
+            if (cursor.getCount() > 0) {
+                while (cursor.moveToNext()) {
+                    String idd = cursor.getString(0);
+                    if (!allIDDs.contains(idd)) {
+                        allIDDs.add(idd);
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+
+        IDDS_MAPS.put(mcc, allIDDs);
+
+        if (DBG) Rlog.d(TAG, "MCC = " + mcc + ", all IDDs = " + allIDDs);
+        return allIDDs;
+    }
+
+
+    /**
+     * Verify if the the destination number is a NANP number
+     *
+     * @param numberEntry including number and IDD array
+     * @param allIDDs the IDD array list of the current network's country code
+     *
+     * @return the number plan type related NANP
+     */
+    private static int checkNANP(NumberEntry numberEntry, ArrayList<String> allIDDs) {
+        boolean isNANP = false;
+        String number = numberEntry.number;
+
+        if (number.length() == NANP_SHORT_LENGTH) {
+            // 7 digits - Seven digit phone numbers
+            char firstChar = number.charAt(0);
+            if (firstChar >= '2' && firstChar <= '9') {
+                isNANP = true;
+                for (int i=1; i< NANP_SHORT_LENGTH; i++ ) {
+                    char c= number.charAt(i);
+                    if (!PhoneNumberUtils.isISODigit(c)) {
+                        isNANP = false;
+                        break;
+                    }
+                }
+            }
+            if (isNANP) {
+                return NP_NANP_LOCAL;
+            }
+        } else if (number.length() == NANP_MEDIUM_LENGTH) {
+            // 10 digits - Three digit area code followed by seven digit phone numbers/
+            if (isNANP(number)) {
+                return NP_NANP_AREA_LOCAL;
+            }
+        } else if (number.length() == NANP_LONG_LENGTH) {
+            // 11 digits - One digit U.S. NDD(National Direct Dial) prefix '1',
+            // followed by three digit area code and seven digit phone numbers
+            if (isNANP(number)) {
+                return NP_NANP_NDD_AREA_LOCAL;
+            }
+        } else if (number.startsWith(PLUS_SIGN)) {
+            number = number.substring(1);
+            if (number.length() == NANP_LONG_LENGTH) {
+                // '+' and 11 digits -'+', followed by NANP CC prefix '1' followed by
+                // three digit area code and seven digit phone numbers
+                if (isNANP(number)) {
+                    return NP_NANP_NBPCD_CC_AREA_LOCAL;
+                }
+            } else if (number.startsWith(NANP_IDD) && number.length() == NANP_LONG_LENGTH + 3) {
+                // '+' and 14 digits -'+', followed by NANP IDD "011" followed by NANP CC
+                // prefix '1' followed by three digit area code and seven digit phone numbers
+                number = number.substring(3);
+                if (isNANP(number)) {
+                    return NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL;
+                }
+            }
+        } else {
+            // Check whether it's NP_NANP_LOCALIDD_CC_AREA_LOCAL
+            for (String idd : allIDDs) {
+                if (number.startsWith(idd)) {
+                    String number2 = number.substring(idd.length());
+                    if(number2 !=null && number2.startsWith(String.valueOf(NANP_CC))){
+                        if (isNANP(number2)) {
+                            numberEntry.IDD = idd;
+                            return NP_NANP_LOCALIDD_CC_AREA_LOCAL;
+                        }
+                    }
+                }
+            }
+        }
+
+        return NP_NONE;
+    }
+
+    private static boolean isNANP(String number) {
+        if (number.length() == NANP_MEDIUM_LENGTH
+            || (number.length() == NANP_LONG_LENGTH  && number.startsWith(NANP_NDD))) {
+            if (number.length() == NANP_LONG_LENGTH) {
+                number = number.substring(1);
+            }
+            return (PhoneNumberUtils.isNanp(number));
+        }
+        return false;
+    }
+
+    /**
+     * Verify if the the destination number is an internal number
+     *
+     * @param numberEntry including number and IDD array
+     * @param allIDDs the IDD array list of the current network's country code
+     *
+     * @return the number plan type related international number
+     */
+    private static int checkInternationalNumberPlan(Context context, NumberEntry numberEntry,
+            ArrayList<String> allIDDs,String homeIDD) {
+        String number = numberEntry.number;
+        int countryCode = -1;
+
+        if (number.startsWith(PLUS_SIGN)) {
+            // +xxxxxxxxxx
+            String numberNoNBPCD = number.substring(1);
+            if (numberNoNBPCD.startsWith(homeIDD)) {
+                // +011xxxxxxxx
+                String numberCountryAreaLocal = numberNoNBPCD.substring(homeIDD.length());
+                if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) {
+                    numberEntry.countryCode = countryCode;
+                    return NP_NBPCD_HOMEIDD_CC_AREA_LOCAL;
+                }
+            } else if ((countryCode = getCountryCode(context, numberNoNBPCD)) > 0) {
+                numberEntry.countryCode = countryCode;
+                return NP_NBPCD_CC_AREA_LOCAL;
+            }
+
+        } else if (number.startsWith(homeIDD)) {
+            // 011xxxxxxxxx
+            String numberCountryAreaLocal = number.substring(homeIDD.length());
+            if ((countryCode = getCountryCode(context, numberCountryAreaLocal)) > 0) {
+                numberEntry.countryCode = countryCode;
+                return NP_HOMEIDD_CC_AREA_LOCAL;
+            }
+        } else {
+            for (String exitCode : allIDDs) {
+                if (number.startsWith(exitCode)) {
+                    String numberNoIDD = number.substring(exitCode.length());
+                    if ((countryCode = getCountryCode(context, numberNoIDD)) > 0) {
+                        numberEntry.countryCode = countryCode;
+                        numberEntry.IDD = exitCode;
+                        return NP_LOCALIDD_CC_AREA_LOCAL;
+                    }
+                }
+            }
+
+            if (!number.startsWith("0") && (countryCode = getCountryCode(context, number)) > 0) {
+                numberEntry.countryCode = countryCode;
+                return NP_CC_AREA_LOCAL;
+            }
+        }
+        return NP_NONE;
+    }
+
+    /**
+     *  Returns the country code from the given number.
+     */
+    private static int getCountryCode(Context context, String number) {
+        int countryCode = -1;
+        if (number.length() >= MIN_COUNTRY_AREA_LOCAL_LENGTH) {
+            // Check Country code
+            int[] allCCs = getAllCountryCodes(context);
+            if (allCCs == null) {
+                return countryCode;
+            }
+
+            int[] ccArray = new int[MAX_COUNTRY_CODES_LENGTH];
+            for (int i = 0; i < MAX_COUNTRY_CODES_LENGTH; i ++) {
+                ccArray[i] = Integer.parseInt(number.substring(0, i+1));
+            }
+
+            for (int i = 0; i < allCCs.length; i ++) {
+                int tempCC = allCCs[i];
+                for (int j = 0; j < MAX_COUNTRY_CODES_LENGTH; j ++) {
+                    if (tempCC == ccArray[j]) {
+                        if (DBG) Rlog.d(TAG, "Country code = " + tempCC);
+                        return tempCC;
+                    }
+                }
+            }
+        }
+
+        return countryCode;
+    }
+
+    /**
+     *  Gets all country Codes information with given MCC.
+     */
+    private static int[] getAllCountryCodes(Context context) {
+        if (ALL_COUNTRY_CODES != null) {
+            return ALL_COUNTRY_CODES;
+        }
+
+        Cursor cursor = null;
+        try {
+            String projection[] = {MccLookup.COUNTRY_CODE};
+            cursor = context.getContentResolver().query(MccLookup.CONTENT_URI,
+                    projection, null, null, null);
+
+            if (cursor.getCount() > 0) {
+                ALL_COUNTRY_CODES = new int[cursor.getCount()];
+                int i = 0;
+                while (cursor.moveToNext()) {
+                    int countryCode = cursor.getInt(0);
+                    ALL_COUNTRY_CODES[i++] = countryCode;
+                    int length = String.valueOf(countryCode).trim().length();
+                    if (length > MAX_COUNTRY_CODES_LENGTH) {
+                        MAX_COUNTRY_CODES_LENGTH = length;
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            Rlog.e(TAG, "Can't access HbpcdLookup database", e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return ALL_COUNTRY_CODES;
+    }
+
+    private static boolean inExceptionListForNpCcAreaLocal(NumberEntry numberEntry) {
+        int countryCode = numberEntry.countryCode;
+        boolean result = (numberEntry.number.length() == 12
+                          && (countryCode == 7 || countryCode == 20
+                              || countryCode == 65 || countryCode == 90));
+        return result;
+    }
+
+    private static String getNumberPlanType(int state) {
+        String numberPlanType = "Number Plan type (" + state + "): ";
+
+        if (state == NP_NANP_LOCAL) {
+            numberPlanType = "NP_NANP_LOCAL";
+        } else if (state == NP_NANP_AREA_LOCAL) {
+            numberPlanType = "NP_NANP_AREA_LOCAL";
+        } else if (state  == NP_NANP_NDD_AREA_LOCAL) {
+            numberPlanType = "NP_NANP_NDD_AREA_LOCAL";
+        } else if (state == NP_NANP_NBPCD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_NANP_NBPCD_CC_AREA_LOCAL";
+        } else if (state == NP_NANP_LOCALIDD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_NANP_LOCALIDD_CC_AREA_LOCAL";
+        } else if (state == NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_NANP_NBPCD_HOMEIDD_CC_AREA_LOCAL";
+        } else if (state == NP_NBPCD_HOMEIDD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_NBPCD_HOMEIDD_CC_AREA_LOCAL";
+        } else if (state == NP_HOMEIDD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_HOMEIDD_CC_AREA_LOCAL";
+        } else if (state == NP_NBPCD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_NBPCD_CC_AREA_LOCAL";
+        } else if (state == NP_LOCALIDD_CC_AREA_LOCAL) {
+            numberPlanType = "NP_LOCALIDD_CC_AREA_LOCAL";
+        } else if (state == NP_CC_AREA_LOCAL) {
+            numberPlanType = "NP_CC_AREA_LOCAL";
+        } else {
+            numberPlanType = "Unknown type";
+        }
+        return numberPlanType;
+    }
+
+    /**
+     * Filter the destination number if using VZW sim card.
+     */
+    public static String filterDestAddr(Context context, int subId, String destAddr) {
+        if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" );
+
+        if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) {
+            Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) +
+                    " is not a global phone number! Nothing changed.");
+            return destAddr;
+        }
+
+        final TelephonyManager telephonyManager = ((TelephonyManager) context
+                .getSystemService(Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId);
+        final String networkOperator = telephonyManager.getNetworkOperator();
+        String result = null;
+
+        if (needToConvert(context, subId)) {
+            final int networkType = getNetworkType(telephonyManager);
+            if (networkType != -1 && !TextUtils.isEmpty(networkOperator)) {
+                String networkMcc = networkOperator.substring(0, 3);
+                if (networkMcc != null && networkMcc.trim().length() > 0) {
+                    result = formatNumber(context, destAddr, networkMcc, networkType);
+                }
+            }
+        }
+
+        if (DBG) {
+            Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
+            Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG,
+                    result) : Rlog.pii(TAG, destAddr)) + "\"");
+        }
+        return result != null ? result : destAddr;
+    }
+
+    /**
+     * Returns the current network type
+     */
+    private static int getNetworkType(TelephonyManager telephonyManager) {
+        int networkType = -1;
+        int phoneType = telephonyManager.getPhoneType();
+
+        if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
+            networkType = GSM_UMTS_NETWORK;
+        } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
+            if (isInternationalRoaming(telephonyManager)) {
+                networkType = CDMA_ROAMING_NETWORK;
+            } else {
+                networkType = CDMA_HOME_NETWORK;
+            }
+        } else {
+            if (DBG) Rlog.w(TAG, "warning! unknown mPhoneType value=" + phoneType);
+        }
+
+        return networkType;
+    }
+
+    private static boolean isInternationalRoaming(TelephonyManager telephonyManager) {
+        String operatorIsoCountry = telephonyManager.getNetworkCountryIso();
+        String simIsoCountry = telephonyManager.getSimCountryIso();
+        boolean internationalRoaming = !TextUtils.isEmpty(operatorIsoCountry)
+                && !TextUtils.isEmpty(simIsoCountry)
+                && !simIsoCountry.equals(operatorIsoCountry);
+        if (internationalRoaming) {
+            if ("us".equals(simIsoCountry)) {
+                internationalRoaming = !"vi".equals(operatorIsoCountry);
+            } else if ("vi".equals(simIsoCountry)) {
+                internationalRoaming = !"us".equals(operatorIsoCountry);
+            }
+        }
+        return internationalRoaming;
+    }
+
+    private static boolean needToConvert(Context context, int subId) {
+        // Calling package may not have READ_PHONE_STATE which is required for getConfig().
+        // Clear the calling identity so that it is called as self.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            if (configManager != null) {
+                PersistableBundle bundle = configManager.getConfigForSubId(subId);
+                if (bundle != null) {
+                    return bundle.getBoolean(CarrierConfigManager
+                            .KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        // by default this value is false
+        return false;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java
new file mode 100644
index 0000000..12e4b7e
--- /dev/null
+++ b/telephony/common/com/google/android/mms/ContentType.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.util.ArrayList;
+
+public class ContentType {
+    public static final String MMS_MESSAGE       = "application/vnd.wap.mms-message";
+    // The phony content type for generic PDUs (e.g. ReadOrig.ind,
+    // Notification.ind, Delivery.ind).
+    public static final String MMS_GENERIC       = "application/vnd.wap.mms-generic";
+    public static final String MULTIPART_MIXED   = "application/vnd.wap.multipart.mixed";
+    public static final String MULTIPART_RELATED = "application/vnd.wap.multipart.related";
+    public static final String MULTIPART_ALTERNATIVE = "application/vnd.wap.multipart.alternative";
+
+    public static final String TEXT_PLAIN        = "text/plain";
+    public static final String TEXT_HTML         = "text/html";
+    public static final String TEXT_VCALENDAR    = "text/x-vCalendar";
+    public static final String TEXT_VCARD        = "text/x-vCard";
+
+    public static final String IMAGE_UNSPECIFIED = "image/*";
+    public static final String IMAGE_JPEG        = "image/jpeg";
+    public static final String IMAGE_JPG         = "image/jpg";
+    public static final String IMAGE_GIF         = "image/gif";
+    public static final String IMAGE_WBMP        = "image/vnd.wap.wbmp";
+    public static final String IMAGE_PNG         = "image/png";
+    public static final String IMAGE_X_MS_BMP    = "image/x-ms-bmp";
+
+    public static final String AUDIO_UNSPECIFIED = "audio/*";
+    public static final String AUDIO_AAC         = "audio/aac";
+    public static final String AUDIO_AMR         = "audio/amr";
+    public static final String AUDIO_IMELODY     = "audio/imelody";
+    public static final String AUDIO_MID         = "audio/mid";
+    public static final String AUDIO_MIDI        = "audio/midi";
+    public static final String AUDIO_MP3         = "audio/mp3";
+    public static final String AUDIO_MPEG3       = "audio/mpeg3";
+    public static final String AUDIO_MPEG        = "audio/mpeg";
+    public static final String AUDIO_MPG         = "audio/mpg";
+    public static final String AUDIO_MP4         = "audio/mp4";
+    public static final String AUDIO_X_MID       = "audio/x-mid";
+    public static final String AUDIO_X_MIDI      = "audio/x-midi";
+    public static final String AUDIO_X_MP3       = "audio/x-mp3";
+    public static final String AUDIO_X_MPEG3     = "audio/x-mpeg3";
+    public static final String AUDIO_X_MPEG      = "audio/x-mpeg";
+    public static final String AUDIO_X_MPG       = "audio/x-mpg";
+    public static final String AUDIO_3GPP        = "audio/3gpp";
+    public static final String AUDIO_X_WAV       = "audio/x-wav";
+    public static final String AUDIO_OGG         = "application/ogg";
+    public static final String AUDIO_OGG2        = "audio/ogg";
+
+    public static final String VIDEO_UNSPECIFIED = "video/*";
+    public static final String VIDEO_3GPP        = "video/3gpp";
+    public static final String VIDEO_3G2         = "video/3gpp2";
+    public static final String VIDEO_H263        = "video/h263";
+    public static final String VIDEO_MP4         = "video/mp4";
+
+    public static final String APP_SMIL          = "application/smil";
+    public static final String APP_WAP_XHTML     = "application/vnd.wap.xhtml+xml";
+    public static final String APP_XHTML         = "application/xhtml+xml";
+
+    public static final String APP_DRM_CONTENT   = "application/vnd.oma.drm.content";
+    public static final String APP_DRM_MESSAGE   = "application/vnd.oma.drm.message";
+
+    private static final ArrayList<String> sSupportedContentTypes = new ArrayList<String>();
+    private static final ArrayList<String> sSupportedImageTypes = new ArrayList<String>();
+    private static final ArrayList<String> sSupportedAudioTypes = new ArrayList<String>();
+    private static final ArrayList<String> sSupportedVideoTypes = new ArrayList<String>();
+
+    static {
+        sSupportedContentTypes.add(TEXT_PLAIN);
+        sSupportedContentTypes.add(TEXT_HTML);
+        sSupportedContentTypes.add(TEXT_VCALENDAR);
+        sSupportedContentTypes.add(TEXT_VCARD);
+
+        sSupportedContentTypes.add(IMAGE_JPEG);
+        sSupportedContentTypes.add(IMAGE_GIF);
+        sSupportedContentTypes.add(IMAGE_WBMP);
+        sSupportedContentTypes.add(IMAGE_PNG);
+        sSupportedContentTypes.add(IMAGE_JPG);
+        sSupportedContentTypes.add(IMAGE_X_MS_BMP);
+        //supportedContentTypes.add(IMAGE_SVG); not yet supported.
+
+        sSupportedContentTypes.add(AUDIO_AAC);
+        sSupportedContentTypes.add(AUDIO_AMR);
+        sSupportedContentTypes.add(AUDIO_IMELODY);
+        sSupportedContentTypes.add(AUDIO_MID);
+        sSupportedContentTypes.add(AUDIO_MIDI);
+        sSupportedContentTypes.add(AUDIO_MP3);
+        sSupportedContentTypes.add(AUDIO_MP4);
+        sSupportedContentTypes.add(AUDIO_MPEG3);
+        sSupportedContentTypes.add(AUDIO_MPEG);
+        sSupportedContentTypes.add(AUDIO_MPG);
+        sSupportedContentTypes.add(AUDIO_X_MID);
+        sSupportedContentTypes.add(AUDIO_X_MIDI);
+        sSupportedContentTypes.add(AUDIO_X_MP3);
+        sSupportedContentTypes.add(AUDIO_X_MPEG3);
+        sSupportedContentTypes.add(AUDIO_X_MPEG);
+        sSupportedContentTypes.add(AUDIO_X_MPG);
+        sSupportedContentTypes.add(AUDIO_X_WAV);
+        sSupportedContentTypes.add(AUDIO_3GPP);
+        sSupportedContentTypes.add(AUDIO_OGG);
+        sSupportedContentTypes.add(AUDIO_OGG2);
+
+        sSupportedContentTypes.add(VIDEO_3GPP);
+        sSupportedContentTypes.add(VIDEO_3G2);
+        sSupportedContentTypes.add(VIDEO_H263);
+        sSupportedContentTypes.add(VIDEO_MP4);
+
+        sSupportedContentTypes.add(APP_SMIL);
+        sSupportedContentTypes.add(APP_WAP_XHTML);
+        sSupportedContentTypes.add(APP_XHTML);
+
+        sSupportedContentTypes.add(APP_DRM_CONTENT);
+        sSupportedContentTypes.add(APP_DRM_MESSAGE);
+
+        // add supported image types
+        sSupportedImageTypes.add(IMAGE_JPEG);
+        sSupportedImageTypes.add(IMAGE_GIF);
+        sSupportedImageTypes.add(IMAGE_WBMP);
+        sSupportedImageTypes.add(IMAGE_PNG);
+        sSupportedImageTypes.add(IMAGE_JPG);
+        sSupportedImageTypes.add(IMAGE_X_MS_BMP);
+
+        // add supported audio types
+        sSupportedAudioTypes.add(AUDIO_AAC);
+        sSupportedAudioTypes.add(AUDIO_AMR);
+        sSupportedAudioTypes.add(AUDIO_IMELODY);
+        sSupportedAudioTypes.add(AUDIO_MID);
+        sSupportedAudioTypes.add(AUDIO_MIDI);
+        sSupportedAudioTypes.add(AUDIO_MP3);
+        sSupportedAudioTypes.add(AUDIO_MPEG3);
+        sSupportedAudioTypes.add(AUDIO_MPEG);
+        sSupportedAudioTypes.add(AUDIO_MPG);
+        sSupportedAudioTypes.add(AUDIO_MP4);
+        sSupportedAudioTypes.add(AUDIO_X_MID);
+        sSupportedAudioTypes.add(AUDIO_X_MIDI);
+        sSupportedAudioTypes.add(AUDIO_X_MP3);
+        sSupportedAudioTypes.add(AUDIO_X_MPEG3);
+        sSupportedAudioTypes.add(AUDIO_X_MPEG);
+        sSupportedAudioTypes.add(AUDIO_X_MPG);
+        sSupportedAudioTypes.add(AUDIO_X_WAV);
+        sSupportedAudioTypes.add(AUDIO_3GPP);
+        sSupportedAudioTypes.add(AUDIO_OGG);
+        sSupportedAudioTypes.add(AUDIO_OGG2);
+
+        // add supported video types
+        sSupportedVideoTypes.add(VIDEO_3GPP);
+        sSupportedVideoTypes.add(VIDEO_3G2);
+        sSupportedVideoTypes.add(VIDEO_H263);
+        sSupportedVideoTypes.add(VIDEO_MP4);
+    }
+
+    // This class should never be instantiated.
+    private ContentType() {
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isSupportedType(String contentType) {
+        return (null != contentType) && sSupportedContentTypes.contains(contentType);
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isSupportedImageType(String contentType) {
+        return isImageType(contentType) && isSupportedType(contentType);
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isSupportedAudioType(String contentType) {
+        return isAudioType(contentType) && isSupportedType(contentType);
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isSupportedVideoType(String contentType) {
+        return isVideoType(contentType) && isSupportedType(contentType);
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isTextType(String contentType) {
+        return (null != contentType) && contentType.startsWith("text/");
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isImageType(String contentType) {
+        return (null != contentType) && contentType.startsWith("image/");
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isAudioType(String contentType) {
+        return (null != contentType) && contentType.startsWith("audio/");
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isVideoType(String contentType) {
+        return (null != contentType) && contentType.startsWith("video/");
+    }
+
+    @UnsupportedAppUsage
+    public static boolean isDrmType(String contentType) {
+        return (null != contentType)
+                && (contentType.equals(APP_DRM_CONTENT)
+                        || contentType.equals(APP_DRM_MESSAGE));
+    }
+
+    public static boolean isUnspecified(String contentType) {
+        return (null != contentType) && contentType.endsWith("*");
+    }
+
+    @UnsupportedAppUsage
+    @SuppressWarnings("unchecked")
+    public static ArrayList<String> getImageTypes() {
+        return (ArrayList<String>) sSupportedImageTypes.clone();
+    }
+
+    @UnsupportedAppUsage
+    @SuppressWarnings("unchecked")
+    public static ArrayList<String> getAudioTypes() {
+        return (ArrayList<String>) sSupportedAudioTypes.clone();
+    }
+
+    @UnsupportedAppUsage
+    @SuppressWarnings("unchecked")
+    public static ArrayList<String> getVideoTypes() {
+        return (ArrayList<String>) sSupportedVideoTypes.clone();
+    }
+
+    @SuppressWarnings("unchecked")
+    public static ArrayList<String> getSupportedTypes() {
+        return (ArrayList<String>) sSupportedContentTypes.clone();
+    }
+}
diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
new file mode 100644
index 0000000..2836c30
--- /dev/null
+++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+/**
+ * Thrown when an invalid header value was set.
+ */
+public class InvalidHeaderValueException extends MmsException {
+    private static final long serialVersionUID = -2053384496042052262L;
+
+    /**
+     * Constructs an InvalidHeaderValueException with no detailed message.
+     */
+    public InvalidHeaderValueException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidHeaderValueException with the specified detailed message.
+     *
+     * @param message the detailed message.
+     */
+    @UnsupportedAppUsage
+    public InvalidHeaderValueException(String message) {
+        super(message);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java
new file mode 100644
index 0000000..5be33ed
--- /dev/null
+++ b/telephony/common/com/google/android/mms/MmsException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+/**
+ * A generic exception that is thrown by the Mms client.
+ */
+public class MmsException extends Exception {
+    private static final long serialVersionUID = -7323249827281485390L;
+
+    /**
+     * Creates a new MmsException.
+     */
+    @UnsupportedAppUsage
+    public MmsException() {
+        super();
+    }
+
+    /**
+     * Creates a new MmsException with the specified detail message.
+     *
+     * @param message the detail message.
+     */
+    @UnsupportedAppUsage
+    public MmsException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new MmsException with the specified cause.
+     *
+     * @param cause the cause.
+     */
+    @UnsupportedAppUsage
+    public MmsException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Creates a new MmsException with the specified detail message and cause.
+     *
+     * @param message the detail message.
+     * @param cause the cause.
+     */
+    @UnsupportedAppUsage
+    public MmsException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/package.html b/telephony/common/com/google/android/mms/package.html
new file mode 100755
index 0000000..c9f96a6
--- /dev/null
+++ b/telephony/common/com/google/android/mms/package.html
@@ -0,0 +1,5 @@
+<body>
+
+{@hide}
+
+</body>
diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
new file mode 100644
index 0000000..ae447d7
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * M-Acknowledge.ind PDU.
+ */
+public class AcknowledgeInd extends GenericPdu {
+    /**
+     * Constructor, used when composing a M-Acknowledge.ind pdu.
+     *
+     * @param mmsVersion current viersion of mms
+     * @param transactionId the transaction-id value
+     * @throws InvalidHeaderValueException if parameters are invalid.
+     *         NullPointerException if transactionId is null.
+     */
+    @UnsupportedAppUsage
+    public AcknowledgeInd(int mmsVersion, byte[] transactionId)
+            throws InvalidHeaderValueException {
+        super();
+
+        setMessageType(PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND);
+        setMmsVersion(mmsVersion);
+        setTransactionId(transactionId);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    AcknowledgeInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get X-Mms-Report-Allowed field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    public int getReportAllowed() {
+        return mPduHeaders.getOctet(PduHeaders.REPORT_ALLOWED);
+    }
+
+    /**
+     * Set X-Mms-Report-Allowed field value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setReportAllowed(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.REPORT_ALLOWED);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id field value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setTransactionId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java
new file mode 100644
index 0000000..483fa7f
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/Base64.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+public class Base64 {
+    /**
+     * Used to get the number of Quadruples.
+     */
+    static final int FOURBYTE = 4;
+
+    /**
+     * Byte used to pad output.
+     */
+    static final byte PAD = (byte) '=';
+
+    /**
+     * The base length.
+     */
+    static final int BASELENGTH = 255;
+
+    // Create arrays to hold the base64 characters
+    private static byte[] base64Alphabet = new byte[BASELENGTH];
+
+    // Populating the character arrays
+    static {
+        for (int i = 0; i < BASELENGTH; i++) {
+            base64Alphabet[i] = (byte) -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--) {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i >= 'a'; i--) {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+        for (int i = '9'; i >= '0'; i--) {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+'] = 62;
+        base64Alphabet['/'] = 63;
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param base64Data Byte array containing Base64 data
+     * @return Array containing decoded data.
+     */
+    @UnsupportedAppUsage
+    public static byte[] decodeBase64(byte[] base64Data) {
+        // RFC 2045 requires that we discard ALL non-Base64 characters
+        base64Data = discardNonBase64(base64Data);
+
+        // handle the edge case, so we don't have to worry about it later
+        if (base64Data.length == 0) {
+            return new byte[0];
+        }
+
+        int numberQuadruple = base64Data.length / FOURBYTE;
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
+
+        // Throw away anything not in base64Data
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        {
+            // this sizes the output array properly - rlw
+            int lastData = base64Data.length;
+            // ignore the '=' padding
+            while (base64Data[lastData - 1] == PAD) {
+                if (--lastData == 0) {
+                    return new byte[0];
+                }
+            }
+            decodedData = new byte[lastData - numberQuadruple];
+        }
+
+        for (int i = 0; i < numberQuadruple; i++) {
+            dataIndex = i * 4;
+            marker0 = base64Data[dataIndex + 2];
+            marker1 = base64Data[dataIndex + 3];
+
+            b1 = base64Alphabet[base64Data[dataIndex]];
+            b2 = base64Alphabet[base64Data[dataIndex + 1]];
+
+            if (marker0 != PAD && marker1 != PAD) {
+                //No PAD e.g 3cQl
+                b3 = base64Alphabet[marker0];
+                b4 = base64Alphabet[marker1];
+
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                decodedData[encodedIndex + 1] =
+                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
+            } else if (marker0 == PAD) {
+                //Two PAD e.g. 3c[Pad][Pad]
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+            } else if (marker1 == PAD) {
+                //One PAD e.g. 3cQ[Pad]
+                b3 = base64Alphabet[marker0];
+
+                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                decodedData[encodedIndex + 1] =
+                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            }
+            encodedIndex += 3;
+        }
+        return decodedData;
+    }
+
+    /**
+     * Check octect whether it is a base64 encoding.
+     *
+     * @param octect to be checked byte
+     * @return ture if it is base64 encoding, false otherwise.
+     */
+    private static boolean isBase64(byte octect) {
+        if (octect == PAD) {
+            return true;
+        } else if (base64Alphabet[octect] == -1) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Discards any characters outside of the base64 alphabet, per
+     * the requirements on page 25 of RFC 2045 - "Any characters
+     * outside of the base64 alphabet are to be ignored in base64
+     * encoded data."
+     *
+     * @param data The base-64 encoded data to groom
+     * @return The data, less non-base64 characters (see RFC 2045).
+     */
+    static byte[] discardNonBase64(byte[] data) {
+        byte groomedData[] = new byte[data.length];
+        int bytesCopied = 0;
+
+        for (int i = 0; i < data.length; i++) {
+            if (isBase64(data[i])) {
+                groomedData[bytesCopied++] = data[i];
+            }
+        }
+
+        byte packedData[] = new byte[bytesCopied];
+
+        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+        return packedData;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
new file mode 100644
index 0000000..27da35e
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+
+public class CharacterSets {
+    /**
+     * IANA assigned MIB enum numbers.
+     *
+     * From wap-230-wsp-20010705-a.pdf
+     * Any-charset = <Octet 128>
+     * Equivalent to the special RFC2616 charset value "*"
+     */
+    public static final int ANY_CHARSET = 0x00;
+    public static final int US_ASCII    = 0x03;
+    public static final int ISO_8859_1  = 0x04;
+    public static final int ISO_8859_2  = 0x05;
+    public static final int ISO_8859_3  = 0x06;
+    public static final int ISO_8859_4  = 0x07;
+    public static final int ISO_8859_5  = 0x08;
+    public static final int ISO_8859_6  = 0x09;
+    public static final int ISO_8859_7  = 0x0A;
+    public static final int ISO_8859_8  = 0x0B;
+    public static final int ISO_8859_9  = 0x0C;
+    public static final int SHIFT_JIS   = 0x11;
+    public static final int UTF_8       = 0x6A;
+    public static final int BIG5        = 0x07EA;
+    public static final int UCS2        = 0x03E8;
+    public static final int UTF_16      = 0x03F7;
+
+    /**
+     * If the encoding of given data is unsupported, use UTF_8 to decode it.
+     */
+    public static final int DEFAULT_CHARSET = UTF_8;
+
+    /**
+     * Array of MIB enum numbers.
+     */
+    private static final int[] MIBENUM_NUMBERS = {
+        ANY_CHARSET,
+        US_ASCII,
+        ISO_8859_1,
+        ISO_8859_2,
+        ISO_8859_3,
+        ISO_8859_4,
+        ISO_8859_5,
+        ISO_8859_6,
+        ISO_8859_7,
+        ISO_8859_8,
+        ISO_8859_9,
+        SHIFT_JIS,
+        UTF_8,
+        BIG5,
+        UCS2,
+        UTF_16,
+    };
+
+    /**
+     * The Well-known-charset Mime name.
+     */
+    public static final String MIMENAME_ANY_CHARSET = "*";
+    public static final String MIMENAME_US_ASCII    = "us-ascii";
+    public static final String MIMENAME_ISO_8859_1  = "iso-8859-1";
+    public static final String MIMENAME_ISO_8859_2  = "iso-8859-2";
+    public static final String MIMENAME_ISO_8859_3  = "iso-8859-3";
+    public static final String MIMENAME_ISO_8859_4  = "iso-8859-4";
+    public static final String MIMENAME_ISO_8859_5  = "iso-8859-5";
+    public static final String MIMENAME_ISO_8859_6  = "iso-8859-6";
+    public static final String MIMENAME_ISO_8859_7  = "iso-8859-7";
+    public static final String MIMENAME_ISO_8859_8  = "iso-8859-8";
+    public static final String MIMENAME_ISO_8859_9  = "iso-8859-9";
+    public static final String MIMENAME_SHIFT_JIS   = "shift_JIS";
+    public static final String MIMENAME_UTF_8       = "utf-8";
+    public static final String MIMENAME_BIG5        = "big5";
+    public static final String MIMENAME_UCS2        = "iso-10646-ucs-2";
+    public static final String MIMENAME_UTF_16      = "utf-16";
+
+    public static final String DEFAULT_CHARSET_NAME = MIMENAME_UTF_8;
+
+    /**
+     * Array of the names of character sets.
+     */
+    private static final String[] MIME_NAMES = {
+        MIMENAME_ANY_CHARSET,
+        MIMENAME_US_ASCII,
+        MIMENAME_ISO_8859_1,
+        MIMENAME_ISO_8859_2,
+        MIMENAME_ISO_8859_3,
+        MIMENAME_ISO_8859_4,
+        MIMENAME_ISO_8859_5,
+        MIMENAME_ISO_8859_6,
+        MIMENAME_ISO_8859_7,
+        MIMENAME_ISO_8859_8,
+        MIMENAME_ISO_8859_9,
+        MIMENAME_SHIFT_JIS,
+        MIMENAME_UTF_8,
+        MIMENAME_BIG5,
+        MIMENAME_UCS2,
+        MIMENAME_UTF_16,
+    };
+
+    private static final HashMap<Integer, String> MIBENUM_TO_NAME_MAP;
+    private static final HashMap<String, Integer> NAME_TO_MIBENUM_MAP;
+
+    static {
+        // Create the HashMaps.
+        MIBENUM_TO_NAME_MAP = new HashMap<Integer, String>();
+        NAME_TO_MIBENUM_MAP = new HashMap<String, Integer>();
+        assert(MIBENUM_NUMBERS.length == MIME_NAMES.length);
+        int count = MIBENUM_NUMBERS.length - 1;
+        for(int i = 0; i <= count; i++) {
+            MIBENUM_TO_NAME_MAP.put(MIBENUM_NUMBERS[i], MIME_NAMES[i]);
+            NAME_TO_MIBENUM_MAP.put(MIME_NAMES[i], MIBENUM_NUMBERS[i]);
+        }
+    }
+
+    private CharacterSets() {} // Non-instantiatable
+
+    /**
+     * Map an MIBEnum number to the name of the charset which this number
+     * is assigned to by IANA.
+     *
+     * @param mibEnumValue An IANA assigned MIBEnum number.
+     * @return The name string of the charset.
+     * @throws UnsupportedEncodingException
+     */
+    @UnsupportedAppUsage
+    public static String getMimeName(int mibEnumValue)
+            throws UnsupportedEncodingException {
+        String name = MIBENUM_TO_NAME_MAP.get(mibEnumValue);
+        if (name == null) {
+            throw new UnsupportedEncodingException();
+        }
+        return name;
+    }
+
+    /**
+     * Map a well-known charset name to its assigned MIBEnum number.
+     *
+     * @param mimeName The charset name.
+     * @return The MIBEnum number assigned by IANA for this charset.
+     * @throws UnsupportedEncodingException
+     */
+    @UnsupportedAppUsage
+    public static int getMibEnumValue(String mimeName)
+            throws UnsupportedEncodingException {
+        if(null == mimeName) {
+            return -1;
+        }
+
+        Integer mibEnumValue = NAME_TO_MIBENUM_MAP.get(mimeName);
+        if (mibEnumValue == null) {
+            throw new UnsupportedEncodingException();
+        }
+        return mibEnumValue;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
new file mode 100644
index 0000000..7093ac6
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * M-Delivery.Ind Pdu.
+ */
+public class DeliveryInd extends GenericPdu {
+    /**
+     * Empty constructor.
+     * Since the Pdu corresponding to this class is constructed
+     * by the Proxy-Relay server, this class is only instantiated
+     * by the Pdu Parser.
+     *
+     * @throws InvalidHeaderValueException if error occurs.
+     */
+    public DeliveryInd() throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_DELIVERY_IND);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    DeliveryInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get Date value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getDate() {
+        return mPduHeaders.getLongInteger(PduHeaders.DATE);
+    }
+
+    /**
+     * Set Date value.
+     *
+     * @param value the value
+     */
+    public void setDate(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.DATE);
+    }
+
+    /**
+     * Get Message-ID value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageId() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Set Message-ID value.
+     *
+     * @param value the value, should not be null
+     * @throws NullPointerException if the value is null.
+     */
+    public void setMessageId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Get Status value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getStatus() {
+        return mPduHeaders.getOctet(PduHeaders.STATUS);
+    }
+
+    /**
+     * Set Status value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    public void setStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.STATUS);
+    }
+
+    /**
+     * Get To value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue[] getTo() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.TO);
+    }
+
+    /**
+     * set To value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setTo(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.TO);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     *
+     *     public EncodedStringValue getStatusText() {return null;}
+     *     public void setStatusText(EncodedStringValue value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
new file mode 100644
index 0000000..4166275
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+/**
+ * Encoded-string-value = Text-string | Value-length Char-set Text-string
+ */
+public class EncodedStringValue implements Cloneable {
+    private static final String TAG = "EncodedStringValue";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = false;
+
+    /**
+     * The Char-set value.
+     */
+    private int mCharacterSet;
+
+    /**
+     * The Text-string value.
+     */
+    private byte[] mData;
+
+    /**
+     * Constructor.
+     *
+     * @param charset the Char-set value
+     * @param data the Text-string value
+     * @throws NullPointerException if Text-string value is null.
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue(int charset, byte[] data) {
+        // TODO: CharSet needs to be validated against MIBEnum.
+        if(null == data) {
+            throw new NullPointerException("EncodedStringValue: Text-string is null.");
+        }
+
+        mCharacterSet = charset;
+        mData = new byte[data.length];
+        System.arraycopy(data, 0, mData, 0, data.length);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param data the Text-string value
+     * @throws NullPointerException if Text-string value is null.
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue(byte[] data) {
+        this(CharacterSets.DEFAULT_CHARSET, data);
+    }
+
+    @UnsupportedAppUsage
+    public EncodedStringValue(String data) {
+        try {
+            mData = data.getBytes(CharacterSets.DEFAULT_CHARSET_NAME);
+            mCharacterSet = CharacterSets.DEFAULT_CHARSET;
+        } catch (UnsupportedEncodingException e) {
+            Log.e(TAG, "Default encoding must be supported.", e);
+        }
+    }
+
+    /**
+     * Get Char-set value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getCharacterSet() {
+        return mCharacterSet;
+    }
+
+    /**
+     * Set Char-set value.
+     *
+     * @param charset the Char-set value
+     */
+    @UnsupportedAppUsage
+    public void setCharacterSet(int charset) {
+        // TODO: CharSet needs to be validated against MIBEnum.
+        mCharacterSet = charset;
+    }
+
+    /**
+     * Get Text-string value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getTextString() {
+        byte[] byteArray = new byte[mData.length];
+
+        System.arraycopy(mData, 0, byteArray, 0, mData.length);
+        return byteArray;
+    }
+
+    /**
+     * Set Text-string value.
+     *
+     * @param textString the Text-string value
+     * @throws NullPointerException if Text-string value is null.
+     */
+    @UnsupportedAppUsage
+    public void setTextString(byte[] textString) {
+        if(null == textString) {
+            throw new NullPointerException("EncodedStringValue: Text-string is null.");
+        }
+
+        mData = new byte[textString.length];
+        System.arraycopy(textString, 0, mData, 0, textString.length);
+    }
+
+    /**
+     * Convert this object to a {@link java.lang.String}. If the encoding of
+     * the EncodedStringValue is null or unsupported, it will be
+     * treated as iso-8859-1 encoding.
+     *
+     * @return The decoded String.
+     */
+    @UnsupportedAppUsage
+    public String getString()  {
+        if (CharacterSets.ANY_CHARSET == mCharacterSet) {
+            return new String(mData); // system default encoding.
+        } else {
+            try {
+                String name = CharacterSets.getMimeName(mCharacterSet);
+                return new String(mData, name);
+            } catch (UnsupportedEncodingException e) {
+            	if (LOCAL_LOGV) {
+            		Log.v(TAG, e.getMessage(), e);
+            	}
+            	try {
+                    return new String(mData, CharacterSets.MIMENAME_ISO_8859_1);
+                } catch (UnsupportedEncodingException e2) {
+                    return new String(mData); // system default encoding.
+                }
+            }
+        }
+    }
+
+    /**
+     * Append to Text-string.
+     *
+     * @param textString the textString to append
+     * @throws NullPointerException if the text String is null
+     *                      or an IOException occurred.
+     */
+    @UnsupportedAppUsage
+    public void appendTextString(byte[] textString) {
+        if(null == textString) {
+            throw new NullPointerException("Text-string is null.");
+        }
+
+        if(null == mData) {
+            mData = new byte[textString.length];
+            System.arraycopy(textString, 0, mData, 0, textString.length);
+        } else {
+            ByteArrayOutputStream newTextString = new ByteArrayOutputStream();
+            try {
+                newTextString.write(mData);
+                newTextString.write(textString);
+            } catch (IOException e) {
+                e.printStackTrace();
+                throw new NullPointerException(
+                        "appendTextString: failed when write a new Text-string");
+            }
+
+            mData = newTextString.toByteArray();
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+        super.clone();
+        int len = mData.length;
+        byte[] dstBytes = new byte[len];
+        System.arraycopy(mData, 0, dstBytes, 0, len);
+
+        try {
+            return new EncodedStringValue(mCharacterSet, dstBytes);
+        } catch (Exception e) {
+            Log.e(TAG, "failed to clone an EncodedStringValue: " + this);
+            e.printStackTrace();
+            throw new CloneNotSupportedException(e.getMessage());
+        }
+    }
+
+    /**
+     * Split this encoded string around matches of the given pattern.
+     *
+     * @param pattern the delimiting pattern
+     * @return the array of encoded strings computed by splitting this encoded
+     *         string around matches of the given pattern
+     */
+    public EncodedStringValue[] split(String pattern) {
+        String[] temp = getString().split(pattern);
+        EncodedStringValue[] ret = new EncodedStringValue[temp.length];
+        for (int i = 0; i < ret.length; ++i) {
+            try {
+                ret[i] = new EncodedStringValue(mCharacterSet,
+                        temp[i].getBytes());
+            } catch (NullPointerException e) {
+                // Can't arrive here
+                return null;
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Extract an EncodedStringValue[] from a given String.
+     */
+    @UnsupportedAppUsage
+    public static EncodedStringValue[] extract(String src) {
+        String[] values = src.split(";");
+
+        ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>();
+        for (int i = 0; i < values.length; i++) {
+            if (values[i].length() > 0) {
+                list.add(new EncodedStringValue(values[i]));
+            }
+        }
+
+        int len = list.size();
+        if (len > 0) {
+            return list.toArray(new EncodedStringValue[len]);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Concatenate an EncodedStringValue[] into a single String.
+     */
+    @UnsupportedAppUsage
+    public static String concat(EncodedStringValue[] addr) {
+        StringBuilder sb = new StringBuilder();
+        int maxIndex = addr.length - 1;
+        for (int i = 0; i <= maxIndex; i++) {
+            sb.append(addr[i].getString());
+            if (i < maxIndex) {
+                sb.append(";");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    @UnsupportedAppUsage
+    public static EncodedStringValue copy(EncodedStringValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        return new EncodedStringValue(value.mCharacterSet, value.mData);
+    }
+    
+    @UnsupportedAppUsage
+    public static EncodedStringValue[] encodeStrings(String[] array) {
+        int count = array.length;
+        if (count > 0) {
+            EncodedStringValue[] encodedArray = new EncodedStringValue[count];
+            for (int i = 0; i < count; i++) {
+                encodedArray[i] = new EncodedStringValue(array[i]);
+            }
+            return encodedArray;
+        }
+        return null;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
new file mode 100644
index 0000000..ebf16ac
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+public class GenericPdu {
+    /**
+     * The headers of pdu.
+     */
+    @UnsupportedAppUsage
+    PduHeaders mPduHeaders = null;
+
+    /**
+     * Constructor.
+     */
+    @UnsupportedAppUsage
+    public GenericPdu() {
+        mPduHeaders = new PduHeaders();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param headers Headers for this PDU.
+     */
+    GenericPdu(PduHeaders headers) {
+        mPduHeaders = headers;
+    }
+
+    /**
+     * Get the headers of this PDU.
+     *
+     * @return A PduHeaders of this PDU.
+     */
+    @UnsupportedAppUsage
+    PduHeaders getPduHeaders() {
+        return mPduHeaders;
+    }
+
+    /**
+     * Get X-Mms-Message-Type field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    @UnsupportedAppUsage
+    public int getMessageType() {
+        return mPduHeaders.getOctet(PduHeaders.MESSAGE_TYPE);
+    }
+
+    /**
+     * Set X-Mms-Message-Type field value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if field's value is not Octet.
+     */
+    @UnsupportedAppUsage
+    public void setMessageType(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.MESSAGE_TYPE);
+    }
+
+    /**
+     * Get X-Mms-MMS-Version field value.
+     *
+     * @return the X-Mms-MMS-Version value
+     */
+    public int getMmsVersion() {
+        return mPduHeaders.getOctet(PduHeaders.MMS_VERSION);
+    }
+
+    /**
+     * Set X-Mms-MMS-Version field value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if field's value is not Octet.
+     */
+    public void setMmsVersion(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.MMS_VERSION);
+    }
+
+    /**
+     * Get From value.
+     * From-value = Value-length
+     *      (Address-present-token Encoded-string-value | Insert-address-token)
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getFrom() {
+       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+    }
+
+    /**
+     * Set From value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setFrom(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
new file mode 100644
index 0000000..e108f76
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * Multimedia message PDU.
+ */
+public class MultimediaMessagePdu extends GenericPdu{
+    /**
+     * The body.
+     */
+    private PduBody mMessageBody;
+
+    /**
+     * Constructor.
+     */
+    @UnsupportedAppUsage
+    public MultimediaMessagePdu() {
+        super();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param header the header of this PDU
+     * @param body the body of this PDU
+     */
+    @UnsupportedAppUsage
+    public MultimediaMessagePdu(PduHeaders header, PduBody body) {
+        super(header);
+        mMessageBody = body;
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    MultimediaMessagePdu(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get body of the PDU.
+     *
+     * @return the body
+     */
+    @UnsupportedAppUsage
+    public PduBody getBody() {
+        return mMessageBody;
+    }
+
+    /**
+     * Set body of the PDU.
+     *
+     * @param body the body
+     */
+    @UnsupportedAppUsage
+    public void setBody(PduBody body) {
+        mMessageBody = body;
+    }
+
+    /**
+     * Get subject.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getSubject() {
+        return mPduHeaders.getEncodedStringValue(PduHeaders.SUBJECT);
+    }
+
+    /**
+     * Set subject.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setSubject(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.SUBJECT);
+    }
+
+    /**
+     * Get To value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue[] getTo() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.TO);
+    }
+
+    /**
+     * Add a "To" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void addTo(EncodedStringValue value) {
+        mPduHeaders.appendEncodedStringValue(value, PduHeaders.TO);
+    }
+
+    /**
+     * Get X-Mms-Priority value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getPriority() {
+        return mPduHeaders.getOctet(PduHeaders.PRIORITY);
+    }
+
+    /**
+     * Set X-Mms-Priority value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setPriority(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.PRIORITY);
+    }
+
+    /**
+     * Get Date value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getDate() {
+        return mPduHeaders.getLongInteger(PduHeaders.DATE);
+    }
+
+    /**
+     * Set Date value in seconds.
+     *
+     * @param value the value
+     */
+    @UnsupportedAppUsage
+    public void setDate(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.DATE);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
new file mode 100644
index 0000000..b561bd4
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * M-Notification.ind PDU.
+ */
+public class NotificationInd extends GenericPdu {
+    /**
+     * Empty constructor.
+     * Since the Pdu corresponding to this class is constructed
+     * by the Proxy-Relay server, this class is only instantiated
+     * by the Pdu Parser.
+     *
+     * @throws InvalidHeaderValueException if error occurs.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public NotificationInd() throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    NotificationInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get X-Mms-Content-Class Value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getContentClass() {
+        return mPduHeaders.getOctet(PduHeaders.CONTENT_CLASS);
+    }
+
+    /**
+     * Set X-Mms-Content-Class Value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setContentClass(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.CONTENT_CLASS);
+    }
+
+    /**
+     * Get X-Mms-Content-Location value.
+     * When used in a PDU other than M-Mbox-Delete.conf and M-Delete.conf:
+     * Content-location-value = Uri-value
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getContentLocation() {
+        return mPduHeaders.getTextString(PduHeaders.CONTENT_LOCATION);
+    }
+
+    /**
+     * Set X-Mms-Content-Location value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setContentLocation(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.CONTENT_LOCATION);
+    }
+
+    /**
+     * Get X-Mms-Expiry value.
+     *
+     * Expiry-value = Value-length
+     *      (Absolute-token Date-value | Relative-token Delta-seconds-value)
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getExpiry() {
+        return mPduHeaders.getLongInteger(PduHeaders.EXPIRY);
+    }
+
+    /**
+     * Set X-Mms-Expiry value.
+     *
+     * @param value the value
+     * @throws RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setExpiry(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.EXPIRY);
+    }
+
+    /**
+     * Get From value.
+     * From-value = Value-length
+     *      (Address-present-token Encoded-string-value | Insert-address-token)
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getFrom() {
+       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+    }
+
+    /**
+     * Set From value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setFrom(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+    }
+
+    /**
+     * Get X-Mms-Message-Class value.
+     * Message-class-value = Class-identifier | Token-text
+     * Class-identifier = Personal | Advertisement | Informational | Auto
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageClass() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Set X-Mms-Message-Class value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setMessageClass(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Get X-Mms-Message-Size value.
+     * Message-size-value = Long-integer
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getMessageSize() {
+        return mPduHeaders.getLongInteger(PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
+     * Set X-Mms-Message-Size value.
+     *
+     * @param value the value
+     * @throws RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setMessageSize(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
+     * Get subject.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getSubject() {
+        return mPduHeaders.getEncodedStringValue(PduHeaders.SUBJECT);
+    }
+
+    /**
+     * Set subject.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setSubject(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.SUBJECT);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setTransactionId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Get X-Mms-Delivery-Report Value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getDeliveryReport() {
+        return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT);
+    }
+
+    /**
+     * Set X-Mms-Delivery-Report Value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setDeliveryReport(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte getDrmContent() {return 0x00;}
+     *     public void setDrmContent(byte value) {}
+     *
+     *     public byte getDistributionIndicator() {return 0x00;}
+     *     public void setDistributionIndicator(byte value) {}
+     *
+     *     public ElementDescriptorValue getElementDescriptor() {return null;}
+     *     public void getElementDescriptor(ElementDescriptorValue value) {}
+     *
+     *     public byte getPriority() {return 0x00;}
+     *     public void setPriority(byte value) {}
+     *
+     *     public byte getRecommendedRetrievalMode() {return 0x00;}
+     *     public void setRecommendedRetrievalMode(byte value) {}
+     *
+     *     public byte getRecommendedRetrievalModeText() {return 0x00;}
+     *     public void setRecommendedRetrievalModeText(byte value) {}
+     *
+     *     public byte[] getReplaceId() {return 0x00;}
+     *     public void setReplaceId(byte[] value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     *
+     *     public byte getReplyCharging() {return 0x00;}
+     *     public void setReplyCharging(byte value) {}
+     *
+     *     public byte getReplyChargingDeadline() {return 0x00;}
+     *     public void setReplyChargingDeadline(byte value) {}
+     *
+     *     public byte[] getReplyChargingId() {return 0x00;}
+     *     public void setReplyChargingId(byte[] value) {}
+     *
+     *     public long getReplyChargingSize() {return 0;}
+     *     public void setReplyChargingSize(long value) {}
+     *
+     *     public byte getStored() {return 0x00;}
+     *     public void setStored(byte value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
new file mode 100644
index 0000000..3c70f86
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * M-NofifyResp.ind PDU.
+ */
+public class NotifyRespInd extends GenericPdu {
+    /**
+     * Constructor, used when composing a M-NotifyResp.ind pdu.
+     *
+     * @param mmsVersion current version of mms
+     * @param transactionId the transaction-id value
+     * @param status the status value
+     * @throws InvalidHeaderValueException if parameters are invalid.
+     *         NullPointerException if transactionId is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public NotifyRespInd(int mmsVersion,
+                         byte[] transactionId,
+                         int status) throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND);
+        setMmsVersion(mmsVersion);
+        setTransactionId(transactionId);
+        setStatus(status);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    NotifyRespInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get X-Mms-Report-Allowed field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    public int getReportAllowed() {
+        return mPduHeaders.getOctet(PduHeaders.REPORT_ALLOWED);
+    }
+
+    /**
+     * Set X-Mms-Report-Allowed field value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setReportAllowed(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.REPORT_ALLOWED);
+    }
+
+    /**
+     * Set X-Mms-Status field value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.STATUS);
+    }
+
+    /**
+     * GetX-Mms-Status field value.
+     *
+     * @return the X-Mms-Status value
+     */
+    public int getStatus() {
+        return mPduHeaders.getOctet(PduHeaders.STATUS);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id field value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     *         RuntimeException if an undeclared error occurs.
+     */
+    @UnsupportedAppUsage
+    public void setTransactionId(byte[] value) {
+            mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java
new file mode 100644
index 0000000..51914e4
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduBody.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+public class PduBody {
+    private Vector<PduPart> mParts = null;
+
+    private Map<String, PduPart> mPartMapByContentId = null;
+    private Map<String, PduPart> mPartMapByContentLocation = null;
+    private Map<String, PduPart> mPartMapByName = null;
+    private Map<String, PduPart> mPartMapByFileName = null;
+
+    /**
+     * Constructor.
+     */
+    @UnsupportedAppUsage
+    public PduBody() {
+        mParts = new Vector<PduPart>();
+
+        mPartMapByContentId = new HashMap<String, PduPart>();
+        mPartMapByContentLocation  = new HashMap<String, PduPart>();
+        mPartMapByName = new HashMap<String, PduPart>();
+        mPartMapByFileName = new HashMap<String, PduPart>();
+    }
+
+    private void putPartToMaps(PduPart part) {
+        // Put part to mPartMapByContentId.
+        byte[] contentId = part.getContentId();
+        if(null != contentId) {
+            mPartMapByContentId.put(new String(contentId), part);
+        }
+
+        // Put part to mPartMapByContentLocation.
+        byte[] contentLocation = part.getContentLocation();
+        if(null != contentLocation) {
+            String clc = new String(contentLocation);
+            mPartMapByContentLocation.put(clc, part);
+        }
+
+        // Put part to mPartMapByName.
+        byte[] name = part.getName();
+        if(null != name) {
+            String clc = new String(name);
+            mPartMapByName.put(clc, part);
+        }
+
+        // Put part to mPartMapByFileName.
+        byte[] fileName = part.getFilename();
+        if(null != fileName) {
+            String clc = new String(fileName);
+            mPartMapByFileName.put(clc, part);
+        }
+    }
+
+    /**
+     * Appends the specified part to the end of this body.
+     *
+     * @param part part to be appended
+     * @return true when success, false when fail
+     * @throws NullPointerException when part is null
+     */
+    @UnsupportedAppUsage
+    public boolean addPart(PduPart part) {
+        if(null == part) {
+            throw new NullPointerException();
+        }
+
+        putPartToMaps(part);
+        return mParts.add(part);
+    }
+
+    /**
+     * Inserts the specified part at the specified position.
+     *
+     * @param index index at which the specified part is to be inserted
+     * @param part part to be inserted
+     * @throws NullPointerException when part is null
+     */
+    @UnsupportedAppUsage
+    public void addPart(int index, PduPart part) {
+        if(null == part) {
+            throw new NullPointerException();
+        }
+
+        putPartToMaps(part);
+        mParts.add(index, part);
+    }
+
+    /**
+     * Removes the part at the specified position.
+     *
+     * @param index index of the part to return
+     * @return part at the specified index
+     */
+    @UnsupportedAppUsage
+    public PduPart removePart(int index) {
+        return mParts.remove(index);
+    }
+
+    /**
+     * Remove all of the parts.
+     */
+    public void removeAll() {
+        mParts.clear();
+    }
+
+    /**
+     * Get the part at the specified position.
+     *
+     * @param index index of the part to return
+     * @return part at the specified index
+     */
+    @UnsupportedAppUsage
+    public PduPart getPart(int index) {
+        return mParts.get(index);
+    }
+
+    /**
+     * Get the index of the specified part.
+     *
+     * @param part the part object
+     * @return index the index of the first occurrence of the part in this body
+     */
+    @UnsupportedAppUsage
+    public int getPartIndex(PduPart part) {
+        return mParts.indexOf(part);
+    }
+
+    /**
+     * Get the number of parts.
+     *
+     * @return the number of parts
+     */
+    @UnsupportedAppUsage
+    public int getPartsNum() {
+        return mParts.size();
+    }
+
+    /**
+     * Get pdu part by content id.
+     *
+     * @param cid the value of content id.
+     * @return the pdu part.
+     */
+    @UnsupportedAppUsage
+    public PduPart getPartByContentId(String cid) {
+        return mPartMapByContentId.get(cid);
+    }
+
+    /**
+     * Get pdu part by Content-Location. Content-Location of part is
+     * the same as filename and name(param of content-type).
+     *
+     * @param fileName the value of filename.
+     * @return the pdu part.
+     */
+    @UnsupportedAppUsage
+    public PduPart getPartByContentLocation(String contentLocation) {
+        return mPartMapByContentLocation.get(contentLocation);
+    }
+
+    /**
+     * Get pdu part by name.
+     *
+     * @param fileName the value of filename.
+     * @return the pdu part.
+     */
+    @UnsupportedAppUsage
+    public PduPart getPartByName(String name) {
+        return mPartMapByName.get(name);
+    }
+
+    /**
+     * Get pdu part by filename.
+     *
+     * @param fileName the value of filename.
+     * @return the pdu part.
+     */
+    @UnsupportedAppUsage
+    public PduPart getPartByFileName(String filename) {
+        return mPartMapByFileName.get(filename);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
new file mode 100644
index 0000000..e24bf21
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -0,0 +1,1229 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.text.TextUtils;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class PduComposer {
+    /**
+     * Address type.
+     */
+    static private final int PDU_PHONE_NUMBER_ADDRESS_TYPE = 1;
+    static private final int PDU_EMAIL_ADDRESS_TYPE = 2;
+    static private final int PDU_IPV4_ADDRESS_TYPE = 3;
+    static private final int PDU_IPV6_ADDRESS_TYPE = 4;
+    static private final int PDU_UNKNOWN_ADDRESS_TYPE = 5;
+
+    /**
+     * Address regular expression string.
+     */
+    static final String REGEXP_PHONE_NUMBER_ADDRESS_TYPE = "\\+?[0-9|\\.|\\-]+";
+    static final String REGEXP_EMAIL_ADDRESS_TYPE = "[a-zA-Z| ]*\\<{0,1}[a-zA-Z| ]+@{1}" +
+            "[a-zA-Z| ]+\\.{1}[a-zA-Z| ]+\\>{0,1}";
+    static final String REGEXP_IPV6_ADDRESS_TYPE =
+        "[a-fA-F]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}" +
+        "[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}\\:{1}" +
+        "[a-fA-F0-9]{4}\\:{1}[a-fA-F0-9]{4}";
+    static final String REGEXP_IPV4_ADDRESS_TYPE = "[0-9]{1,3}\\.{1}[0-9]{1,3}\\.{1}" +
+            "[0-9]{1,3}\\.{1}[0-9]{1,3}";
+
+    /**
+     * The postfix strings of address.
+     */
+    static final String STRING_PHONE_NUMBER_ADDRESS_TYPE = "/TYPE=PLMN";
+    static final String STRING_IPV4_ADDRESS_TYPE = "/TYPE=IPV4";
+    static final String STRING_IPV6_ADDRESS_TYPE = "/TYPE=IPV6";
+
+    /**
+     * Error values.
+     */
+    static private final int PDU_COMPOSE_SUCCESS = 0;
+    static private final int PDU_COMPOSE_CONTENT_ERROR = 1;
+    static private final int PDU_COMPOSE_FIELD_NOT_SET = 2;
+    static private final int PDU_COMPOSE_FIELD_NOT_SUPPORTED = 3;
+
+    /**
+     * WAP values defined in WSP spec.
+     */
+    static private final int QUOTED_STRING_FLAG = 34;
+    static private final int END_STRING_FLAG = 0;
+    static private final int LENGTH_QUOTE = 31;
+    static private final int TEXT_MAX = 127;
+    static private final int SHORT_INTEGER_MAX = 127;
+    static private final int LONG_INTEGER_LENGTH_MAX = 8;
+
+    /**
+     * Block size when read data from InputStream.
+     */
+    static private final int PDU_COMPOSER_BLOCK_SIZE = 1024;
+
+    /**
+     * The output message.
+     */
+    @UnsupportedAppUsage
+    protected ByteArrayOutputStream mMessage = null;
+
+    /**
+     * The PDU.
+     */
+    @UnsupportedAppUsage
+    private GenericPdu mPdu = null;
+
+    /**
+     * Current visiting position of the mMessage.
+     */
+    @UnsupportedAppUsage
+    protected int mPosition = 0;
+
+    /**
+     * Message compose buffer stack.
+     */
+    @UnsupportedAppUsage
+    private BufferStack mStack = null;
+
+    /**
+     * Content resolver.
+     */
+    @UnsupportedAppUsage
+    private final ContentResolver mResolver;
+
+    /**
+     * Header of this pdu.
+     */
+    @UnsupportedAppUsage
+    private PduHeaders mPduHeader = null;
+
+    /**
+     * Map of all content type
+     */
+    @UnsupportedAppUsage
+    private static HashMap<String, Integer> mContentTypeMap = null;
+
+    static {
+        mContentTypeMap = new HashMap<String, Integer>();
+
+        int i;
+        for (i = 0; i < PduContentTypes.contentTypes.length; i++) {
+            mContentTypeMap.put(PduContentTypes.contentTypes[i], i);
+        }
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param context the context
+     * @param pdu the pdu to be composed
+     */
+    @UnsupportedAppUsage
+    public PduComposer(Context context, GenericPdu pdu) {
+        mPdu = pdu;
+        mResolver = context.getContentResolver();
+        mPduHeader = pdu.getPduHeaders();
+        mStack = new BufferStack();
+        mMessage = new ByteArrayOutputStream();
+        mPosition = 0;
+    }
+
+    /**
+     * Make the message. No need to check whether mandatory fields are set,
+     * because the constructors of outgoing pdus are taking care of this.
+     *
+     * @return OutputStream of maked message. Return null if
+     *         the PDU is invalid.
+     */
+    @UnsupportedAppUsage
+    public byte[] make() {
+        // Get Message-type.
+        int type = mPdu.getMessageType();
+
+        /* make the message */
+        switch (type) {
+            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
+            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
+                if (makeSendRetrievePdu(type) != PDU_COMPOSE_SUCCESS) {
+                    return null;
+                }
+                break;
+            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
+                if (makeNotifyResp() != PDU_COMPOSE_SUCCESS) {
+                    return null;
+                }
+                break;
+            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
+                if (makeAckInd() != PDU_COMPOSE_SUCCESS) {
+                    return null;
+                }
+                break;
+            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
+                if (makeReadRecInd() != PDU_COMPOSE_SUCCESS) {
+                    return null;
+                }
+                break;
+            default:
+                return null;
+        }
+
+        return mMessage.toByteArray();
+    }
+
+    /**
+     *  Copy buf to mMessage.
+     */
+    @UnsupportedAppUsage
+    protected void arraycopy(byte[] buf, int pos, int length) {
+        mMessage.write(buf, pos, length);
+        mPosition = mPosition + length;
+    }
+
+    /**
+     * Append a byte to mMessage.
+     */
+    protected void append(int value) {
+        mMessage.write(value);
+        mPosition ++;
+    }
+
+    /**
+     * Append short integer value to mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendShortInteger(int value) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Short-integer = OCTET
+         * ; Integers in range 0-127 shall be encoded as a one octet value
+         * ; with the most significant bit set to one (1xxx xxxx) and with
+         * ; the value in the remaining least significant bits.
+         * In our implementation, only low 7 bits are stored and otherwise
+         * bits are ignored.
+         */
+        append((value | 0x80) & 0xff);
+    }
+
+    /**
+     * Append an octet number between 128 and 255 into mMessage.
+     * NOTE:
+     * A value between 0 and 127 should be appended by using appendShortInteger.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendOctet(int number) {
+        append(number);
+    }
+
+    /**
+     * Append a short length into mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    protected void appendShortLength(int value) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Short-length = <Any octet 0-30>
+         */
+        append(value);
+    }
+
+    /**
+     * Append long integer into mMessage. it's used for really long integers.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendLongInteger(long longInt) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Long-integer = Short-length Multi-octet-integer
+         * ; The Short-length indicates the length of the Multi-octet-integer
+         * Multi-octet-integer = 1*30 OCTET
+         * ; The content octets shall be an unsigned integer value with the
+         * ; most significant octet encoded first (big-endian representation).
+         * ; The minimum number of octets must be used to encode the value.
+         */
+        int size;
+        long temp = longInt;
+
+        // Count the length of the long integer.
+        for(size = 0; (temp != 0) && (size < LONG_INTEGER_LENGTH_MAX); size++) {
+            temp = (temp >>> 8);
+        }
+
+        // Set Length.
+        appendShortLength(size);
+
+        // Count and set the long integer.
+        int i;
+        int shift = (size -1) * 8;
+
+        for (i = 0; i < size; i++) {
+            append((int)((longInt >>> shift) & 0xff));
+            shift = shift - 8;
+        }
+    }
+
+    /**
+     * Append text string into mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendTextString(byte[] text) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Text-string = [Quote] *TEXT End-of-string
+         * ; If the first character in the TEXT is in the range of 128-255,
+         * ; a Quote character must precede it. Otherwise the Quote character
+         * ;must be omitted. The Quote is not part of the contents.
+         */
+        if (((text[0])&0xff) > TEXT_MAX) { // No need to check for <= 255
+            append(TEXT_MAX);
+        }
+
+        arraycopy(text, 0, text.length);
+        append(0);
+    }
+
+    /**
+     * Append text string into mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendTextString(String str) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Text-string = [Quote] *TEXT End-of-string
+         * ; If the first character in the TEXT is in the range of 128-255,
+         * ; a Quote character must precede it. Otherwise the Quote character
+         * ;must be omitted. The Quote is not part of the contents.
+         */
+        appendTextString(str.getBytes());
+    }
+
+    /**
+     * Append encoded string value to mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendEncodedString(EncodedStringValue enStr) {
+        /*
+         * From OMA-TS-MMS-ENC-V1_3-20050927-C:
+         * Encoded-string-value = Text-string | Value-length Char-set Text-string
+         */
+        assert(enStr != null);
+
+        int charset = enStr.getCharacterSet();
+        byte[] textString = enStr.getTextString();
+        if (null == textString) {
+            return;
+        }
+
+        /*
+         * In the implementation of EncodedStringValue, the charset field will
+         * never be 0. It will always be composed as
+         * Encoded-string-value = Value-length Char-set Text-string
+         */
+        mStack.newbuf();
+        PositionMarker start = mStack.mark();
+
+        appendShortInteger(charset);
+        appendTextString(textString);
+
+        int len = start.getLength();
+        mStack.pop();
+        appendValueLength(len);
+        mStack.copy();
+    }
+
+    /**
+     * Append uintvar integer into mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendUintvarInteger(long value) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * To encode a large unsigned integer, split it into 7-bit fragments
+         * and place them in the payloads of multiple octets. The most significant
+         * bits are placed in the first octets with the least significant bits
+         * ending up in the last octet. All octets MUST set the Continue bit to 1
+         * except the last octet, which MUST set the Continue bit to 0.
+         */
+        int i;
+        long max = SHORT_INTEGER_MAX;
+
+        for (i = 0; i < 5; i++) {
+            if (value < max) {
+                break;
+            }
+
+            max = (max << 7) | 0x7fl;
+        }
+
+        while(i > 0) {
+            long temp = value >>> (i * 7);
+            temp = temp & 0x7f;
+
+            append((int)((temp | 0x80) & 0xff));
+
+            i--;
+        }
+
+        append((int)(value & 0x7f));
+    }
+
+    /**
+     * Append date value into mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    protected void appendDateValue(long date) {
+        /*
+         * From OMA-TS-MMS-ENC-V1_3-20050927-C:
+         * Date-value = Long-integer
+         */
+        appendLongInteger(date);
+    }
+
+    /**
+     * Append value length to mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendValueLength(long value) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Value-length = Short-length | (Length-quote Length)
+         * ; Value length is used to indicate the length of the value to follow
+         * Short-length = <Any octet 0-30>
+         * Length-quote = <Octet 31>
+         * Length = Uintvar-integer
+         */
+        if (value < LENGTH_QUOTE) {
+            appendShortLength((int) value);
+            return;
+        }
+
+        append(LENGTH_QUOTE);
+        appendUintvarInteger(value);
+    }
+
+    /**
+     * Append quoted string to mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendQuotedString(byte[] text) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Quoted-string = <Octet 34> *TEXT End-of-string
+         * ;The TEXT encodes an RFC2616 Quoted-string with the enclosing
+         * ;quotation-marks <"> removed.
+         */
+        append(QUOTED_STRING_FLAG);
+        arraycopy(text, 0, text.length);
+        append(END_STRING_FLAG);
+    }
+
+    /**
+     * Append quoted string to mMessage.
+     * This implementation doesn't check the validity of parameter, since it
+     * assumes that the values are validated in the GenericPdu setter methods.
+     */
+    @UnsupportedAppUsage
+    protected void appendQuotedString(String str) {
+        /*
+         * From WAP-230-WSP-20010705-a:
+         * Quoted-string = <Octet 34> *TEXT End-of-string
+         * ;The TEXT encodes an RFC2616 Quoted-string with the enclosing
+         * ;quotation-marks <"> removed.
+         */
+        appendQuotedString(str.getBytes());
+    }
+
+    private EncodedStringValue appendAddressType(EncodedStringValue address) {
+        EncodedStringValue temp = null;
+
+        try {
+            int addressType = checkAddressType(address.getString());
+            temp = EncodedStringValue.copy(address);
+            if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) {
+                // Phone number.
+                temp.appendTextString(STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes());
+            } else if (PDU_IPV4_ADDRESS_TYPE == addressType) {
+                // Ipv4 address.
+                temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes());
+            } else if (PDU_IPV6_ADDRESS_TYPE == addressType) {
+                // Ipv6 address.
+                temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes());
+            }
+        } catch (NullPointerException e) {
+            return null;
+        }
+
+        return temp;
+    }
+
+    /**
+     * Append header to mMessage.
+     */
+    @UnsupportedAppUsage
+    private int appendHeader(int field) {
+        switch (field) {
+            case PduHeaders.MMS_VERSION:
+                appendOctet(field);
+
+                int version = mPduHeader.getOctet(field);
+                if (0 == version) {
+                    appendShortInteger(PduHeaders.CURRENT_MMS_VERSION);
+                } else {
+                    appendShortInteger(version);
+                }
+
+                break;
+
+            case PduHeaders.MESSAGE_ID:
+            case PduHeaders.TRANSACTION_ID:
+                byte[] textString = mPduHeader.getTextString(field);
+                if (null == textString) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+                appendTextString(textString);
+                break;
+
+            case PduHeaders.TO:
+            case PduHeaders.BCC:
+            case PduHeaders.CC:
+                EncodedStringValue[] addr = mPduHeader.getEncodedStringValues(field);
+
+                if (null == addr) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                EncodedStringValue temp;
+                for (int i = 0; i < addr.length; i++) {
+                    temp = appendAddressType(addr[i]);
+                    if (temp == null) {
+                        return PDU_COMPOSE_CONTENT_ERROR;
+                    }
+
+                    appendOctet(field);
+                    appendEncodedString(temp);
+                }
+                break;
+
+            case PduHeaders.FROM:
+                // Value-length (Address-present-token Encoded-string-value | Insert-address-token)
+                appendOctet(field);
+
+                EncodedStringValue from = mPduHeader.getEncodedStringValue(field);
+                if ((from == null)
+                        || TextUtils.isEmpty(from.getString())
+                        || new String(from.getTextString()).equals(
+                                PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) {
+                    // Length of from = 1
+                    append(1);
+                    // Insert-address-token = <Octet 129>
+                    append(PduHeaders.FROM_INSERT_ADDRESS_TOKEN);
+                } else {
+                    mStack.newbuf();
+                    PositionMarker fstart = mStack.mark();
+
+                    // Address-present-token = <Octet 128>
+                    append(PduHeaders.FROM_ADDRESS_PRESENT_TOKEN);
+
+                    temp = appendAddressType(from);
+                    if (temp == null) {
+                        return PDU_COMPOSE_CONTENT_ERROR;
+                    }
+
+                    appendEncodedString(temp);
+
+                    int flen = fstart.getLength();
+                    mStack.pop();
+                    appendValueLength(flen);
+                    mStack.copy();
+                }
+                break;
+
+            case PduHeaders.READ_STATUS:
+            case PduHeaders.STATUS:
+            case PduHeaders.REPORT_ALLOWED:
+            case PduHeaders.PRIORITY:
+            case PduHeaders.DELIVERY_REPORT:
+            case PduHeaders.READ_REPORT:
+            case PduHeaders.RETRIEVE_STATUS:
+                int octet = mPduHeader.getOctet(field);
+                if (0 == octet) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+                appendOctet(octet);
+                break;
+
+            case PduHeaders.DATE:
+                long date = mPduHeader.getLongInteger(field);
+                if (-1 == date) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+                appendDateValue(date);
+                break;
+
+            case PduHeaders.SUBJECT:
+            case PduHeaders.RETRIEVE_TEXT:
+                EncodedStringValue enString =
+                    mPduHeader.getEncodedStringValue(field);
+                if (null == enString) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+                appendEncodedString(enString);
+                break;
+
+            case PduHeaders.MESSAGE_CLASS:
+                byte[] messageClass = mPduHeader.getTextString(field);
+                if (null == messageClass) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+                if (Arrays.equals(messageClass,
+                        PduHeaders.MESSAGE_CLASS_ADVERTISEMENT_STR.getBytes())) {
+                    appendOctet(PduHeaders.MESSAGE_CLASS_ADVERTISEMENT);
+                } else if (Arrays.equals(messageClass,
+                        PduHeaders.MESSAGE_CLASS_AUTO_STR.getBytes())) {
+                    appendOctet(PduHeaders.MESSAGE_CLASS_AUTO);
+                } else if (Arrays.equals(messageClass,
+                        PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes())) {
+                    appendOctet(PduHeaders.MESSAGE_CLASS_PERSONAL);
+                } else if (Arrays.equals(messageClass,
+                        PduHeaders.MESSAGE_CLASS_INFORMATIONAL_STR.getBytes())) {
+                    appendOctet(PduHeaders.MESSAGE_CLASS_INFORMATIONAL);
+                } else {
+                    appendTextString(messageClass);
+                }
+                break;
+
+            case PduHeaders.EXPIRY:
+                long expiry = mPduHeader.getLongInteger(field);
+                if (-1 == expiry) {
+                    return PDU_COMPOSE_FIELD_NOT_SET;
+                }
+
+                appendOctet(field);
+
+                mStack.newbuf();
+                PositionMarker expiryStart = mStack.mark();
+
+                append(PduHeaders.VALUE_RELATIVE_TOKEN);
+                appendLongInteger(expiry);
+
+                int expiryLength = expiryStart.getLength();
+                mStack.pop();
+                appendValueLength(expiryLength);
+                mStack.copy();
+                break;
+
+            default:
+                return PDU_COMPOSE_FIELD_NOT_SUPPORTED;
+        }
+
+        return PDU_COMPOSE_SUCCESS;
+    }
+
+    /**
+     * Make ReadRec.Ind.
+     */
+    private int makeReadRecInd() {
+        if (mMessage == null) {
+            mMessage = new ByteArrayOutputStream();
+            mPosition = 0;
+        }
+
+        // X-Mms-Message-Type
+        appendOctet(PduHeaders.MESSAGE_TYPE);
+        appendOctet(PduHeaders.MESSAGE_TYPE_READ_REC_IND);
+
+        // X-Mms-MMS-Version
+        if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // Message-ID
+        if (appendHeader(PduHeaders.MESSAGE_ID) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // To
+        if (appendHeader(PduHeaders.TO) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // From
+        if (appendHeader(PduHeaders.FROM) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // Date Optional
+        appendHeader(PduHeaders.DATE);
+
+        // X-Mms-Read-Status
+        if (appendHeader(PduHeaders.READ_STATUS) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // X-Mms-Applic-ID Optional(not support)
+        // X-Mms-Reply-Applic-ID Optional(not support)
+        // X-Mms-Aux-Applic-Info Optional(not support)
+
+        return PDU_COMPOSE_SUCCESS;
+    }
+
+    /**
+     * Make NotifyResp.Ind.
+     */
+    private int makeNotifyResp() {
+        if (mMessage == null) {
+            mMessage = new ByteArrayOutputStream();
+            mPosition = 0;
+        }
+
+        //    X-Mms-Message-Type
+        appendOctet(PduHeaders.MESSAGE_TYPE);
+        appendOctet(PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND);
+
+        // X-Mms-Transaction-ID
+        if (appendHeader(PduHeaders.TRANSACTION_ID) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // X-Mms-MMS-Version
+        if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        //  X-Mms-Status
+        if (appendHeader(PduHeaders.STATUS) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // X-Mms-Report-Allowed Optional (not support)
+        return PDU_COMPOSE_SUCCESS;
+    }
+
+    /**
+     * Make Acknowledge.Ind.
+     */
+    private int makeAckInd() {
+        if (mMessage == null) {
+            mMessage = new ByteArrayOutputStream();
+            mPosition = 0;
+        }
+
+        //    X-Mms-Message-Type
+        appendOctet(PduHeaders.MESSAGE_TYPE);
+        appendOctet(PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND);
+
+        // X-Mms-Transaction-ID
+        if (appendHeader(PduHeaders.TRANSACTION_ID) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        //     X-Mms-MMS-Version
+        if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // X-Mms-Report-Allowed Optional
+        appendHeader(PduHeaders.REPORT_ALLOWED);
+
+        return PDU_COMPOSE_SUCCESS;
+    }
+
+    /**
+     * Make Send.req.
+     */
+    private int makeSendRetrievePdu(int type) {
+        if (mMessage == null) {
+            mMessage = new ByteArrayOutputStream();
+            mPosition = 0;
+        }
+
+        // X-Mms-Message-Type
+        appendOctet(PduHeaders.MESSAGE_TYPE);
+        appendOctet(type);
+
+        // X-Mms-Transaction-ID
+        appendOctet(PduHeaders.TRANSACTION_ID);
+
+        byte[] trid = mPduHeader.getTextString(PduHeaders.TRANSACTION_ID);
+        if (trid == null) {
+            // Transaction-ID should be set(by Transaction) before make().
+            throw new IllegalArgumentException("Transaction-ID is null.");
+        }
+        appendTextString(trid);
+
+        //  X-Mms-MMS-Version
+        if (appendHeader(PduHeaders.MMS_VERSION) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // Date Date-value Optional.
+        appendHeader(PduHeaders.DATE);
+
+        // From
+        if (appendHeader(PduHeaders.FROM) != PDU_COMPOSE_SUCCESS) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        boolean recipient = false;
+
+        // To
+        if (appendHeader(PduHeaders.TO) != PDU_COMPOSE_CONTENT_ERROR) {
+            recipient = true;
+        }
+
+        // Cc
+        if (appendHeader(PduHeaders.CC) != PDU_COMPOSE_CONTENT_ERROR) {
+            recipient = true;
+        }
+
+        // Bcc
+        if (appendHeader(PduHeaders.BCC) != PDU_COMPOSE_CONTENT_ERROR) {
+            recipient = true;
+        }
+
+        // Need at least one of "cc", "bcc" and "to".
+        if (false == recipient) {
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        // Subject Optional
+        appendHeader(PduHeaders.SUBJECT);
+
+        // X-Mms-Message-Class Optional
+        // Message-class-value = Class-identifier | Token-text
+        appendHeader(PduHeaders.MESSAGE_CLASS);
+
+        // X-Mms-Expiry Optional
+        appendHeader(PduHeaders.EXPIRY);
+
+        // X-Mms-Priority Optional
+        appendHeader(PduHeaders.PRIORITY);
+
+        // X-Mms-Delivery-Report Optional
+        appendHeader(PduHeaders.DELIVERY_REPORT);
+
+        // X-Mms-Read-Report Optional
+        appendHeader(PduHeaders.READ_REPORT);
+
+        if (type == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF) {
+            // X-Mms-Retrieve-Status Optional
+            appendHeader(PduHeaders.RETRIEVE_STATUS);
+            // X-Mms-Retrieve-Text Optional
+            appendHeader(PduHeaders.RETRIEVE_TEXT);
+        }
+
+
+        //    Content-Type
+        appendOctet(PduHeaders.CONTENT_TYPE);
+
+        //  Message body
+        return makeMessageBody(type);
+    }
+
+    /**
+     * Make message body.
+     */
+    private int makeMessageBody(int type) {
+        // 1. add body informations
+        mStack.newbuf();  // Switching buffer because we need to
+
+        PositionMarker ctStart = mStack.mark();
+
+        // This contentTypeIdentifier should be used for type of attachment...
+        String contentType = new String(mPduHeader.getTextString(PduHeaders.CONTENT_TYPE));
+        Integer contentTypeIdentifier = mContentTypeMap.get(contentType);
+        if (contentTypeIdentifier == null) {
+            // content type is mandatory
+            return PDU_COMPOSE_CONTENT_ERROR;
+        }
+
+        appendShortInteger(contentTypeIdentifier.intValue());
+
+        // content-type parameter: start
+        PduBody body;
+        if (type == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF) {
+            body = ((RetrieveConf) mPdu).getBody();
+        } else {
+            body = ((SendReq) mPdu).getBody();
+        }
+        if (null == body || body.getPartsNum() == 0) {
+            // empty message
+            appendUintvarInteger(0);
+            mStack.pop();
+            mStack.copy();
+            return PDU_COMPOSE_SUCCESS;
+        }
+
+        PduPart part;
+        try {
+            part = body.getPart(0);
+
+            byte[] start = part.getContentId();
+            if (start != null) {
+                appendOctet(PduPart.P_DEP_START);
+                if (('<' == start[0]) && ('>' == start[start.length - 1])) {
+                    appendTextString(start);
+                } else {
+                    appendTextString("<" + new String(start) + ">");
+                }
+            }
+
+            // content-type parameter: type
+            appendOctet(PduPart.P_CT_MR_TYPE);
+            appendTextString(part.getContentType());
+        }
+        catch (ArrayIndexOutOfBoundsException e){
+            e.printStackTrace();
+        }
+
+        int ctLength = ctStart.getLength();
+        mStack.pop();
+        appendValueLength(ctLength);
+        mStack.copy();
+
+        // 3. add content
+        int partNum = body.getPartsNum();
+        appendUintvarInteger(partNum);
+        for (int i = 0; i < partNum; i++) {
+            part = body.getPart(i);
+            mStack.newbuf();  // Leaving space for header lengh and data length
+            PositionMarker attachment = mStack.mark();
+
+            mStack.newbuf();  // Leaving space for Content-Type length
+            PositionMarker contentTypeBegin = mStack.mark();
+
+            byte[] partContentType = part.getContentType();
+
+            if (partContentType == null) {
+                // content type is mandatory
+                return PDU_COMPOSE_CONTENT_ERROR;
+            }
+
+            // content-type value
+            Integer partContentTypeIdentifier =
+                mContentTypeMap.get(new String(partContentType));
+            if (partContentTypeIdentifier == null) {
+                appendTextString(partContentType);
+            } else {
+                appendShortInteger(partContentTypeIdentifier.intValue());
+            }
+
+            /* Content-type parameter : name.
+             * The value of name, filename, content-location is the same.
+             * Just one of them is enough for this PDU.
+             */
+            byte[] name = part.getName();
+
+            if (null == name) {
+                name = part.getFilename();
+
+                if (null == name) {
+                    name = part.getContentLocation();
+
+                    if (null == name) {
+                        /* at lease one of name, filename, Content-location
+                         * should be available.
+                         */
+                        return PDU_COMPOSE_CONTENT_ERROR;
+                    }
+                }
+            }
+            appendOctet(PduPart.P_DEP_NAME);
+            appendTextString(name);
+
+            // content-type parameter : charset
+            int charset = part.getCharset();
+            if (charset != 0) {
+                appendOctet(PduPart.P_CHARSET);
+                appendShortInteger(charset);
+            }
+
+            int contentTypeLength = contentTypeBegin.getLength();
+            mStack.pop();
+            appendValueLength(contentTypeLength);
+            mStack.copy();
+
+            // content id
+            byte[] contentId = part.getContentId();
+
+            if (null != contentId) {
+                appendOctet(PduPart.P_CONTENT_ID);
+                if (('<' == contentId[0]) && ('>' == contentId[contentId.length - 1])) {
+                    appendQuotedString(contentId);
+                } else {
+                    appendQuotedString("<" + new String(contentId) + ">");
+                }
+            }
+
+            // content-location
+            byte[] contentLocation = part.getContentLocation();
+            if (null != contentLocation) {
+            	appendOctet(PduPart.P_CONTENT_LOCATION);
+            	appendTextString(contentLocation);
+            }
+
+            // content
+            int headerLength = attachment.getLength();
+
+            int dataLength = 0; // Just for safety...
+            byte[] partData = part.getData();
+
+            if (partData != null) {
+                arraycopy(partData, 0, partData.length);
+                dataLength = partData.length;
+            } else {
+                InputStream cr = null;
+                try {
+                    byte[] buffer = new byte[PDU_COMPOSER_BLOCK_SIZE];
+                    cr = mResolver.openInputStream(part.getDataUri());
+                    int len = 0;
+                    while ((len = cr.read(buffer)) != -1) {
+                        mMessage.write(buffer, 0, len);
+                        mPosition += len;
+                        dataLength += len;
+                    }
+                } catch (FileNotFoundException e) {
+                    return PDU_COMPOSE_CONTENT_ERROR;
+                } catch (IOException e) {
+                    return PDU_COMPOSE_CONTENT_ERROR;
+                } catch (RuntimeException e) {
+                    return PDU_COMPOSE_CONTENT_ERROR;
+                } finally {
+                    if (cr != null) {
+                        try {
+                            cr.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+
+            if (dataLength != (attachment.getLength() - headerLength)) {
+                throw new RuntimeException("BUG: Length sanity check failed");
+            }
+
+            mStack.pop();
+            appendUintvarInteger(headerLength);
+            appendUintvarInteger(dataLength);
+            mStack.copy();
+        }
+
+        return PDU_COMPOSE_SUCCESS;
+    }
+
+    /**
+     *  Record current message informations.
+     */
+    static private class LengthRecordNode {
+        ByteArrayOutputStream currentMessage = null;
+        public int currentPosition = 0;
+
+        public LengthRecordNode next = null;
+    }
+
+    /**
+     * Mark current message position and stact size.
+     */
+    private class PositionMarker {
+        private int c_pos;   // Current position
+        private int currentStackSize;  // Current stack size
+
+        @UnsupportedAppUsage
+        int getLength() {
+            // If these assert fails, likely that you are finding the
+            // size of buffer that is deep in BufferStack you can only
+            // find the length of the buffer that is on top
+            if (currentStackSize != mStack.stackSize) {
+                throw new RuntimeException("BUG: Invalid call to getLength()");
+            }
+
+            return mPosition - c_pos;
+        }
+    }
+
+    /**
+     * This implementation can be OPTIMIZED to use only
+     * 2 buffers. This optimization involves changing BufferStack
+     * only... Its usage (interface) will not change.
+     */
+    private class BufferStack {
+        private LengthRecordNode stack = null;
+        private LengthRecordNode toCopy = null;
+
+        int stackSize = 0;
+
+        /**
+         *  Create a new message buffer and push it into the stack.
+         */
+        @UnsupportedAppUsage
+        void newbuf() {
+            // You can't create a new buff when toCopy != null
+            // That is after calling pop() and before calling copy()
+            // If you do, it is a bug
+            if (toCopy != null) {
+                throw new RuntimeException("BUG: Invalid newbuf() before copy()");
+            }
+
+            LengthRecordNode temp = new LengthRecordNode();
+
+            temp.currentMessage = mMessage;
+            temp.currentPosition = mPosition;
+
+            temp.next = stack;
+            stack = temp;
+
+            stackSize = stackSize + 1;
+
+            mMessage = new ByteArrayOutputStream();
+            mPosition = 0;
+        }
+
+        /**
+         *  Pop the message before and record current message in the stack.
+         */
+        @UnsupportedAppUsage
+        void pop() {
+            ByteArrayOutputStream currentMessage = mMessage;
+            int currentPosition = mPosition;
+
+            mMessage = stack.currentMessage;
+            mPosition = stack.currentPosition;
+
+            toCopy = stack;
+            // Re using the top element of the stack to avoid memory allocation
+
+            stack = stack.next;
+            stackSize = stackSize - 1;
+
+            toCopy.currentMessage = currentMessage;
+            toCopy.currentPosition = currentPosition;
+        }
+
+        /**
+         *  Append current message to the message before.
+         */
+        @UnsupportedAppUsage
+        void copy() {
+            arraycopy(toCopy.currentMessage.toByteArray(), 0,
+                    toCopy.currentPosition);
+
+            toCopy = null;
+        }
+
+        /**
+         *  Mark current message position
+         */
+        @UnsupportedAppUsage
+        PositionMarker mark() {
+            PositionMarker m = new PositionMarker();
+
+            m.c_pos = mPosition;
+            m.currentStackSize = stackSize;
+
+            return m;
+        }
+    }
+
+    /**
+     * Check address type.
+     *
+     * @param address address string without the postfix stinng type,
+     *        such as "/TYPE=PLMN", "/TYPE=IPv6" and "/TYPE=IPv4"
+     * @return PDU_PHONE_NUMBER_ADDRESS_TYPE if it is phone number,
+     *         PDU_EMAIL_ADDRESS_TYPE if it is email address,
+     *         PDU_IPV4_ADDRESS_TYPE if it is ipv4 address,
+     *         PDU_IPV6_ADDRESS_TYPE if it is ipv6 address,
+     *         PDU_UNKNOWN_ADDRESS_TYPE if it is unknown.
+     */
+    protected static int checkAddressType(String address) {
+        /**
+         * From OMA-TS-MMS-ENC-V1_3-20050927-C.pdf, section 8.
+         * address = ( e-mail / device-address / alphanum-shortcode / num-shortcode)
+         * e-mail = mailbox; to the definition of mailbox as described in
+         * section 3.4 of [RFC2822], but excluding the
+         * obsolete definitions as indicated by the "obs-" prefix.
+         * device-address = ( global-phone-number "/TYPE=PLMN" )
+         * / ( ipv4 "/TYPE=IPv4" ) / ( ipv6 "/TYPE=IPv6" )
+         * / ( escaped-value "/TYPE=" address-type )
+         *
+         * global-phone-number = ["+"] 1*( DIGIT / written-sep )
+         * written-sep =("-"/".")
+         *
+         * ipv4 = 1*3DIGIT 3( "." 1*3DIGIT ) ; IPv4 address value
+         *
+         * ipv6 = 4HEXDIG 7( ":" 4HEXDIG ) ; IPv6 address per RFC 2373
+         */
+
+        if (null == address) {
+            return PDU_UNKNOWN_ADDRESS_TYPE;
+        }
+
+        if (address.matches(REGEXP_IPV4_ADDRESS_TYPE)) {
+            // Ipv4 address.
+            return PDU_IPV4_ADDRESS_TYPE;
+        }else if (address.matches(REGEXP_PHONE_NUMBER_ADDRESS_TYPE)) {
+            // Phone number.
+            return PDU_PHONE_NUMBER_ADDRESS_TYPE;
+        } else if (address.matches(REGEXP_EMAIL_ADDRESS_TYPE)) {
+            // Email address.
+            return PDU_EMAIL_ADDRESS_TYPE;
+        } else if (address.matches(REGEXP_IPV6_ADDRESS_TYPE)) {
+            // Ipv6 address.
+            return PDU_IPV6_ADDRESS_TYPE;
+        } else {
+            // Unknown address.
+            return PDU_UNKNOWN_ADDRESS_TYPE;
+        }
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
new file mode 100644
index 0000000..8551b2f
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+public class PduContentTypes {
+    /**
+     * All content types. From:
+     * http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.htm
+     */
+    @UnsupportedAppUsage
+    static final String[] contentTypes = {
+        "*/*",                                        /* 0x00 */
+        "text/*",                                     /* 0x01 */
+        "text/html",                                  /* 0x02 */
+        "text/plain",                                 /* 0x03 */
+        "text/x-hdml",                                /* 0x04 */
+        "text/x-ttml",                                /* 0x05 */
+        "text/x-vCalendar",                           /* 0x06 */
+        "text/x-vCard",                               /* 0x07 */
+        "text/vnd.wap.wml",                           /* 0x08 */
+        "text/vnd.wap.wmlscript",                     /* 0x09 */
+        "text/vnd.wap.wta-event",                     /* 0x0A */
+        "multipart/*",                                /* 0x0B */
+        "multipart/mixed",                            /* 0x0C */
+        "multipart/form-data",                        /* 0x0D */
+        "multipart/byterantes",                       /* 0x0E */
+        "multipart/alternative",                      /* 0x0F */
+        "application/*",                              /* 0x10 */
+        "application/java-vm",                        /* 0x11 */
+        "application/x-www-form-urlencoded",          /* 0x12 */
+        "application/x-hdmlc",                        /* 0x13 */
+        "application/vnd.wap.wmlc",                   /* 0x14 */
+        "application/vnd.wap.wmlscriptc",             /* 0x15 */
+        "application/vnd.wap.wta-eventc",             /* 0x16 */
+        "application/vnd.wap.uaprof",                 /* 0x17 */
+        "application/vnd.wap.wtls-ca-certificate",    /* 0x18 */
+        "application/vnd.wap.wtls-user-certificate",  /* 0x19 */
+        "application/x-x509-ca-cert",                 /* 0x1A */
+        "application/x-x509-user-cert",               /* 0x1B */
+        "image/*",                                    /* 0x1C */
+        "image/gif",                                  /* 0x1D */
+        "image/jpeg",                                 /* 0x1E */
+        "image/tiff",                                 /* 0x1F */
+        "image/png",                                  /* 0x20 */
+        "image/vnd.wap.wbmp",                         /* 0x21 */
+        "application/vnd.wap.multipart.*",            /* 0x22 */
+        "application/vnd.wap.multipart.mixed",        /* 0x23 */
+        "application/vnd.wap.multipart.form-data",    /* 0x24 */
+        "application/vnd.wap.multipart.byteranges",   /* 0x25 */
+        "application/vnd.wap.multipart.alternative",  /* 0x26 */
+        "application/xml",                            /* 0x27 */
+        "text/xml",                                   /* 0x28 */
+        "application/vnd.wap.wbxml",                  /* 0x29 */
+        "application/x-x968-cross-cert",              /* 0x2A */
+        "application/x-x968-ca-cert",                 /* 0x2B */
+        "application/x-x968-user-cert",               /* 0x2C */
+        "text/vnd.wap.si",                            /* 0x2D */
+        "application/vnd.wap.sic",                    /* 0x2E */
+        "text/vnd.wap.sl",                            /* 0x2F */
+        "application/vnd.wap.slc",                    /* 0x30 */
+        "text/vnd.wap.co",                            /* 0x31 */
+        "application/vnd.wap.coc",                    /* 0x32 */
+        "application/vnd.wap.multipart.related",      /* 0x33 */
+        "application/vnd.wap.sia",                    /* 0x34 */
+        "text/vnd.wap.connectivity-xml",              /* 0x35 */
+        "application/vnd.wap.connectivity-wbxml",     /* 0x36 */
+        "application/pkcs7-mime",                     /* 0x37 */
+        "application/vnd.wap.hashed-certificate",     /* 0x38 */
+        "application/vnd.wap.signed-certificate",     /* 0x39 */
+        "application/vnd.wap.cert-response",          /* 0x3A */
+        "application/xhtml+xml",                      /* 0x3B */
+        "application/wml+xml",                        /* 0x3C */
+        "text/css",                                   /* 0x3D */
+        "application/vnd.wap.mms-message",            /* 0x3E */
+        "application/vnd.wap.rollover-certificate",   /* 0x3F */
+        "application/vnd.wap.locc+wbxml",             /* 0x40 */
+        "application/vnd.wap.loc+xml",                /* 0x41 */
+        "application/vnd.syncml.dm+wbxml",            /* 0x42 */
+        "application/vnd.syncml.dm+xml",              /* 0x43 */
+        "application/vnd.syncml.notification",        /* 0x44 */
+        "application/vnd.wap.xhtml+xml",              /* 0x45 */
+        "application/vnd.wv.csp.cir",                 /* 0x46 */
+        "application/vnd.oma.dd+xml",                 /* 0x47 */
+        "application/vnd.oma.drm.message",            /* 0x48 */
+        "application/vnd.oma.drm.content",            /* 0x49 */
+        "application/vnd.oma.drm.rights+xml",         /* 0x4A */
+        "application/vnd.oma.drm.rights+wbxml",       /* 0x4B */
+        "application/vnd.wv.csp+xml",                 /* 0x4C */
+        "application/vnd.wv.csp+wbxml",               /* 0x4D */
+        "application/vnd.syncml.ds.notification",     /* 0x4E */
+        "audio/*",                                    /* 0x4F */
+        "video/*",                                    /* 0x50 */
+        "application/vnd.oma.dd2+xml",                /* 0x51 */
+        "application/mikey"                           /* 0x52 */
+    };
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
new file mode 100644
index 0000000..b524464
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class PduHeaders {
+    /**
+     * All pdu header fields.
+     */
+    public static final int BCC                             = 0x81;
+    public static final int CC                              = 0x82;
+    public static final int CONTENT_LOCATION                = 0x83;
+    public static final int CONTENT_TYPE                    = 0x84;
+    public static final int DATE                            = 0x85;
+    public static final int DELIVERY_REPORT                 = 0x86;
+    public static final int DELIVERY_TIME                   = 0x87;
+    public static final int EXPIRY                          = 0x88;
+    public static final int FROM                            = 0x89;
+    public static final int MESSAGE_CLASS                   = 0x8A;
+    public static final int MESSAGE_ID                      = 0x8B;
+    public static final int MESSAGE_TYPE                    = 0x8C;
+    public static final int MMS_VERSION                     = 0x8D;
+    public static final int MESSAGE_SIZE                    = 0x8E;
+    public static final int PRIORITY                        = 0x8F;
+
+    public static final int READ_REPLY                      = 0x90;
+    public static final int READ_REPORT                     = 0x90;
+    public static final int REPORT_ALLOWED                  = 0x91;
+    public static final int RESPONSE_STATUS                 = 0x92;
+    public static final int RESPONSE_TEXT                   = 0x93;
+    public static final int SENDER_VISIBILITY               = 0x94;
+    public static final int STATUS                          = 0x95;
+    public static final int SUBJECT                         = 0x96;
+    public static final int TO                              = 0x97;
+    public static final int TRANSACTION_ID                  = 0x98;
+    public static final int RETRIEVE_STATUS                 = 0x99;
+    public static final int RETRIEVE_TEXT                   = 0x9A;
+    public static final int READ_STATUS                     = 0x9B;
+    public static final int REPLY_CHARGING                  = 0x9C;
+    public static final int REPLY_CHARGING_DEADLINE         = 0x9D;
+    public static final int REPLY_CHARGING_ID               = 0x9E;
+    public static final int REPLY_CHARGING_SIZE             = 0x9F;
+
+    public static final int PREVIOUSLY_SENT_BY              = 0xA0;
+    public static final int PREVIOUSLY_SENT_DATE            = 0xA1;
+    public static final int STORE                           = 0xA2;
+    public static final int MM_STATE                        = 0xA3;
+    public static final int MM_FLAGS                        = 0xA4;
+    public static final int STORE_STATUS                    = 0xA5;
+    public static final int STORE_STATUS_TEXT               = 0xA6;
+    public static final int STORED                          = 0xA7;
+    public static final int ATTRIBUTES                      = 0xA8;
+    public static final int TOTALS                          = 0xA9;
+    public static final int MBOX_TOTALS                     = 0xAA;
+    public static final int QUOTAS                          = 0xAB;
+    public static final int MBOX_QUOTAS                     = 0xAC;
+    public static final int MESSAGE_COUNT                   = 0xAD;
+    public static final int CONTENT                         = 0xAE;
+    public static final int START                           = 0xAF;
+
+    public static final int ADDITIONAL_HEADERS              = 0xB0;
+    public static final int DISTRIBUTION_INDICATOR          = 0xB1;
+    public static final int ELEMENT_DESCRIPTOR              = 0xB2;
+    public static final int LIMIT                           = 0xB3;
+    public static final int RECOMMENDED_RETRIEVAL_MODE      = 0xB4;
+    public static final int RECOMMENDED_RETRIEVAL_MODE_TEXT = 0xB5;
+    public static final int STATUS_TEXT                     = 0xB6;
+    public static final int APPLIC_ID                       = 0xB7;
+    public static final int REPLY_APPLIC_ID                 = 0xB8;
+    public static final int AUX_APPLIC_ID                   = 0xB9;
+    public static final int CONTENT_CLASS                   = 0xBA;
+    public static final int DRM_CONTENT                     = 0xBB;
+    public static final int ADAPTATION_ALLOWED              = 0xBC;
+    public static final int REPLACE_ID                      = 0xBD;
+    public static final int CANCEL_ID                       = 0xBE;
+    public static final int CANCEL_STATUS                   = 0xBF;
+
+    /**
+     * X-Mms-Message-Type field types.
+     */
+    public static final int MESSAGE_TYPE_SEND_REQ           = 0x80;
+    public static final int MESSAGE_TYPE_SEND_CONF          = 0x81;
+    public static final int MESSAGE_TYPE_NOTIFICATION_IND   = 0x82;
+    public static final int MESSAGE_TYPE_NOTIFYRESP_IND     = 0x83;
+    public static final int MESSAGE_TYPE_RETRIEVE_CONF      = 0x84;
+    public static final int MESSAGE_TYPE_ACKNOWLEDGE_IND    = 0x85;
+    public static final int MESSAGE_TYPE_DELIVERY_IND       = 0x86;
+    public static final int MESSAGE_TYPE_READ_REC_IND       = 0x87;
+    public static final int MESSAGE_TYPE_READ_ORIG_IND      = 0x88;
+    public static final int MESSAGE_TYPE_FORWARD_REQ        = 0x89;
+    public static final int MESSAGE_TYPE_FORWARD_CONF       = 0x8A;
+    public static final int MESSAGE_TYPE_MBOX_STORE_REQ     = 0x8B;
+    public static final int MESSAGE_TYPE_MBOX_STORE_CONF    = 0x8C;
+    public static final int MESSAGE_TYPE_MBOX_VIEW_REQ      = 0x8D;
+    public static final int MESSAGE_TYPE_MBOX_VIEW_CONF     = 0x8E;
+    public static final int MESSAGE_TYPE_MBOX_UPLOAD_REQ    = 0x8F;
+    public static final int MESSAGE_TYPE_MBOX_UPLOAD_CONF   = 0x90;
+    public static final int MESSAGE_TYPE_MBOX_DELETE_REQ    = 0x91;
+    public static final int MESSAGE_TYPE_MBOX_DELETE_CONF   = 0x92;
+    public static final int MESSAGE_TYPE_MBOX_DESCR         = 0x93;
+    public static final int MESSAGE_TYPE_DELETE_REQ         = 0x94;
+    public static final int MESSAGE_TYPE_DELETE_CONF        = 0x95;
+    public static final int MESSAGE_TYPE_CANCEL_REQ         = 0x96;
+    public static final int MESSAGE_TYPE_CANCEL_CONF        = 0x97;
+
+    /**
+     *  X-Mms-Delivery-Report |
+     *  X-Mms-Read-Report |
+     *  X-Mms-Report-Allowed |
+     *  X-Mms-Sender-Visibility |
+     *  X-Mms-Store |
+     *  X-Mms-Stored |
+     *  X-Mms-Totals |
+     *  X-Mms-Quotas |
+     *  X-Mms-Distribution-Indicator |
+     *  X-Mms-DRM-Content |
+     *  X-Mms-Adaptation-Allowed |
+     *  field types.
+     */
+    public static final int VALUE_YES                       = 0x80;
+    public static final int VALUE_NO                        = 0x81;
+
+    /**
+     *  Delivery-Time |
+     *  Expiry and Reply-Charging-Deadline |
+     *  field type components.
+     */
+    public static final int VALUE_ABSOLUTE_TOKEN            = 0x80;
+    public static final int VALUE_RELATIVE_TOKEN            = 0x81;
+
+    /**
+     * X-Mms-MMS-Version field types.
+     */
+    public static final int MMS_VERSION_1_3                 = ((1 << 4) | 3);
+    public static final int MMS_VERSION_1_2                 = ((1 << 4) | 2);
+    public static final int MMS_VERSION_1_1                 = ((1 << 4) | 1);
+    public static final int MMS_VERSION_1_0                 = ((1 << 4) | 0);
+
+    // Current version is 1.2.
+    public static final int CURRENT_MMS_VERSION             = MMS_VERSION_1_2;
+
+    /**
+     *  From field type components.
+     */
+    public static final int FROM_ADDRESS_PRESENT_TOKEN      = 0x80;
+    public static final int FROM_INSERT_ADDRESS_TOKEN       = 0x81;
+
+    public static final String FROM_ADDRESS_PRESENT_TOKEN_STR = "address-present-token";
+    public static final String FROM_INSERT_ADDRESS_TOKEN_STR = "insert-address-token";
+
+    /**
+     *  X-Mms-Status Field.
+     */
+    public static final int STATUS_EXPIRED                  = 0x80;
+    public static final int STATUS_RETRIEVED                = 0x81;
+    public static final int STATUS_REJECTED                 = 0x82;
+    public static final int STATUS_DEFERRED                 = 0x83;
+    public static final int STATUS_UNRECOGNIZED             = 0x84;
+    public static final int STATUS_INDETERMINATE            = 0x85;
+    public static final int STATUS_FORWARDED                = 0x86;
+    public static final int STATUS_UNREACHABLE              = 0x87;
+
+    /**
+     *  MM-Flags field type components.
+     */
+    public static final int MM_FLAGS_ADD_TOKEN              = 0x80;
+    public static final int MM_FLAGS_REMOVE_TOKEN           = 0x81;
+    public static final int MM_FLAGS_FILTER_TOKEN           = 0x82;
+
+    /**
+     *  X-Mms-Message-Class field types.
+     */
+    public static final int MESSAGE_CLASS_PERSONAL          = 0x80;
+    public static final int MESSAGE_CLASS_ADVERTISEMENT     = 0x81;
+    public static final int MESSAGE_CLASS_INFORMATIONAL     = 0x82;
+    public static final int MESSAGE_CLASS_AUTO              = 0x83;
+
+    public static final String MESSAGE_CLASS_PERSONAL_STR = "personal";
+    public static final String MESSAGE_CLASS_ADVERTISEMENT_STR = "advertisement";
+    public static final String MESSAGE_CLASS_INFORMATIONAL_STR = "informational";
+    public static final String MESSAGE_CLASS_AUTO_STR = "auto";
+
+    /**
+     *  X-Mms-Priority field types.
+     */
+    public static final int PRIORITY_LOW                    = 0x80;
+    public static final int PRIORITY_NORMAL                 = 0x81;
+    public static final int PRIORITY_HIGH                   = 0x82;
+
+    /**
+     *  X-Mms-Response-Status field types.
+     */
+    public static final int RESPONSE_STATUS_OK                   = 0x80;
+    public static final int RESPONSE_STATUS_ERROR_UNSPECIFIED    = 0x81;
+    public static final int RESPONSE_STATUS_ERROR_SERVICE_DENIED = 0x82;
+
+    public static final int RESPONSE_STATUS_ERROR_MESSAGE_FORMAT_CORRUPT     = 0x83;
+    public static final int RESPONSE_STATUS_ERROR_SENDING_ADDRESS_UNRESOLVED = 0x84;
+
+    public static final int RESPONSE_STATUS_ERROR_MESSAGE_NOT_FOUND    = 0x85;
+    public static final int RESPONSE_STATUS_ERROR_NETWORK_PROBLEM      = 0x86;
+    public static final int RESPONSE_STATUS_ERROR_CONTENT_NOT_ACCEPTED = 0x87;
+    public static final int RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE  = 0x88;
+    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE    = 0xC0;
+
+    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_SENDNG_ADDRESS_UNRESOLVED = 0xC1;
+    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND         = 0xC2;
+    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM           = 0xC3;
+    public static final int RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS           = 0xC4;
+
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_FAILURE                             = 0xE0;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_SERVICE_DENIED                      = 0xE1;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT              = 0xE2;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED          = 0xE3;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND                   = 0xE4;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_CONTENT_NOT_ACCEPTED                = 0xE5;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_LIMITATIONS_NOT_MET  = 0xE6;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_REQUEST_NOT_ACCEPTED = 0xE6;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_FORWARDING_DENIED    = 0xE8;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_REPLY_CHARGING_NOT_SUPPORTED        = 0xE9;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_ADDRESS_HIDING_NOT_SUPPORTED        = 0xEA;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID                     = 0xEB;
+    public static final int RESPONSE_STATUS_ERROR_PERMANENT_END                                 = 0xFF;
+
+    /**
+     *  X-Mms-Retrieve-Status field types.
+     */
+    public static final int RETRIEVE_STATUS_OK                                  = 0x80;
+    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE             = 0xC0;
+    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_MESSAGE_NOT_FOUND   = 0xC1;
+    public static final int RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM     = 0xC2;
+    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE             = 0xE0;
+    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_SERVICE_DENIED      = 0xE1;
+    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND   = 0xE2;
+    public static final int RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 0xE3;
+    public static final int RETRIEVE_STATUS_ERROR_END                           = 0xFF;
+
+    /**
+     *  X-Mms-Sender-Visibility field types.
+     */
+    public static final int SENDER_VISIBILITY_HIDE          = 0x80;
+    public static final int SENDER_VISIBILITY_SHOW          = 0x81;
+
+    /**
+     *  X-Mms-Read-Status field types.
+     */
+    public static final int READ_STATUS_READ                        = 0x80;
+    public static final int READ_STATUS__DELETED_WITHOUT_BEING_READ = 0x81;
+
+    /**
+     *  X-Mms-Cancel-Status field types.
+     */
+    public static final int CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED = 0x80;
+    public static final int CANCEL_STATUS_REQUEST_CORRUPTED             = 0x81;
+
+    /**
+     *  X-Mms-Reply-Charging field types.
+     */
+    public static final int REPLY_CHARGING_REQUESTED           = 0x80;
+    public static final int REPLY_CHARGING_REQUESTED_TEXT_ONLY = 0x81;
+    public static final int REPLY_CHARGING_ACCEPTED            = 0x82;
+    public static final int REPLY_CHARGING_ACCEPTED_TEXT_ONLY  = 0x83;
+
+    /**
+     *  X-Mms-MM-State field types.
+     */
+    public static final int MM_STATE_DRAFT                  = 0x80;
+    public static final int MM_STATE_SENT                   = 0x81;
+    public static final int MM_STATE_NEW                    = 0x82;
+    public static final int MM_STATE_RETRIEVED              = 0x83;
+    public static final int MM_STATE_FORWARDED              = 0x84;
+
+    /**
+     * X-Mms-Recommended-Retrieval-Mode field types.
+     */
+    public static final int RECOMMENDED_RETRIEVAL_MODE_MANUAL = 0x80;
+
+    /**
+     *  X-Mms-Content-Class field types.
+     */
+    public static final int CONTENT_CLASS_TEXT              = 0x80;
+    public static final int CONTENT_CLASS_IMAGE_BASIC       = 0x81;
+    public static final int CONTENT_CLASS_IMAGE_RICH        = 0x82;
+    public static final int CONTENT_CLASS_VIDEO_BASIC       = 0x83;
+    public static final int CONTENT_CLASS_VIDEO_RICH        = 0x84;
+    public static final int CONTENT_CLASS_MEGAPIXEL         = 0x85;
+    public static final int CONTENT_CLASS_CONTENT_BASIC     = 0x86;
+    public static final int CONTENT_CLASS_CONTENT_RICH      = 0x87;
+
+    /**
+     *  X-Mms-Store-Status field types.
+     */
+    public static final int STORE_STATUS_SUCCESS                                = 0x80;
+    public static final int STORE_STATUS_ERROR_TRANSIENT_FAILURE                = 0xC0;
+    public static final int STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM        = 0xC1;
+    public static final int STORE_STATUS_ERROR_PERMANENT_FAILURE                = 0xE0;
+    public static final int STORE_STATUS_ERROR_PERMANENT_SERVICE_DENIED         = 0xE1;
+    public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_FORMAT_CORRUPT = 0xE2;
+    public static final int STORE_STATUS_ERROR_PERMANENT_MESSAGE_NOT_FOUND      = 0xE3;
+    public static final int STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL             = 0xE4;
+    public static final int STORE_STATUS_ERROR_END                              = 0xFF;
+
+    /**
+     * The map contains the value of all headers.
+     */
+    private HashMap<Integer, Object> mHeaderMap = null;
+
+    /**
+     * Constructor of PduHeaders.
+     */
+    @UnsupportedAppUsage
+    public PduHeaders() {
+        mHeaderMap = new HashMap<Integer, Object>();
+    }
+
+    /**
+     * Get octet value by header field.
+     *
+     * @param field the field
+     * @return the octet value of the pdu header
+     *          with specified header field. Return 0 if
+     *          the value is not set.
+     */
+    @UnsupportedAppUsage
+    protected int getOctet(int field) {
+        Integer octet = (Integer) mHeaderMap.get(field);
+        if (null == octet) {
+            return 0;
+        }
+
+        return octet;
+    }
+
+    /**
+     * Set octet value to pdu header by header field.
+     *
+     * @param value the value
+     * @param field the field
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    protected void setOctet(int value, int field)
+            throws InvalidHeaderValueException{
+        /**
+         * Check whether this field can be set for specific
+         * header and check validity of the field.
+         */
+        switch (field) {
+            case REPORT_ALLOWED:
+            case ADAPTATION_ALLOWED:
+            case DELIVERY_REPORT:
+            case DRM_CONTENT:
+            case DISTRIBUTION_INDICATOR:
+            case QUOTAS:
+            case READ_REPORT:
+            case STORE:
+            case STORED:
+            case TOTALS:
+            case SENDER_VISIBILITY:
+                if ((VALUE_YES != value) && (VALUE_NO != value)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case READ_STATUS:
+                if ((READ_STATUS_READ != value) &&
+                        (READ_STATUS__DELETED_WITHOUT_BEING_READ != value)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case CANCEL_STATUS:
+                if ((CANCEL_STATUS_REQUEST_SUCCESSFULLY_RECEIVED != value) &&
+                        (CANCEL_STATUS_REQUEST_CORRUPTED != value)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case PRIORITY:
+                if ((value < PRIORITY_LOW) || (value > PRIORITY_HIGH)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case STATUS:
+                if ((value < STATUS_EXPIRED) || (value > STATUS_UNREACHABLE)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case REPLY_CHARGING:
+                if ((value < REPLY_CHARGING_REQUESTED)
+                        || (value > REPLY_CHARGING_ACCEPTED_TEXT_ONLY)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case MM_STATE:
+                if ((value < MM_STATE_DRAFT) || (value > MM_STATE_FORWARDED)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case RECOMMENDED_RETRIEVAL_MODE:
+                if (RECOMMENDED_RETRIEVAL_MODE_MANUAL != value) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case CONTENT_CLASS:
+                if ((value < CONTENT_CLASS_TEXT)
+                        || (value > CONTENT_CLASS_CONTENT_RICH)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            case RETRIEVE_STATUS:
+                // According to oma-ts-mms-enc-v1_3, section 7.3.50, we modify the invalid value.
+                if ((value > RETRIEVE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) &&
+                        (value < RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE)) {
+                    value = RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE;
+                } else if ((value > RETRIEVE_STATUS_ERROR_PERMANENT_CONTENT_UNSUPPORTED) &&
+                        (value <= RETRIEVE_STATUS_ERROR_END)) {
+                    value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE;
+                } else if ((value < RETRIEVE_STATUS_OK) ||
+                        ((value > RETRIEVE_STATUS_OK) &&
+                                (value < RETRIEVE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
+                                (value > RETRIEVE_STATUS_ERROR_END)) {
+                    value = RETRIEVE_STATUS_ERROR_PERMANENT_FAILURE;
+                }
+                break;
+            case STORE_STATUS:
+                // According to oma-ts-mms-enc-v1_3, section 7.3.58, we modify the invalid value.
+                if ((value > STORE_STATUS_ERROR_TRANSIENT_NETWORK_PROBLEM) &&
+                        (value < STORE_STATUS_ERROR_PERMANENT_FAILURE)) {
+                    value = STORE_STATUS_ERROR_TRANSIENT_FAILURE;
+                } else if ((value > STORE_STATUS_ERROR_PERMANENT_MMBOX_FULL) &&
+                        (value <= STORE_STATUS_ERROR_END)) {
+                    value = STORE_STATUS_ERROR_PERMANENT_FAILURE;
+                } else if ((value < STORE_STATUS_SUCCESS) ||
+                        ((value > STORE_STATUS_SUCCESS) &&
+                                (value < STORE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
+                                (value > STORE_STATUS_ERROR_END)) {
+                    value = STORE_STATUS_ERROR_PERMANENT_FAILURE;
+                }
+                break;
+            case RESPONSE_STATUS:
+                // According to oma-ts-mms-enc-v1_3, section 7.3.48, we modify the invalid value.
+                if ((value > RESPONSE_STATUS_ERROR_TRANSIENT_PARTIAL_SUCCESS) &&
+                        (value < RESPONSE_STATUS_ERROR_PERMANENT_FAILURE)) {
+                    value = RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE;
+                } else if (((value > RESPONSE_STATUS_ERROR_PERMANENT_LACK_OF_PREPAID) &&
+                        (value <= RESPONSE_STATUS_ERROR_PERMANENT_END)) ||
+                        (value < RESPONSE_STATUS_OK) ||
+                        ((value > RESPONSE_STATUS_ERROR_UNSUPPORTED_MESSAGE) &&
+                                (value < RESPONSE_STATUS_ERROR_TRANSIENT_FAILURE)) ||
+                                (value > RESPONSE_STATUS_ERROR_PERMANENT_END)) {
+                    value = RESPONSE_STATUS_ERROR_PERMANENT_FAILURE;
+                }
+                break;
+            case MMS_VERSION:
+                if ((value < MMS_VERSION_1_0)|| (value > MMS_VERSION_1_3)) {
+                    value = CURRENT_MMS_VERSION; // Current version is the default value.
+                }
+                break;
+            case MESSAGE_TYPE:
+                if ((value < MESSAGE_TYPE_SEND_REQ) || (value > MESSAGE_TYPE_CANCEL_CONF)) {
+                    // Invalid value.
+                    throw new InvalidHeaderValueException("Invalid Octet value!");
+                }
+                break;
+            default:
+                // This header value should not be Octect.
+                throw new RuntimeException("Invalid header field!");
+        }
+        mHeaderMap.put(field, value);
+    }
+
+    /**
+     * Get TextString value by header field.
+     *
+     * @param field the field
+     * @return the TextString value of the pdu header
+     *          with specified header field
+     */
+    @UnsupportedAppUsage
+    protected byte[] getTextString(int field) {
+        return (byte[]) mHeaderMap.get(field);
+    }
+
+    /**
+     * Set TextString value to pdu header by header field.
+     *
+     * @param value the value
+     * @param field the field
+     * @return the TextString value of the pdu header
+     *          with specified header field
+     * @throws NullPointerException if the value is null.
+     */
+    protected void setTextString(byte[] value, int field) {
+        /**
+         * Check whether this field can be set for specific
+         * header and check validity of the field.
+         */
+        if (null == value) {
+            throw new NullPointerException();
+        }
+
+        switch (field) {
+            case TRANSACTION_ID:
+            case REPLY_CHARGING_ID:
+            case AUX_APPLIC_ID:
+            case APPLIC_ID:
+            case REPLY_APPLIC_ID:
+            case MESSAGE_ID:
+            case REPLACE_ID:
+            case CANCEL_ID:
+            case CONTENT_LOCATION:
+            case MESSAGE_CLASS:
+            case CONTENT_TYPE:
+                break;
+            default:
+                // This header value should not be Text-String.
+                throw new RuntimeException("Invalid header field!");
+        }
+        mHeaderMap.put(field, value);
+    }
+
+    /**
+     * Get EncodedStringValue value by header field.
+     *
+     * @param field the field
+     * @return the EncodedStringValue value of the pdu header
+     *          with specified header field
+     */
+    @UnsupportedAppUsage
+    protected EncodedStringValue getEncodedStringValue(int field) {
+        return (EncodedStringValue) mHeaderMap.get(field);
+    }
+
+    /**
+     * Get TO, CC or BCC header value.
+     *
+     * @param field the field
+     * @return the EncodeStringValue array of the pdu header
+     *          with specified header field
+     */
+    @UnsupportedAppUsage
+    protected EncodedStringValue[] getEncodedStringValues(int field) {
+        ArrayList<EncodedStringValue> list =
+                (ArrayList<EncodedStringValue>) mHeaderMap.get(field);
+        if (null == list) {
+            return null;
+        }
+        EncodedStringValue[] values = new EncodedStringValue[list.size()];
+        return list.toArray(values);
+    }
+
+    /**
+     * Set EncodedStringValue value to pdu header by header field.
+     *
+     * @param value the value
+     * @param field the field
+     * @return the EncodedStringValue value of the pdu header
+     *          with specified header field
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    protected void setEncodedStringValue(EncodedStringValue value, int field) {
+        /**
+         * Check whether this field can be set for specific
+         * header and check validity of the field.
+         */
+        if (null == value) {
+            throw new NullPointerException();
+        }
+
+        switch (field) {
+            case SUBJECT:
+            case RECOMMENDED_RETRIEVAL_MODE_TEXT:
+            case RETRIEVE_TEXT:
+            case STATUS_TEXT:
+            case STORE_STATUS_TEXT:
+            case RESPONSE_TEXT:
+            case FROM:
+            case PREVIOUSLY_SENT_BY:
+            case MM_FLAGS:
+                break;
+            default:
+                // This header value should not be Encoded-String-Value.
+                throw new RuntimeException("Invalid header field!");
+        }
+
+        mHeaderMap.put(field, value);
+    }
+
+    /**
+     * Set TO, CC or BCC header value.
+     *
+     * @param value the value
+     * @param field the field
+     * @return the EncodedStringValue value array of the pdu header
+     *          with specified header field
+     * @throws NullPointerException if the value is null.
+     */
+    protected void setEncodedStringValues(EncodedStringValue[] value, int field) {
+        /**
+         * Check whether this field can be set for specific
+         * header and check validity of the field.
+         */
+        if (null == value) {
+            throw new NullPointerException();
+        }
+
+        switch (field) {
+            case BCC:
+            case CC:
+            case TO:
+                break;
+            default:
+                // This header value should not be Encoded-String-Value.
+                throw new RuntimeException("Invalid header field!");
+        }
+
+        ArrayList<EncodedStringValue> list = new ArrayList<EncodedStringValue>();
+        for (int i = 0; i < value.length; i++) {
+            list.add(value[i]);
+        }
+        mHeaderMap.put(field, list);
+    }
+
+    /**
+     * Append one EncodedStringValue to another.
+     *
+     * @param value the EncodedStringValue to append
+     * @param field the field
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    protected void appendEncodedStringValue(EncodedStringValue value,
+                                    int field) {
+        if (null == value) {
+            throw new NullPointerException();
+        }
+
+        switch (field) {
+            case BCC:
+            case CC:
+            case TO:
+                break;
+            default:
+                throw new RuntimeException("Invalid header field!");
+        }
+
+        ArrayList<EncodedStringValue> list =
+            (ArrayList<EncodedStringValue>) mHeaderMap.get(field);
+        if (null == list) {
+            list  = new ArrayList<EncodedStringValue>();
+        }
+        list.add(value);
+        mHeaderMap.put(field, list);
+    }
+
+    /**
+     * Get LongInteger value by header field.
+     *
+     * @param field the field
+     * @return the LongInteger value of the pdu header
+     *          with specified header field. if return -1, the
+     *          field is not existed in pdu header.
+     */
+    @UnsupportedAppUsage
+    protected long getLongInteger(int field) {
+        Long longInteger = (Long) mHeaderMap.get(field);
+        if (null == longInteger) {
+            return -1;
+        }
+
+        return longInteger.longValue();
+    }
+
+    /**
+     * Set LongInteger value to pdu header by header field.
+     *
+     * @param value the value
+     * @param field the field
+     */
+    @UnsupportedAppUsage
+    protected void setLongInteger(long value, int field) {
+        /**
+         * Check whether this field can be set for specific
+         * header and check validity of the field.
+         */
+        switch (field) {
+            case DATE:
+            case REPLY_CHARGING_SIZE:
+            case MESSAGE_SIZE:
+            case MESSAGE_COUNT:
+            case START:
+            case LIMIT:
+            case DELIVERY_TIME:
+            case EXPIRY:
+            case REPLY_CHARGING_DEADLINE:
+            case PREVIOUSLY_SENT_DATE:
+                break;
+            default:
+                // This header value should not be LongInteger.
+                throw new RuntimeException("Invalid header field!");
+        }
+        mHeaderMap.put(field, value);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
new file mode 100755
index 0000000..f483994
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -0,0 +1,2023 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.ContentType;
+import com.google.android.mms.InvalidHeaderValueException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class PduParser {
+    /**
+     *  The next are WAP values defined in WSP specification.
+     */
+    private static final int QUOTE = 127;
+    private static final int LENGTH_QUOTE = 31;
+    private static final int TEXT_MIN = 32;
+    private static final int TEXT_MAX = 127;
+    private static final int SHORT_INTEGER_MAX = 127;
+    private static final int SHORT_LENGTH_MAX = 30;
+    private static final int LONG_INTEGER_LENGTH_MAX = 8;
+    private static final int QUOTED_STRING_FLAG = 34;
+    private static final int END_STRING_FLAG = 0x00;
+    //The next two are used by the interface "parseWapString" to
+    //distinguish Text-String and Quoted-String.
+    private static final int TYPE_TEXT_STRING = 0;
+    private static final int TYPE_QUOTED_STRING = 1;
+    private static final int TYPE_TOKEN_STRING = 2;
+
+    /**
+     * Specify the part position.
+     */
+    private static final int THE_FIRST_PART = 0;
+    private static final int THE_LAST_PART = 1;
+
+    /**
+     * The pdu data.
+     */
+    private ByteArrayInputStream mPduDataStream = null;
+
+    /**
+     * Store pdu headers
+     */
+    private PduHeaders mHeaders = null;
+
+    /**
+     * Store pdu parts.
+     */
+    private PduBody mBody = null;
+
+    /**
+     * Store the "type" parameter in "Content-Type" header field.
+     */
+    private static byte[] mTypeParam = null;
+
+    /**
+     * Store the "start" parameter in "Content-Type" header field.
+     */
+    private static byte[] mStartParam = null;
+
+    /**
+     * The log tag.
+     */
+    private static final String LOG_TAG = "PduParser";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = false;
+
+    /**
+     * Whether to parse content-disposition part header
+     */
+    private final boolean mParseContentDisposition;
+
+    /**
+     * Constructor.
+     *
+     * @param pduDataStream pdu data to be parsed
+     * @param parseContentDisposition whether to parse the Content-Disposition part header
+     */
+    @UnsupportedAppUsage
+    public PduParser(byte[] pduDataStream, boolean parseContentDisposition) {
+        mPduDataStream = new ByteArrayInputStream(pduDataStream);
+        mParseContentDisposition = parseContentDisposition;
+    }
+
+    /**
+     * Parse the pdu.
+     *
+     * @return the pdu structure if parsing successfully.
+     *         null if parsing error happened or mandatory fields are not set.
+     */
+    @UnsupportedAppUsage
+    public GenericPdu parse(){
+        if (mPduDataStream == null) {
+            return null;
+        }
+
+        /* parse headers */
+        mHeaders = parseHeaders(mPduDataStream);
+        if (null == mHeaders) {
+            // Parse headers failed.
+            return null;
+        }
+
+        /* get the message type */
+        int messageType = mHeaders.getOctet(PduHeaders.MESSAGE_TYPE);
+
+        /* check mandatory header fields */
+        if (false == checkMandatoryHeader(mHeaders)) {
+            log("check mandatory headers failed!");
+            return null;
+        }
+
+        if ((PduHeaders.MESSAGE_TYPE_SEND_REQ == messageType) ||
+                (PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF == messageType)) {
+            /* need to parse the parts */
+            mBody = parseParts(mPduDataStream);
+            if (null == mBody) {
+                // Parse parts failed.
+                return null;
+            }
+        }
+
+        switch (messageType) {
+            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_SEND_REQ");
+                }
+                SendReq sendReq = new SendReq(mHeaders, mBody);
+                return sendReq;
+            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_SEND_CONF");
+                }
+                SendConf sendConf = new SendConf(mHeaders);
+                return sendConf;
+            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_NOTIFICATION_IND");
+                }
+                NotificationInd notificationInd =
+                    new NotificationInd(mHeaders);
+                return notificationInd;
+            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_NOTIFYRESP_IND");
+                }
+                NotifyRespInd notifyRespInd =
+                    new NotifyRespInd(mHeaders);
+                return notifyRespInd;
+            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_RETRIEVE_CONF");
+                }
+                RetrieveConf retrieveConf =
+                    new RetrieveConf(mHeaders, mBody);
+
+                byte[] contentType = retrieveConf.getContentType();
+                if (null == contentType) {
+                    return null;
+                }
+                String ctTypeStr = new String(contentType);
+                if (ctTypeStr.equals(ContentType.MULTIPART_MIXED)
+                        || ctTypeStr.equals(ContentType.MULTIPART_RELATED)
+                        || ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
+                    // The MMS content type must be "application/vnd.wap.multipart.mixed"
+                    // or "application/vnd.wap.multipart.related"
+                    // or "application/vnd.wap.multipart.alternative"
+                    return retrieveConf;
+                } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) {
+                    // "application/vnd.wap.multipart.alternative"
+                    // should take only the first part.
+                    PduPart firstPart = mBody.getPart(0);
+                    mBody.removeAll();
+                    mBody.addPart(0, firstPart);
+                    return retrieveConf;
+                }
+                return null;
+            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_DELIVERY_IND");
+                }
+                DeliveryInd deliveryInd =
+                    new DeliveryInd(mHeaders);
+                return deliveryInd;
+            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_ACKNOWLEDGE_IND");
+                }
+                AcknowledgeInd acknowledgeInd =
+                    new AcknowledgeInd(mHeaders);
+                return acknowledgeInd;
+            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_READ_ORIG_IND");
+                }
+                ReadOrigInd readOrigInd =
+                    new ReadOrigInd(mHeaders);
+                return readOrigInd;
+            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "parse: MESSAGE_TYPE_READ_REC_IND");
+                }
+                ReadRecInd readRecInd =
+                    new ReadRecInd(mHeaders);
+                return readRecInd;
+            default:
+                log("Parser doesn't support this message type in this version!");
+            return null;
+        }
+    }
+
+    /**
+     * Parse pdu headers.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return headers in PduHeaders structure, null when parse fail
+     */
+    protected PduHeaders parseHeaders(ByteArrayInputStream pduDataStream){
+        if (pduDataStream == null) {
+            return null;
+        }
+        boolean keepParsing = true;
+        PduHeaders headers = new PduHeaders();
+
+        while (keepParsing && (pduDataStream.available() > 0)) {
+            pduDataStream.mark(1);
+            int headerField = extractByteValue(pduDataStream);
+            /* parse custom text header */
+            if ((headerField >= TEXT_MIN) && (headerField <= TEXT_MAX)) {
+                pduDataStream.reset();
+                byte [] bVal = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "TextHeader: " + new String(bVal));
+                }
+                /* we should ignore it at the moment */
+                continue;
+            }
+            switch (headerField) {
+                case PduHeaders.MESSAGE_TYPE:
+                {
+                    int messageType = extractByteValue(pduDataStream);
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: messageType: " + messageType);
+                    }
+                    switch (messageType) {
+                        // We don't support these kind of messages now.
+                        case PduHeaders.MESSAGE_TYPE_FORWARD_REQ:
+                        case PduHeaders.MESSAGE_TYPE_FORWARD_CONF:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF:
+                        case PduHeaders.MESSAGE_TYPE_MBOX_DESCR:
+                        case PduHeaders.MESSAGE_TYPE_DELETE_REQ:
+                        case PduHeaders.MESSAGE_TYPE_DELETE_CONF:
+                        case PduHeaders.MESSAGE_TYPE_CANCEL_REQ:
+                        case PduHeaders.MESSAGE_TYPE_CANCEL_CONF:
+                            return null;
+                    }
+                    try {
+                        headers.setOctet(messageType, headerField);
+                    } catch(InvalidHeaderValueException e) {
+                        log("Set invalid Octet value: " + messageType +
+                                " into the header filed: " + headerField);
+                        return null;
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Octet header field!");
+                        return null;
+                    }
+                    break;
+                }
+                /* Octect value */
+                case PduHeaders.REPORT_ALLOWED:
+                case PduHeaders.ADAPTATION_ALLOWED:
+                case PduHeaders.DELIVERY_REPORT:
+                case PduHeaders.DRM_CONTENT:
+                case PduHeaders.DISTRIBUTION_INDICATOR:
+                case PduHeaders.QUOTAS:
+                case PduHeaders.READ_REPORT:
+                case PduHeaders.STORE:
+                case PduHeaders.STORED:
+                case PduHeaders.TOTALS:
+                case PduHeaders.SENDER_VISIBILITY:
+                case PduHeaders.READ_STATUS:
+                case PduHeaders.CANCEL_STATUS:
+                case PduHeaders.PRIORITY:
+                case PduHeaders.STATUS:
+                case PduHeaders.REPLY_CHARGING:
+                case PduHeaders.MM_STATE:
+                case PduHeaders.RECOMMENDED_RETRIEVAL_MODE:
+                case PduHeaders.CONTENT_CLASS:
+                case PduHeaders.RETRIEVE_STATUS:
+                case PduHeaders.STORE_STATUS:
+                    /**
+                     * The following field has a different value when
+                     * used in the M-Mbox-Delete.conf and M-Delete.conf PDU.
+                     * For now we ignore this fact, since we do not support these PDUs
+                     */
+                case PduHeaders.RESPONSE_STATUS:
+                {
+                    int value = extractByteValue(pduDataStream);
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: byte: " + headerField + " value: " +
+                                value);
+                    }
+
+                    try {
+                        headers.setOctet(value, headerField);
+                    } catch(InvalidHeaderValueException e) {
+                        log("Set invalid Octet value: " + value +
+                                " into the header filed: " + headerField);
+                        return null;
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Octet header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                /* Long-Integer */
+                case PduHeaders.DATE:
+                case PduHeaders.REPLY_CHARGING_SIZE:
+                case PduHeaders.MESSAGE_SIZE:
+                {
+                    try {
+                        long value = parseLongInteger(pduDataStream);
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: longint: " + headerField + " value: " +
+                                    value);
+                        }
+                        headers.setLongInteger(value, headerField);
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Long-Integer header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                /* Integer-Value */
+                case PduHeaders.MESSAGE_COUNT:
+                case PduHeaders.START:
+                case PduHeaders.LIMIT:
+                {
+                    try {
+                        long value = parseIntegerValue(pduDataStream);
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: int: " + headerField + " value: " +
+                                    value);
+                        }
+                        headers.setLongInteger(value, headerField);
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Long-Integer header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                /* Text-String */
+                case PduHeaders.TRANSACTION_ID:
+                case PduHeaders.REPLY_CHARGING_ID:
+                case PduHeaders.AUX_APPLIC_ID:
+                case PduHeaders.APPLIC_ID:
+                case PduHeaders.REPLY_APPLIC_ID:
+                    /**
+                     * The next three header fields are email addresses
+                     * as defined in RFC2822,
+                     * not including the characters "<" and ">"
+                     */
+                case PduHeaders.MESSAGE_ID:
+                case PduHeaders.REPLACE_ID:
+                case PduHeaders.CANCEL_ID:
+                    /**
+                     * The following field has a different value when
+                     * used in the M-Mbox-Delete.conf and M-Delete.conf PDU.
+                     * For now we ignore this fact, since we do not support these PDUs
+                     */
+                case PduHeaders.CONTENT_LOCATION:
+                {
+                    byte[] value = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                    if (null != value) {
+                        try {
+                            if (LOCAL_LOGV) {
+                                Log.v(LOG_TAG, "parseHeaders: string: " + headerField + " value: " +
+                                        new String(value));
+                            }
+                            headers.setTextString(value, headerField);
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch(RuntimeException e) {
+                            log(headerField + "is not Text-String header field!");
+                            return null;
+                        }
+                    }
+                    break;
+                }
+
+                /* Encoded-string-value */
+                case PduHeaders.SUBJECT:
+                case PduHeaders.RECOMMENDED_RETRIEVAL_MODE_TEXT:
+                case PduHeaders.RETRIEVE_TEXT:
+                case PduHeaders.STATUS_TEXT:
+                case PduHeaders.STORE_STATUS_TEXT:
+                    /* the next one is not support
+                     * M-Mbox-Delete.conf and M-Delete.conf now */
+                case PduHeaders.RESPONSE_TEXT:
+                {
+                    EncodedStringValue value =
+                        parseEncodedStringValue(pduDataStream);
+                    if (null != value) {
+                        try {
+                            if (LOCAL_LOGV) {
+                                Log.v(LOG_TAG, "parseHeaders: encoded string: " + headerField
+                                        + " value: " + value.getString());
+                            }
+                            headers.setEncodedStringValue(value, headerField);
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch (RuntimeException e) {
+                            log(headerField + "is not Encoded-String-Value header field!");
+                            return null;
+                        }
+                    }
+                    break;
+                }
+
+                /* Addressing model */
+                case PduHeaders.BCC:
+                case PduHeaders.CC:
+                case PduHeaders.TO:
+                {
+                    EncodedStringValue value =
+                        parseEncodedStringValue(pduDataStream);
+                    if (null != value) {
+                        byte[] address = value.getTextString();
+                        if (null != address) {
+                            String str = new String(address);
+                            if (LOCAL_LOGV) {
+                                Log.v(LOG_TAG, "parseHeaders: (to/cc/bcc) address: " + headerField
+                                        + " value: " + str);
+                            }
+                            int endIndex = str.indexOf("/");
+                            if (endIndex > 0) {
+                                str = str.substring(0, endIndex);
+                            }
+                            try {
+                                value.setTextString(str.getBytes());
+                            } catch(NullPointerException e) {
+                                log("null pointer error!");
+                                return null;
+                            }
+                        }
+
+                        try {
+                            headers.appendEncodedStringValue(value, headerField);
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch(RuntimeException e) {
+                            log(headerField + "is not Encoded-String-Value header field!");
+                            return null;
+                        }
+                    }
+                    break;
+                }
+
+                /* Value-length
+                 * (Absolute-token Date-value | Relative-token Delta-seconds-value) */
+                case PduHeaders.DELIVERY_TIME:
+                case PduHeaders.EXPIRY:
+                case PduHeaders.REPLY_CHARGING_DEADLINE:
+                {
+                    /* parse Value-length */
+                    parseValueLength(pduDataStream);
+
+                    /* Absolute-token or Relative-token */
+                    int token = extractByteValue(pduDataStream);
+
+                    /* Date-value or Delta-seconds-value */
+                    long timeValue;
+                    try {
+                        timeValue = parseLongInteger(pduDataStream);
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Long-Integer header field!");
+                        return null;
+                    }
+                    if (PduHeaders.VALUE_RELATIVE_TOKEN == token) {
+                        /* need to convert the Delta-seconds-value
+                         * into Date-value */
+                        timeValue = System.currentTimeMillis()/1000 + timeValue;
+                    }
+
+                    try {
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: time value: " + headerField
+                                    + " value: " + timeValue);
+                        }
+                        headers.setLongInteger(timeValue, headerField);
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Long-Integer header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                case PduHeaders.FROM: {
+                    /* From-value =
+                     * Value-length
+                     * (Address-present-token Encoded-string-value | Insert-address-token)
+                     */
+                    EncodedStringValue from = null;
+                    parseValueLength(pduDataStream); /* parse value-length */
+
+                    /* Address-present-token or Insert-address-token */
+                    int fromToken = extractByteValue(pduDataStream);
+
+                    /* Address-present-token or Insert-address-token */
+                    if (PduHeaders.FROM_ADDRESS_PRESENT_TOKEN == fromToken) {
+                        /* Encoded-string-value */
+                        from = parseEncodedStringValue(pduDataStream);
+                        if (null != from) {
+                            byte[] address = from.getTextString();
+                            if (null != address) {
+                                String str = new String(address);
+                                int endIndex = str.indexOf("/");
+                                if (endIndex > 0) {
+                                    str = str.substring(0, endIndex);
+                                }
+                                try {
+                                    from.setTextString(str.getBytes());
+                                } catch(NullPointerException e) {
+                                    log("null pointer error!");
+                                    return null;
+                                }
+                            }
+                        }
+                    } else {
+                        try {
+                            from = new EncodedStringValue(
+                                    PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.getBytes());
+                        } catch(NullPointerException e) {
+                            log(headerField + "is not Encoded-String-Value header field!");
+                            return null;
+                        }
+                    }
+
+                    try {
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: from address: " + headerField
+                                    + " value: " + from.getString());
+                        }
+                        headers.setEncodedStringValue(from, PduHeaders.FROM);
+                    } catch(NullPointerException e) {
+                        log("null pointer error!");
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Encoded-String-Value header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                case PduHeaders.MESSAGE_CLASS: {
+                    /* Message-class-value = Class-identifier | Token-text */
+                    pduDataStream.mark(1);
+                    int messageClass = extractByteValue(pduDataStream);
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: MESSAGE_CLASS: " + headerField
+                                + " value: " + messageClass);
+                    }
+
+                    if (messageClass >= PduHeaders.MESSAGE_CLASS_PERSONAL) {
+                        /* Class-identifier */
+                        try {
+                            if (PduHeaders.MESSAGE_CLASS_PERSONAL == messageClass) {
+                                headers.setTextString(
+                                        PduHeaders.MESSAGE_CLASS_PERSONAL_STR.getBytes(),
+                                        PduHeaders.MESSAGE_CLASS);
+                            } else if (PduHeaders.MESSAGE_CLASS_ADVERTISEMENT == messageClass) {
+                                headers.setTextString(
+                                        PduHeaders.MESSAGE_CLASS_ADVERTISEMENT_STR.getBytes(),
+                                        PduHeaders.MESSAGE_CLASS);
+                            } else if (PduHeaders.MESSAGE_CLASS_INFORMATIONAL == messageClass) {
+                                headers.setTextString(
+                                        PduHeaders.MESSAGE_CLASS_INFORMATIONAL_STR.getBytes(),
+                                        PduHeaders.MESSAGE_CLASS);
+                            } else if (PduHeaders.MESSAGE_CLASS_AUTO == messageClass) {
+                                headers.setTextString(
+                                        PduHeaders.MESSAGE_CLASS_AUTO_STR.getBytes(),
+                                        PduHeaders.MESSAGE_CLASS);
+                            }
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch(RuntimeException e) {
+                            log(headerField + "is not Text-String header field!");
+                            return null;
+                        }
+                    } else {
+                        /* Token-text */
+                        pduDataStream.reset();
+                        byte[] messageClassString = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                        if (null != messageClassString) {
+                            try {
+                                headers.setTextString(messageClassString, PduHeaders.MESSAGE_CLASS);
+                            } catch(NullPointerException e) {
+                                log("null pointer error!");
+                            } catch(RuntimeException e) {
+                                log(headerField + "is not Text-String header field!");
+                                return null;
+                            }
+                        }
+                    }
+                    break;
+                }
+
+                case PduHeaders.MMS_VERSION: {
+                    int version = parseShortInteger(pduDataStream);
+
+                    try {
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: MMS_VERSION: " + headerField
+                                    + " value: " + version);
+                        }
+                        headers.setOctet(version, PduHeaders.MMS_VERSION);
+                    } catch(InvalidHeaderValueException e) {
+                        log("Set invalid Octet value: " + version +
+                                " into the header filed: " + headerField);
+                        return null;
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Octet header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                case PduHeaders.PREVIOUSLY_SENT_BY: {
+                    /* Previously-sent-by-value =
+                     * Value-length Forwarded-count-value Encoded-string-value */
+                    /* parse value-length */
+                    parseValueLength(pduDataStream);
+
+                    /* parse Forwarded-count-value */
+                    try {
+                        parseIntegerValue(pduDataStream);
+                    } catch(RuntimeException e) {
+                        log(headerField + " is not Integer-Value");
+                        return null;
+                    }
+
+                    /* parse Encoded-string-value */
+                    EncodedStringValue previouslySentBy =
+                        parseEncodedStringValue(pduDataStream);
+                    if (null != previouslySentBy) {
+                        try {
+                            if (LOCAL_LOGV) {
+                                Log.v(LOG_TAG, "parseHeaders: PREVIOUSLY_SENT_BY: " + headerField
+                                        + " value: " + previouslySentBy.getString());
+                            }
+                            headers.setEncodedStringValue(previouslySentBy,
+                                    PduHeaders.PREVIOUSLY_SENT_BY);
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch(RuntimeException e) {
+                            log(headerField + "is not Encoded-String-Value header field!");
+                            return null;
+                        }
+                    }
+                    break;
+                }
+
+                case PduHeaders.PREVIOUSLY_SENT_DATE: {
+                    /* Previously-sent-date-value =
+                     * Value-length Forwarded-count-value Date-value */
+                    /* parse value-length */
+                    parseValueLength(pduDataStream);
+
+                    /* parse Forwarded-count-value */
+                    try {
+                        parseIntegerValue(pduDataStream);
+                    } catch(RuntimeException e) {
+                        log(headerField + " is not Integer-Value");
+                        return null;
+                    }
+
+                    /* Date-value */
+                    try {
+                        long perviouslySentDate = parseLongInteger(pduDataStream);
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "parseHeaders: PREVIOUSLY_SENT_DATE: " + headerField
+                                    + " value: " + perviouslySentDate);
+                        }
+                        headers.setLongInteger(perviouslySentDate,
+                                PduHeaders.PREVIOUSLY_SENT_DATE);
+                    } catch(RuntimeException e) {
+                        log(headerField + "is not Long-Integer header field!");
+                        return null;
+                    }
+                    break;
+                }
+
+                case PduHeaders.MM_FLAGS: {
+                    /* MM-flags-value =
+                     * Value-length
+                     * ( Add-token | Remove-token | Filter-token )
+                     * Encoded-string-value
+                     */
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: MM_FLAGS: " + headerField
+                                + " NOT REALLY SUPPORTED");
+                    }
+
+                    /* parse Value-length */
+                    parseValueLength(pduDataStream);
+
+                    /* Add-token | Remove-token | Filter-token */
+                    extractByteValue(pduDataStream);
+
+                    /* Encoded-string-value */
+                    parseEncodedStringValue(pduDataStream);
+
+                    /* not store this header filed in "headers",
+                     * because now PduHeaders doesn't support it */
+                    break;
+                }
+
+                /* Value-length
+                 * (Message-total-token | Size-total-token) Integer-Value */
+                case PduHeaders.MBOX_TOTALS:
+                case PduHeaders.MBOX_QUOTAS:
+                {
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: MBOX_TOTALS: " + headerField);
+                    }
+                    /* Value-length */
+                    parseValueLength(pduDataStream);
+
+                    /* Message-total-token | Size-total-token */
+                    extractByteValue(pduDataStream);
+
+                    /*Integer-Value*/
+                    try {
+                        parseIntegerValue(pduDataStream);
+                    } catch(RuntimeException e) {
+                        log(headerField + " is not Integer-Value");
+                        return null;
+                    }
+
+                    /* not store these headers filed in "headers",
+                    because now PduHeaders doesn't support them */
+                    break;
+                }
+
+                case PduHeaders.ELEMENT_DESCRIPTOR: {
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: ELEMENT_DESCRIPTOR: " + headerField);
+                    }
+                    parseContentType(pduDataStream, null);
+
+                    /* not store this header filed in "headers",
+                    because now PduHeaders doesn't support it */
+                    break;
+                }
+
+                case PduHeaders.CONTENT_TYPE: {
+                    HashMap<Integer, Object> map =
+                        new HashMap<Integer, Object>();
+                    byte[] contentType =
+                        parseContentType(pduDataStream, map);
+
+                    if (null != contentType) {
+                        try {
+                            if (LOCAL_LOGV) {
+                                Log.v(LOG_TAG, "parseHeaders: CONTENT_TYPE: " + headerField +
+                                        contentType.toString());
+                            }
+                            headers.setTextString(contentType, PduHeaders.CONTENT_TYPE);
+                        } catch(NullPointerException e) {
+                            log("null pointer error!");
+                        } catch(RuntimeException e) {
+                            log(headerField + "is not Text-String header field!");
+                            return null;
+                        }
+                    }
+
+                    /* get start parameter */
+                    mStartParam = (byte[]) map.get(PduPart.P_START);
+
+                    /* get charset parameter */
+                    mTypeParam= (byte[]) map.get(PduPart.P_TYPE);
+
+                    keepParsing = false;
+                    break;
+                }
+
+                case PduHeaders.CONTENT:
+                case PduHeaders.ADDITIONAL_HEADERS:
+                case PduHeaders.ATTRIBUTES:
+                default: {
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "parseHeaders: Unknown header: " + headerField);
+                    }
+                    log("Unknown header");
+                }
+            }
+        }
+
+        return headers;
+    }
+
+    /**
+     * Parse pdu parts.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return parts in PduBody structure
+     */
+    protected PduBody parseParts(ByteArrayInputStream pduDataStream) {
+        if (pduDataStream == null) {
+            return null;
+        }
+
+        int count = parseUnsignedInt(pduDataStream); // get the number of parts
+        PduBody body = new PduBody();
+
+        for (int i = 0 ; i < count ; i++) {
+            int headerLength = parseUnsignedInt(pduDataStream);
+            int dataLength = parseUnsignedInt(pduDataStream);
+            PduPart part = new PduPart();
+            int startPos = pduDataStream.available();
+            if (startPos <= 0) {
+                // Invalid part.
+                return null;
+            }
+
+            /* parse part's content-type */
+            HashMap<Integer, Object> map = new HashMap<Integer, Object>();
+            byte[] contentType = parseContentType(pduDataStream, map);
+            if (null != contentType) {
+                part.setContentType(contentType);
+            } else {
+                part.setContentType((PduContentTypes.contentTypes[0]).getBytes()); //"*/*"
+            }
+
+            /* get name parameter */
+            byte[] name = (byte[]) map.get(PduPart.P_NAME);
+            if (null != name) {
+                part.setName(name);
+            }
+
+            /* get charset parameter */
+            Integer charset = (Integer) map.get(PduPart.P_CHARSET);
+            if (null != charset) {
+                part.setCharset(charset);
+            }
+
+            /* parse part's headers */
+            int endPos = pduDataStream.available();
+            int partHeaderLen = headerLength - (startPos - endPos);
+            if (partHeaderLen > 0) {
+                if (false == parsePartHeaders(pduDataStream, part, partHeaderLen)) {
+                    // Parse part header faild.
+                    return null;
+                }
+            } else if (partHeaderLen < 0) {
+                // Invalid length of content-type.
+                return null;
+            }
+
+            /* FIXME: check content-id, name, filename and content location,
+             * if not set anyone of them, generate a default content-location
+             */
+            if ((null == part.getContentLocation())
+                    && (null == part.getName())
+                    && (null == part.getFilename())
+                    && (null == part.getContentId())) {
+                part.setContentLocation(Long.toOctalString(
+                        System.currentTimeMillis()).getBytes());
+            }
+
+            /* get part's data */
+            if (dataLength > 0) {
+                byte[] partData = new byte[dataLength];
+                String partContentType = new String(part.getContentType());
+                pduDataStream.read(partData, 0, dataLength);
+                if (partContentType.equalsIgnoreCase(ContentType.MULTIPART_ALTERNATIVE)) {
+                    // parse "multipart/vnd.wap.multipart.alternative".
+                    PduBody childBody = parseParts(new ByteArrayInputStream(partData));
+                    // take the first part of children.
+                    part = childBody.getPart(0);
+                } else {
+                    // Check Content-Transfer-Encoding.
+                    byte[] partDataEncoding = part.getContentTransferEncoding();
+                    if (null != partDataEncoding) {
+                        String encoding = new String(partDataEncoding);
+                        if (encoding.equalsIgnoreCase(PduPart.P_BASE64)) {
+                            // Decode "base64" into "binary".
+                            partData = Base64.decodeBase64(partData);
+                        } else if (encoding.equalsIgnoreCase(PduPart.P_QUOTED_PRINTABLE)) {
+                            // Decode "quoted-printable" into "binary".
+                            partData = QuotedPrintable.decodeQuotedPrintable(partData);
+                        } else {
+                            // "binary" is the default encoding.
+                        }
+                    }
+                    if (null == partData) {
+                        log("Decode part data error!");
+                        return null;
+                    }
+                    part.setData(partData);
+                }
+            }
+
+            /* add this part to body */
+            if (THE_FIRST_PART == checkPartPosition(part)) {
+                /* this is the first part */
+                body.addPart(0, part);
+            } else {
+                /* add the part to the end */
+                body.addPart(part);
+            }
+        }
+
+        return body;
+    }
+
+    /**
+     * Log status.
+     *
+     * @param text log information
+     */
+    @UnsupportedAppUsage
+    private static void log(String text) {
+        if (LOCAL_LOGV) {
+            Log.v(LOG_TAG, text);
+        }
+    }
+
+    /**
+     * Parse unsigned integer.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return the integer, -1 when failed
+     */
+    @UnsupportedAppUsage
+    protected static int parseUnsignedInt(ByteArrayInputStream pduDataStream) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * The maximum size of a uintvar is 32 bits.
+         * So it will be encoded in no more than 5 octets.
+         */
+        assert(null != pduDataStream);
+        int result = 0;
+        int temp = pduDataStream.read();
+        if (temp == -1) {
+            return temp;
+        }
+
+        while((temp & 0x80) != 0) {
+            result = result << 7;
+            result |= temp & 0x7F;
+            temp = pduDataStream.read();
+            if (temp == -1) {
+                return temp;
+            }
+        }
+
+        result = result << 7;
+        result |= temp & 0x7F;
+
+        return result;
+    }
+
+    /**
+     * Parse value length.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return the integer
+     */
+    @UnsupportedAppUsage
+    protected static int parseValueLength(ByteArrayInputStream pduDataStream) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Value-length = Short-length | (Length-quote Length)
+         * Short-length = <Any octet 0-30>
+         * Length-quote = <Octet 31>
+         * Length = Uintvar-integer
+         * Uintvar-integer = 1*5 OCTET
+         */
+        assert(null != pduDataStream);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        int first = temp & 0xFF;
+
+        if (first <= SHORT_LENGTH_MAX) {
+            return first;
+        } else if (first == LENGTH_QUOTE) {
+            return parseUnsignedInt(pduDataStream);
+        }
+
+        throw new RuntimeException ("Value length > LENGTH_QUOTE!");
+    }
+
+    /**
+     * Parse encoded string value.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return the EncodedStringValue
+     */
+    protected static EncodedStringValue parseEncodedStringValue(ByteArrayInputStream pduDataStream){
+        /**
+         * From OMA-TS-MMS-ENC-V1_3-20050927-C.pdf
+         * Encoded-string-value = Text-string | Value-length Char-set Text-string
+         */
+        assert(null != pduDataStream);
+        pduDataStream.mark(1);
+        EncodedStringValue returnValue = null;
+        int charset = 0;
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        int first = temp & 0xFF;
+        if (first == 0) {
+            return new EncodedStringValue("");
+        }
+
+        pduDataStream.reset();
+        if (first < TEXT_MIN) {
+            parseValueLength(pduDataStream);
+
+            charset = parseShortInteger(pduDataStream); //get the "Charset"
+        }
+
+        byte[] textString = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+
+        try {
+            if (0 != charset) {
+                returnValue = new EncodedStringValue(charset, textString);
+            } else {
+                returnValue = new EncodedStringValue(textString);
+            }
+        } catch(Exception e) {
+            return null;
+        }
+
+        return returnValue;
+    }
+
+    /**
+     * Parse Text-String or Quoted-String.
+     *
+     * @param pduDataStream pdu data input stream
+     * @param stringType TYPE_TEXT_STRING or TYPE_QUOTED_STRING
+     * @return the string without End-of-string in byte array
+     */
+    @UnsupportedAppUsage
+    protected static byte[] parseWapString(ByteArrayInputStream pduDataStream,
+            int stringType) {
+        assert(null != pduDataStream);
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Text-string = [Quote] *TEXT End-of-string
+         * If the first character in the TEXT is in the range of 128-255,
+         * a Quote character must precede it.
+         * Otherwise the Quote character must be omitted.
+         * The Quote is not part of the contents.
+         * Quote = <Octet 127>
+         * End-of-string = <Octet 0>
+         *
+         * Quoted-string = <Octet 34> *TEXT End-of-string
+         *
+         * Token-text = Token End-of-string
+         */
+
+        // Mark supposed beginning of Text-string
+        // We will have to mark again if first char is QUOTE or QUOTED_STRING_FLAG
+        pduDataStream.mark(1);
+
+        // Check first char
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        if ((TYPE_QUOTED_STRING == stringType) &&
+                (QUOTED_STRING_FLAG == temp)) {
+            // Mark again if QUOTED_STRING_FLAG and ignore it
+            pduDataStream.mark(1);
+        } else if ((TYPE_TEXT_STRING == stringType) &&
+                (QUOTE == temp)) {
+            // Mark again if QUOTE and ignore it
+            pduDataStream.mark(1);
+        } else {
+            // Otherwise go back to origin
+            pduDataStream.reset();
+        }
+
+        // We are now definitely at the beginning of string
+        /**
+         * Return *TOKEN or *TEXT (Text-String without QUOTE,
+         * Quoted-String without QUOTED_STRING_FLAG and without End-of-string)
+         */
+        return getWapString(pduDataStream, stringType);
+    }
+
+    /**
+     * Check TOKEN data defined in RFC2616.
+     * @param ch checking data
+     * @return true when ch is TOKEN, false when ch is not TOKEN
+     */
+    protected static boolean isTokenCharacter(int ch) {
+        /**
+         * Token      = 1*<any CHAR except CTLs or separators>
+         * separators = "("(40) | ")"(41) | "<"(60) | ">"(62) | "@"(64)
+         *            | ","(44) | ";"(59) | ":"(58) | "\"(92) | <">(34)
+         *            | "/"(47) | "["(91) | "]"(93) | "?"(63) | "="(61)
+         *            | "{"(123) | "}"(125) | SP(32) | HT(9)
+         * CHAR       = <any US-ASCII character (octets 0 - 127)>
+         * CTL        = <any US-ASCII control character
+         *            (octets 0 - 31) and DEL (127)>
+         * SP         = <US-ASCII SP, space (32)>
+         * HT         = <US-ASCII HT, horizontal-tab (9)>
+         */
+        if((ch < 33) || (ch > 126)) {
+            return false;
+        }
+
+        switch(ch) {
+            case '"': /* '"' */
+            case '(': /* '(' */
+            case ')': /* ')' */
+            case ',': /* ',' */
+            case '/': /* '/' */
+            case ':': /* ':' */
+            case ';': /* ';' */
+            case '<': /* '<' */
+            case '=': /* '=' */
+            case '>': /* '>' */
+            case '?': /* '?' */
+            case '@': /* '@' */
+            case '[': /* '[' */
+            case '\\': /* '\' */
+            case ']': /* ']' */
+            case '{': /* '{' */
+            case '}': /* '}' */
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Check TEXT data defined in RFC2616.
+     * @param ch checking data
+     * @return true when ch is TEXT, false when ch is not TEXT
+     */
+    protected static boolean isText(int ch) {
+        /**
+         * TEXT = <any OCTET except CTLs,
+         *      but including LWS>
+         * CTL  = <any US-ASCII control character
+         *      (octets 0 - 31) and DEL (127)>
+         * LWS  = [CRLF] 1*( SP | HT )
+         * CRLF = CR LF
+         * CR   = <US-ASCII CR, carriage return (13)>
+         * LF   = <US-ASCII LF, linefeed (10)>
+         */
+        if(((ch >= 32) && (ch <= 126)) || ((ch >= 128) && (ch <= 255))) {
+            return true;
+        }
+
+        switch(ch) {
+            case '\t': /* '\t' */
+            case '\n': /* '\n' */
+            case '\r': /* '\r' */
+                return true;
+        }
+
+        return false;
+    }
+
+    protected static byte[] getWapString(ByteArrayInputStream pduDataStream,
+            int stringType) {
+        assert(null != pduDataStream);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        while((-1 != temp) && ('\0' != temp)) {
+            // check each of the character
+            if (stringType == TYPE_TOKEN_STRING) {
+                if (isTokenCharacter(temp)) {
+                    out.write(temp);
+                }
+            } else {
+                if (isText(temp)) {
+                    out.write(temp);
+                }
+            }
+
+            temp = pduDataStream.read();
+            assert(-1 != temp);
+        }
+
+        if (out.size() > 0) {
+            return out.toByteArray();
+        }
+
+        return null;
+    }
+
+    /**
+     * Extract a byte value from the input stream.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return the byte
+     */
+    protected static int extractByteValue(ByteArrayInputStream pduDataStream) {
+        assert(null != pduDataStream);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        return temp & 0xFF;
+    }
+
+    /**
+     * Parse Short-Integer.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return the byte
+     */
+    @UnsupportedAppUsage
+    protected static int parseShortInteger(ByteArrayInputStream pduDataStream) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Short-integer = OCTET
+         * Integers in range 0-127 shall be encoded as a one
+         * octet value with the most significant bit set to one (1xxx xxxx)
+         * and with the value in the remaining least significant bits.
+         */
+        assert(null != pduDataStream);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        return temp & 0x7F;
+    }
+
+    /**
+     * Parse Long-Integer.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return long integer
+     */
+    protected static long parseLongInteger(ByteArrayInputStream pduDataStream) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Long-integer = Short-length Multi-octet-integer
+         * The Short-length indicates the length of the Multi-octet-integer
+         * Multi-octet-integer = 1*30 OCTET
+         * The content octets shall be an unsigned integer value
+         * with the most significant octet encoded first (big-endian representation).
+         * The minimum number of octets must be used to encode the value.
+         * Short-length = <Any octet 0-30>
+         */
+        assert(null != pduDataStream);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        int count = temp & 0xFF;
+
+        if (count > LONG_INTEGER_LENGTH_MAX) {
+            throw new RuntimeException("Octet count greater than 8 and I can't represent that!");
+        }
+
+        long result = 0;
+
+        for (int i = 0 ; i < count ; i++) {
+            temp = pduDataStream.read();
+            assert(-1 != temp);
+            result <<= 8;
+            result += (temp & 0xFF);
+        }
+
+        return result;
+    }
+
+    /**
+     * Parse Integer-Value.
+     *
+     * @param pduDataStream pdu data input stream
+     * @return long integer
+     */
+    protected static long parseIntegerValue(ByteArrayInputStream pduDataStream) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Integer-Value = Short-integer | Long-integer
+         */
+        assert(null != pduDataStream);
+        pduDataStream.mark(1);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        pduDataStream.reset();
+        if (temp > SHORT_INTEGER_MAX) {
+            return parseShortInteger(pduDataStream);
+        } else {
+            return parseLongInteger(pduDataStream);
+        }
+    }
+
+    /**
+     * To skip length of the wap value.
+     *
+     * @param pduDataStream pdu data input stream
+     * @param length area size
+     * @return the values in this area
+     */
+    protected static int skipWapValue(ByteArrayInputStream pduDataStream, int length) {
+        assert(null != pduDataStream);
+        byte[] area = new byte[length];
+        int readLen = pduDataStream.read(area, 0, length);
+        if (readLen < length) { //The actually read length is lower than the length
+            return -1;
+        } else {
+            return readLen;
+        }
+    }
+
+    /**
+     * Parse content type parameters. For now we just support
+     * four parameters used in mms: "type", "start", "name", "charset".
+     *
+     * @param pduDataStream pdu data input stream
+     * @param map to store parameters of Content-Type field
+     * @param length length of all the parameters
+     */
+    protected static void parseContentTypeParams(ByteArrayInputStream pduDataStream,
+            HashMap<Integer, Object> map, Integer length) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Parameter = Typed-parameter | Untyped-parameter
+         * Typed-parameter = Well-known-parameter-token Typed-value
+         * the actual expected type of the value is implied by the well-known parameter
+         * Well-known-parameter-token = Integer-value
+         * the code values used for parameters are specified in the Assigned Numbers appendix
+         * Typed-value = Compact-value | Text-value
+         * In addition to the expected type, there may be no value.
+         * If the value cannot be encoded using the expected type, it shall be encoded as text.
+         * Compact-value = Integer-value |
+         * Date-value | Delta-seconds-value | Q-value | Version-value |
+         * Uri-value
+         * Untyped-parameter = Token-text Untyped-value
+         * the type of the value is unknown, but it shall be encoded as an integer,
+         * if that is possible.
+         * Untyped-value = Integer-value | Text-value
+         */
+        assert(null != pduDataStream);
+        assert(length > 0);
+
+        int startPos = pduDataStream.available();
+        int tempPos = 0;
+        int lastLen = length;
+        while(0 < lastLen) {
+            int param = pduDataStream.read();
+            assert(-1 != param);
+            lastLen--;
+
+            switch (param) {
+                /**
+                 * From rfc2387, chapter 3.1
+                 * The type parameter must be specified and its value is the MIME media
+                 * type of the "root" body part. It permits a MIME user agent to
+                 * determine the content-type without reference to the enclosed body
+                 * part. If the value of the type parameter and the root body part's
+                 * content-type differ then the User Agent's behavior is undefined.
+                 *
+                 * From wap-230-wsp-20010705-a.pdf
+                 * type = Constrained-encoding
+                 * Constrained-encoding = Extension-Media | Short-integer
+                 * Extension-media = *TEXT End-of-string
+                 */
+                case PduPart.P_TYPE:
+                case PduPart.P_CT_MR_TYPE:
+                    pduDataStream.mark(1);
+                    int first = extractByteValue(pduDataStream);
+                    pduDataStream.reset();
+                    if (first > TEXT_MAX) {
+                        // Short-integer (well-known type)
+                        int index = parseShortInteger(pduDataStream);
+
+                        if (index < PduContentTypes.contentTypes.length) {
+                            byte[] type = (PduContentTypes.contentTypes[index]).getBytes();
+                            map.put(PduPart.P_TYPE, type);
+                        } else {
+                            //not support this type, ignore it.
+                        }
+                    } else {
+                        // Text-String (extension-media)
+                        byte[] type = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                        if ((null != type) && (null != map)) {
+                            map.put(PduPart.P_TYPE, type);
+                        }
+                    }
+
+                    tempPos = pduDataStream.available();
+                    lastLen = length - (startPos - tempPos);
+                    break;
+
+                    /**
+                     * From oma-ts-mms-conf-v1_3.pdf, chapter 10.2.3.
+                     * Start Parameter Referring to Presentation
+                     *
+                     * From rfc2387, chapter 3.2
+                     * The start parameter, if given, is the content-ID of the compound
+                     * object's "root". If not present the "root" is the first body part in
+                     * the Multipart/Related entity. The "root" is the element the
+                     * applications processes first.
+                     *
+                     * From wap-230-wsp-20010705-a.pdf
+                     * start = Text-String
+                     */
+                case PduPart.P_START:
+                case PduPart.P_DEP_START:
+                    byte[] start = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                    if ((null != start) && (null != map)) {
+                        map.put(PduPart.P_START, start);
+                    }
+
+                    tempPos = pduDataStream.available();
+                    lastLen = length - (startPos - tempPos);
+                    break;
+
+                    /**
+                     * From oma-ts-mms-conf-v1_3.pdf
+                     * In creation, the character set SHALL be either us-ascii
+                     * (IANA MIBenum 3) or utf-8 (IANA MIBenum 106)[Unicode].
+                     * In retrieval, both us-ascii and utf-8 SHALL be supported.
+                     *
+                     * From wap-230-wsp-20010705-a.pdf
+                     * charset = Well-known-charset|Text-String
+                     * Well-known-charset = Any-charset | Integer-value
+                     * Both are encoded using values from Character Set
+                     * Assignments table in Assigned Numbers
+                     * Any-charset = <Octet 128>
+                     * Equivalent to the special RFC2616 charset value "*"
+                     */
+                case PduPart.P_CHARSET:
+                    pduDataStream.mark(1);
+                    int firstValue = extractByteValue(pduDataStream);
+                    pduDataStream.reset();
+                    //Check first char
+                    if (((firstValue > TEXT_MIN) && (firstValue < TEXT_MAX)) ||
+                            (END_STRING_FLAG == firstValue)) {
+                        //Text-String (extension-charset)
+                        byte[] charsetStr = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                        try {
+                            int charsetInt = CharacterSets.getMibEnumValue(
+                                    new String(charsetStr));
+                            map.put(PduPart.P_CHARSET, charsetInt);
+                        } catch (UnsupportedEncodingException e) {
+                            // Not a well-known charset, use "*".
+                            Log.e(LOG_TAG, Arrays.toString(charsetStr), e);
+                            map.put(PduPart.P_CHARSET, CharacterSets.ANY_CHARSET);
+                        }
+                    } else {
+                        //Well-known-charset
+                        int charset = (int) parseIntegerValue(pduDataStream);
+                        if (map != null) {
+                            map.put(PduPart.P_CHARSET, charset);
+                        }
+                    }
+
+                    tempPos = pduDataStream.available();
+                    lastLen = length - (startPos - tempPos);
+                    break;
+
+                    /**
+                     * From oma-ts-mms-conf-v1_3.pdf
+                     * A name for multipart object SHALL be encoded using name-parameter
+                     * for Content-Type header in WSP multipart headers.
+                     *
+                     * From wap-230-wsp-20010705-a.pdf
+                     * name = Text-String
+                     */
+                case PduPart.P_DEP_NAME:
+                case PduPart.P_NAME:
+                    byte[] name = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                    if ((null != name) && (null != map)) {
+                        map.put(PduPart.P_NAME, name);
+                    }
+
+                    tempPos = pduDataStream.available();
+                    lastLen = length - (startPos - tempPos);
+                    break;
+                default:
+                    if (LOCAL_LOGV) {
+                        Log.v(LOG_TAG, "Not supported Content-Type parameter");
+                    }
+                if (-1 == skipWapValue(pduDataStream, lastLen)) {
+                    Log.e(LOG_TAG, "Corrupt Content-Type");
+                } else {
+                    lastLen = 0;
+                }
+                break;
+            }
+        }
+
+        if (0 != lastLen) {
+            Log.e(LOG_TAG, "Corrupt Content-Type");
+        }
+    }
+
+    /**
+     * Parse content type.
+     *
+     * @param pduDataStream pdu data input stream
+     * @param map to store parameters in Content-Type header field
+     * @return Content-Type value
+     */
+    @UnsupportedAppUsage
+    protected static byte[] parseContentType(ByteArrayInputStream pduDataStream,
+            HashMap<Integer, Object> map) {
+        /**
+         * From wap-230-wsp-20010705-a.pdf
+         * Content-type-value = Constrained-media | Content-general-form
+         * Content-general-form = Value-length Media-type
+         * Media-type = (Well-known-media | Extension-Media) *(Parameter)
+         */
+        assert(null != pduDataStream);
+
+        byte[] contentType = null;
+        pduDataStream.mark(1);
+        int temp = pduDataStream.read();
+        assert(-1 != temp);
+        pduDataStream.reset();
+
+        int cur = (temp & 0xFF);
+
+        if (cur < TEXT_MIN) {
+            int length = parseValueLength(pduDataStream);
+            int startPos = pduDataStream.available();
+            pduDataStream.mark(1);
+            temp = pduDataStream.read();
+            assert(-1 != temp);
+            pduDataStream.reset();
+            int first = (temp & 0xFF);
+
+            if ((first >= TEXT_MIN) && (first <= TEXT_MAX)) {
+                contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+            } else if (first > TEXT_MAX) {
+                int index = parseShortInteger(pduDataStream);
+
+                if (index < PduContentTypes.contentTypes.length) { //well-known type
+                    contentType = (PduContentTypes.contentTypes[index]).getBytes();
+                } else {
+                    pduDataStream.reset();
+                    contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                }
+            } else {
+                Log.e(LOG_TAG, "Corrupt content-type");
+                return (PduContentTypes.contentTypes[0]).getBytes(); //"*/*"
+            }
+
+            int endPos = pduDataStream.available();
+            int parameterLen = length - (startPos - endPos);
+            if (parameterLen > 0) {//have parameters
+                parseContentTypeParams(pduDataStream, map, parameterLen);
+            }
+
+            if (parameterLen < 0) {
+                Log.e(LOG_TAG, "Corrupt MMS message");
+                return (PduContentTypes.contentTypes[0]).getBytes(); //"*/*"
+            }
+        } else if (cur <= TEXT_MAX) {
+            contentType = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+        } else {
+            contentType =
+                (PduContentTypes.contentTypes[parseShortInteger(pduDataStream)]).getBytes();
+        }
+
+        return contentType;
+    }
+
+    /**
+     * Parse part's headers.
+     *
+     * @param pduDataStream pdu data input stream
+     * @param part to store the header informations of the part
+     * @param length length of the headers
+     * @return true if parse successfully, false otherwise
+     */
+    @UnsupportedAppUsage
+    protected boolean parsePartHeaders(ByteArrayInputStream pduDataStream,
+            PduPart part, int length) {
+        assert(null != pduDataStream);
+        assert(null != part);
+        assert(length > 0);
+
+        /**
+         * From oma-ts-mms-conf-v1_3.pdf, chapter 10.2.
+         * A name for multipart object SHALL be encoded using name-parameter
+         * for Content-Type header in WSP multipart headers.
+         * In decoding, name-parameter of Content-Type SHALL be used if available.
+         * If name-parameter of Content-Type is not available,
+         * filename parameter of Content-Disposition header SHALL be used if available.
+         * If neither name-parameter of Content-Type header nor filename parameter
+         * of Content-Disposition header is available,
+         * Content-Location header SHALL be used if available.
+         *
+         * Within SMIL part the reference to the media object parts SHALL use
+         * either Content-ID or Content-Location mechanism [RFC2557]
+         * and the corresponding WSP part headers in media object parts
+         * contain the corresponding definitions.
+         */
+        int startPos = pduDataStream.available();
+        int tempPos = 0;
+        int lastLen = length;
+        while(0 < lastLen) {
+            int header = pduDataStream.read();
+            assert(-1 != header);
+            lastLen--;
+
+            if (header > TEXT_MAX) {
+                // Number assigned headers.
+                switch (header) {
+                    case PduPart.P_CONTENT_LOCATION:
+                        /**
+                         * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21
+                         * Content-location-value = Uri-value
+                         */
+                        byte[] contentLocation = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                        if (null != contentLocation) {
+                            part.setContentLocation(contentLocation);
+                        }
+
+                        tempPos = pduDataStream.available();
+                        lastLen = length - (startPos - tempPos);
+                        break;
+                    case PduPart.P_CONTENT_ID:
+                        /**
+                         * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21
+                         * Content-ID-value = Quoted-string
+                         */
+                        byte[] contentId = parseWapString(pduDataStream, TYPE_QUOTED_STRING);
+                        if (null != contentId) {
+                            part.setContentId(contentId);
+                        }
+
+                        tempPos = pduDataStream.available();
+                        lastLen = length - (startPos - tempPos);
+                        break;
+                    case PduPart.P_DEP_CONTENT_DISPOSITION:
+                    case PduPart.P_CONTENT_DISPOSITION:
+                        /**
+                         * From wap-230-wsp-20010705-a.pdf, chapter 8.4.2.21
+                         * Content-disposition-value = Value-length Disposition *(Parameter)
+                         * Disposition = Form-data | Attachment | Inline | Token-text
+                         * Form-data = <Octet 128>
+                         * Attachment = <Octet 129>
+                         * Inline = <Octet 130>
+                         */
+
+                        /*
+                         * some carrier mmsc servers do not support content_disposition
+                         * field correctly
+                         */
+                        if (mParseContentDisposition) {
+                            int len = parseValueLength(pduDataStream);
+                            pduDataStream.mark(1);
+                            int thisStartPos = pduDataStream.available();
+                            int thisEndPos = 0;
+                            int value = pduDataStream.read();
+
+                            if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
+                                part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
+                            } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
+                                part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
+                            } else if (value == PduPart.P_DISPOSITION_INLINE) {
+                                part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+                            } else {
+                                pduDataStream.reset();
+                                /* Token-text */
+                                part.setContentDisposition(parseWapString(pduDataStream
+                                        , TYPE_TEXT_STRING));
+                            }
+
+                            /* get filename parameter and skip other parameters */
+                            thisEndPos = pduDataStream.available();
+                            if (thisStartPos - thisEndPos < len) {
+                                value = pduDataStream.read();
+                                if (value == PduPart.P_FILENAME) { //filename is text-string
+                                    part.setFilename(parseWapString(pduDataStream
+                                            , TYPE_TEXT_STRING));
+                                }
+
+                                /* skip other parameters */
+                                thisEndPos = pduDataStream.available();
+                                if (thisStartPos - thisEndPos < len) {
+                                    int last = len - (thisStartPos - thisEndPos);
+                                    byte[] temp = new byte[last];
+                                    pduDataStream.read(temp, 0, last);
+                                }
+                            }
+
+                            tempPos = pduDataStream.available();
+                            lastLen = length - (startPos - tempPos);
+                        }
+                        break;
+                    default:
+                        if (LOCAL_LOGV) {
+                            Log.v(LOG_TAG, "Not supported Part headers: " + header);
+                        }
+                    if (-1 == skipWapValue(pduDataStream, lastLen)) {
+                        Log.e(LOG_TAG, "Corrupt Part headers");
+                        return false;
+                    }
+                    lastLen = 0;
+                    break;
+                }
+            } else if ((header >= TEXT_MIN) && (header <= TEXT_MAX)) {
+                // Not assigned header.
+                byte[] tempHeader = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+                byte[] tempValue = parseWapString(pduDataStream, TYPE_TEXT_STRING);
+
+                // Check the header whether it is "Content-Transfer-Encoding".
+                if (true ==
+                    PduPart.CONTENT_TRANSFER_ENCODING.equalsIgnoreCase(new String(tempHeader))) {
+                    part.setContentTransferEncoding(tempValue);
+                }
+
+                tempPos = pduDataStream.available();
+                lastLen = length - (startPos - tempPos);
+            } else {
+                if (LOCAL_LOGV) {
+                    Log.v(LOG_TAG, "Not supported Part headers: " + header);
+                }
+                // Skip all headers of this part.
+                if (-1 == skipWapValue(pduDataStream, lastLen)) {
+                    Log.e(LOG_TAG, "Corrupt Part headers");
+                    return false;
+                }
+                lastLen = 0;
+            }
+        }
+
+        if (0 != lastLen) {
+            Log.e(LOG_TAG, "Corrupt Part headers");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Check the position of a specified part.
+     *
+     * @param part the part to be checked
+     * @return part position, THE_FIRST_PART when it's the
+     * first one, THE_LAST_PART when it's the last one.
+     */
+    @UnsupportedAppUsage
+    private static int checkPartPosition(PduPart part) {
+        assert(null != part);
+        if ((null == mTypeParam) &&
+                (null == mStartParam)) {
+            return THE_LAST_PART;
+        }
+
+        /* check part's content-id */
+        if (null != mStartParam) {
+            byte[] contentId = part.getContentId();
+            if (null != contentId) {
+                if (true == Arrays.equals(mStartParam, contentId)) {
+                    return THE_FIRST_PART;
+                }
+            }
+            // This is not the first part, so append to end (keeping the original order)
+            // Check b/19607294 for details of this change
+            return THE_LAST_PART;
+        }
+
+        /* check part's content-type */
+        if (null != mTypeParam) {
+            byte[] contentType = part.getContentType();
+            if (null != contentType) {
+                if (true == Arrays.equals(mTypeParam, contentType)) {
+                    return THE_FIRST_PART;
+                }
+            }
+        }
+
+        return THE_LAST_PART;
+    }
+
+    /**
+     * Check mandatory headers of a pdu.
+     *
+     * @param headers pdu headers
+     * @return true if the pdu has all of the mandatory headers, false otherwise.
+     */
+    protected static boolean checkMandatoryHeader(PduHeaders headers) {
+        if (null == headers) {
+            return false;
+        }
+
+        /* get message type */
+        int messageType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
+
+        /* check Mms-Version field */
+        int mmsVersion = headers.getOctet(PduHeaders.MMS_VERSION);
+        if (0 == mmsVersion) {
+            // Every message should have Mms-Version field.
+            return false;
+        }
+
+        /* check mandatory header fields */
+        switch (messageType) {
+            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
+                // Content-Type field.
+                byte[] srContentType = headers.getTextString(PduHeaders.CONTENT_TYPE);
+                if (null == srContentType) {
+                    return false;
+                }
+
+                // From field.
+                EncodedStringValue srFrom = headers.getEncodedStringValue(PduHeaders.FROM);
+                if (null == srFrom) {
+                    return false;
+                }
+
+                // Transaction-Id field.
+                byte[] srTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID);
+                if (null == srTransactionId) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
+                // Response-Status field.
+                int scResponseStatus = headers.getOctet(PduHeaders.RESPONSE_STATUS);
+                if (0 == scResponseStatus) {
+                    return false;
+                }
+
+                // Transaction-Id field.
+                byte[] scTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID);
+                if (null == scTransactionId) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
+                // Content-Location field.
+                byte[] niContentLocation = headers.getTextString(PduHeaders.CONTENT_LOCATION);
+                if (null == niContentLocation) {
+                    return false;
+                }
+
+                // Expiry field.
+                long niExpiry = headers.getLongInteger(PduHeaders.EXPIRY);
+                if (-1 == niExpiry) {
+                    return false;
+                }
+
+                // Message-Class field.
+                byte[] niMessageClass = headers.getTextString(PduHeaders.MESSAGE_CLASS);
+                if (null == niMessageClass) {
+                    return false;
+                }
+
+                // Message-Size field.
+                long niMessageSize = headers.getLongInteger(PduHeaders.MESSAGE_SIZE);
+                if (-1 == niMessageSize) {
+                    return false;
+                }
+
+                // Transaction-Id field.
+                byte[] niTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID);
+                if (null == niTransactionId) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
+                // Status field.
+                int nriStatus = headers.getOctet(PduHeaders.STATUS);
+                if (0 == nriStatus) {
+                    return false;
+                }
+
+                // Transaction-Id field.
+                byte[] nriTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID);
+                if (null == nriTransactionId) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
+                // Content-Type field.
+                byte[] rcContentType = headers.getTextString(PduHeaders.CONTENT_TYPE);
+                if (null == rcContentType) {
+                    return false;
+                }
+
+                // Date field.
+                long rcDate = headers.getLongInteger(PduHeaders.DATE);
+                if (-1 == rcDate) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
+                // Date field.
+                long diDate = headers.getLongInteger(PduHeaders.DATE);
+                if (-1 == diDate) {
+                    return false;
+                }
+
+                // Message-Id field.
+                byte[] diMessageId = headers.getTextString(PduHeaders.MESSAGE_ID);
+                if (null == diMessageId) {
+                    return false;
+                }
+
+                // Status field.
+                int diStatus = headers.getOctet(PduHeaders.STATUS);
+                if (0 == diStatus) {
+                    return false;
+                }
+
+                // To field.
+                EncodedStringValue[] diTo = headers.getEncodedStringValues(PduHeaders.TO);
+                if (null == diTo) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
+                // Transaction-Id field.
+                byte[] aiTransactionId = headers.getTextString(PduHeaders.TRANSACTION_ID);
+                if (null == aiTransactionId) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
+                // Date field.
+                long roDate = headers.getLongInteger(PduHeaders.DATE);
+                if (-1 == roDate) {
+                    return false;
+                }
+
+                // From field.
+                EncodedStringValue roFrom = headers.getEncodedStringValue(PduHeaders.FROM);
+                if (null == roFrom) {
+                    return false;
+                }
+
+                // Message-Id field.
+                byte[] roMessageId = headers.getTextString(PduHeaders.MESSAGE_ID);
+                if (null == roMessageId) {
+                    return false;
+                }
+
+                // Read-Status field.
+                int roReadStatus = headers.getOctet(PduHeaders.READ_STATUS);
+                if (0 == roReadStatus) {
+                    return false;
+                }
+
+                // To field.
+                EncodedStringValue[] roTo = headers.getEncodedStringValues(PduHeaders.TO);
+                if (null == roTo) {
+                    return false;
+                }
+
+                break;
+            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
+                // From field.
+                EncodedStringValue rrFrom = headers.getEncodedStringValue(PduHeaders.FROM);
+                if (null == rrFrom) {
+                    return false;
+                }
+
+                // Message-Id field.
+                byte[] rrMessageId = headers.getTextString(PduHeaders.MESSAGE_ID);
+                if (null == rrMessageId) {
+                    return false;
+                }
+
+                // Read-Status field.
+                int rrReadStatus = headers.getOctet(PduHeaders.READ_STATUS);
+                if (0 == rrReadStatus) {
+                    return false;
+                }
+
+                // To field.
+                EncodedStringValue[] rrTo = headers.getEncodedStringValues(PduHeaders.TO);
+                if (null == rrTo) {
+                    return false;
+                }
+
+                break;
+            default:
+                // Parser doesn't support this message type in this version.
+                return false;
+        }
+
+        return true;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java
new file mode 100644
index 0000000..09b7751
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduPart.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.net.Uri;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The pdu part.
+ */
+public class PduPart {
+    /**
+     * Well-Known Parameters.
+     */
+    public static final int P_Q                  = 0x80;
+    public static final int P_CHARSET            = 0x81;
+    public static final int P_LEVEL              = 0x82;
+    public static final int P_TYPE               = 0x83;
+    public static final int P_DEP_NAME           = 0x85;
+    public static final int P_DEP_FILENAME       = 0x86;
+    public static final int P_DIFFERENCES        = 0x87;
+    public static final int P_PADDING            = 0x88;
+    // This value of "TYPE" s used with Content-Type: multipart/related
+    public static final int P_CT_MR_TYPE         = 0x89;
+    public static final int P_DEP_START          = 0x8A;
+    public static final int P_DEP_START_INFO     = 0x8B;
+    public static final int P_DEP_COMMENT        = 0x8C;
+    public static final int P_DEP_DOMAIN         = 0x8D;
+    public static final int P_MAX_AGE            = 0x8E;
+    public static final int P_DEP_PATH           = 0x8F;
+    public static final int P_SECURE             = 0x90;
+    public static final int P_SEC                = 0x91;
+    public static final int P_MAC                = 0x92;
+    public static final int P_CREATION_DATE      = 0x93;
+    public static final int P_MODIFICATION_DATE  = 0x94;
+    public static final int P_READ_DATE          = 0x95;
+    public static final int P_SIZE               = 0x96;
+    public static final int P_NAME               = 0x97;
+    public static final int P_FILENAME           = 0x98;
+    public static final int P_START              = 0x99;
+    public static final int P_START_INFO         = 0x9A;
+    public static final int P_COMMENT            = 0x9B;
+    public static final int P_DOMAIN             = 0x9C;
+    public static final int P_PATH               = 0x9D;
+
+    /**
+     *  Header field names.
+     */
+     public static final int P_CONTENT_TYPE       = 0x91;
+     public static final int P_CONTENT_LOCATION   = 0x8E;
+     public static final int P_CONTENT_ID         = 0xC0;
+     public static final int P_DEP_CONTENT_DISPOSITION = 0xAE;
+     public static final int P_CONTENT_DISPOSITION = 0xC5;
+    // The next header is unassigned header, use reserved header(0x48) value.
+     public static final int P_CONTENT_TRANSFER_ENCODING = 0xC8;
+
+     /**
+      * Content=Transfer-Encoding string.
+      */
+     public static final String CONTENT_TRANSFER_ENCODING =
+             "Content-Transfer-Encoding";
+
+     /**
+      * Value of Content-Transfer-Encoding.
+      */
+     public static final String P_BINARY = "binary";
+     public static final String P_7BIT = "7bit";
+     public static final String P_8BIT = "8bit";
+     public static final String P_BASE64 = "base64";
+     public static final String P_QUOTED_PRINTABLE = "quoted-printable";
+
+     /**
+      * Value of disposition can be set to PduPart when the value is octet in
+      * the PDU.
+      * "from-data" instead of Form-data<Octet 128>.
+      * "attachment" instead of Attachment<Octet 129>.
+      * "inline" instead of Inline<Octet 130>.
+      */
+     static final byte[] DISPOSITION_FROM_DATA = "from-data".getBytes();
+     static final byte[] DISPOSITION_ATTACHMENT = "attachment".getBytes();
+     static final byte[] DISPOSITION_INLINE = "inline".getBytes();
+
+     /**
+      * Content-Disposition value.
+      */
+     public static final int P_DISPOSITION_FROM_DATA  = 0x80;
+     public static final int P_DISPOSITION_ATTACHMENT = 0x81;
+     public static final int P_DISPOSITION_INLINE     = 0x82;
+
+     /**
+      * Header of part.
+      */
+     private Map<Integer, Object> mPartHeader = null;
+
+     /**
+      * Data uri.
+      */
+     private Uri mUri = null;
+
+     /**
+      * Part data.
+      */
+     private byte[] mPartData = null;
+
+     private static final String TAG = "PduPart";
+
+     /**
+      * Empty Constructor.
+      */
+     @UnsupportedAppUsage
+     public PduPart() {
+         mPartHeader = new HashMap<Integer, Object>();
+     }
+
+     /**
+      * Set part data. The data are stored as byte array.
+      *
+      * @param data the data
+      */
+     @UnsupportedAppUsage
+     public void setData(byte[] data) {
+         if(data == null) {
+            return;
+        }
+
+         mPartData = new byte[data.length];
+         System.arraycopy(data, 0, mPartData, 0, data.length);
+     }
+
+     /**
+      * @return A copy of the part data or null if the data wasn't set or
+      *         the data is stored as Uri.
+      * @see #getDataUri
+      */
+     @UnsupportedAppUsage
+     public byte[] getData() {
+         if(mPartData == null) {
+            return null;
+         }
+
+         byte[] byteArray = new byte[mPartData.length];
+         System.arraycopy(mPartData, 0, byteArray, 0, mPartData.length);
+         return byteArray;
+     }
+
+    /**
+     * @return The length of the data, if this object have data, else 0.
+     */
+     @UnsupportedAppUsage
+     public int getDataLength() {
+         if(mPartData != null){
+             return mPartData.length;
+         } else {
+             return 0;
+         }
+     }
+
+
+     /**
+      * Set data uri. The data are stored as Uri.
+      *
+      * @param uri the uri
+      */
+     @UnsupportedAppUsage
+     public void setDataUri(Uri uri) {
+         mUri = uri;
+     }
+
+     /**
+      * @return The Uri of the part data or null if the data wasn't set or
+      *         the data is stored as byte array.
+      * @see #getData
+      */
+     @UnsupportedAppUsage
+     public Uri getDataUri() {
+         return mUri;
+     }
+
+     /**
+      * Set Content-id value
+      *
+      * @param contentId the content-id value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setContentId(byte[] contentId) {
+         if((contentId == null) || (contentId.length == 0)) {
+             throw new IllegalArgumentException(
+                     "Content-Id may not be null or empty.");
+         }
+
+         if ((contentId.length > 1)
+                 && ((char) contentId[0] == '<')
+                 && ((char) contentId[contentId.length - 1] == '>')) {
+             mPartHeader.put(P_CONTENT_ID, contentId);
+             return;
+         }
+
+         // Insert beginning '<' and trailing '>' for Content-Id.
+         byte[] buffer = new byte[contentId.length + 2];
+         buffer[0] = (byte) (0xff & '<');
+         buffer[buffer.length - 1] = (byte) (0xff & '>');
+         System.arraycopy(contentId, 0, buffer, 1, contentId.length);
+         mPartHeader.put(P_CONTENT_ID, buffer);
+     }
+
+     /**
+      * Get Content-id value.
+      *
+      * @return the value
+      */
+     @UnsupportedAppUsage
+     public byte[] getContentId() {
+         return (byte[]) mPartHeader.get(P_CONTENT_ID);
+     }
+
+     /**
+      * Set Char-set value.
+      *
+      * @param charset the value
+      */
+     @UnsupportedAppUsage
+     public void setCharset(int charset) {
+         mPartHeader.put(P_CHARSET, charset);
+     }
+
+     /**
+      * Get Char-set value
+      *
+      * @return the charset value. Return 0 if charset was not set.
+      */
+     @UnsupportedAppUsage
+     public int getCharset() {
+         Integer charset = (Integer) mPartHeader.get(P_CHARSET);
+         if(charset == null) {
+             return 0;
+         } else {
+             return charset.intValue();
+         }
+     }
+
+     /**
+      * Set Content-Location value.
+      *
+      * @param contentLocation the value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setContentLocation(byte[] contentLocation) {
+         if(contentLocation == null) {
+             throw new NullPointerException("null content-location");
+         }
+
+         mPartHeader.put(P_CONTENT_LOCATION, contentLocation);
+     }
+
+     /**
+      * Get Content-Location value.
+      *
+      * @return the value
+      *     return PduPart.disposition[0] instead of <Octet 128> (Form-data).
+      *     return PduPart.disposition[1] instead of <Octet 129> (Attachment).
+      *     return PduPart.disposition[2] instead of <Octet 130> (Inline).
+      */
+     @UnsupportedAppUsage
+     public byte[] getContentLocation() {
+         return (byte[]) mPartHeader.get(P_CONTENT_LOCATION);
+     }
+
+     /**
+      * Set Content-Disposition value.
+      * Use PduPart.disposition[0] instead of <Octet 128> (Form-data).
+      * Use PduPart.disposition[1] instead of <Octet 129> (Attachment).
+      * Use PduPart.disposition[2] instead of <Octet 130> (Inline).
+      *
+      * @param contentDisposition the value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setContentDisposition(byte[] contentDisposition) {
+         if(contentDisposition == null) {
+             throw new NullPointerException("null content-disposition");
+         }
+
+         mPartHeader.put(P_CONTENT_DISPOSITION, contentDisposition);
+     }
+
+     /**
+      * Get Content-Disposition value.
+      *
+      * @return the value
+      */
+     @UnsupportedAppUsage
+     public byte[] getContentDisposition() {
+         return (byte[]) mPartHeader.get(P_CONTENT_DISPOSITION);
+     }
+
+     /**
+      *  Set Content-Type value.
+      *
+      *  @param value the value
+      *  @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setContentType(byte[] contentType) {
+         if(contentType == null) {
+             throw new NullPointerException("null content-type");
+         }
+
+         mPartHeader.put(P_CONTENT_TYPE, contentType);
+     }
+
+     /**
+      * Get Content-Type value of part.
+      *
+      * @return the value
+      */
+     @UnsupportedAppUsage
+     public byte[] getContentType() {
+         return (byte[]) mPartHeader.get(P_CONTENT_TYPE);
+     }
+
+     /**
+      * Set Content-Transfer-Encoding value
+      *
+      * @param contentId the content-id value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setContentTransferEncoding(byte[] contentTransferEncoding) {
+         if(contentTransferEncoding == null) {
+             throw new NullPointerException("null content-transfer-encoding");
+         }
+
+         mPartHeader.put(P_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+     }
+
+     /**
+      * Get Content-Transfer-Encoding value.
+      *
+      * @return the value
+      */
+     @UnsupportedAppUsage
+     public byte[] getContentTransferEncoding() {
+         return (byte[]) mPartHeader.get(P_CONTENT_TRANSFER_ENCODING);
+     }
+
+     /**
+      * Set Content-type parameter: name.
+      *
+      * @param name the name value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setName(byte[] name) {
+         if(null == name) {
+             throw new NullPointerException("null content-id");
+         }
+
+         mPartHeader.put(P_NAME, name);
+     }
+
+     /**
+      *  Get content-type parameter: name.
+      *
+      *  @return the name
+      */
+     @UnsupportedAppUsage
+     public byte[] getName() {
+         return (byte[]) mPartHeader.get(P_NAME);
+     }
+
+     /**
+      * Get Content-disposition parameter: filename
+      *
+      * @param fileName the filename value
+      * @throws NullPointerException if the value is null.
+      */
+     @UnsupportedAppUsage
+     public void setFilename(byte[] fileName) {
+         if(null == fileName) {
+             throw new NullPointerException("null content-id");
+         }
+
+         mPartHeader.put(P_FILENAME, fileName);
+     }
+
+     /**
+      * Set Content-disposition parameter: filename
+      *
+      * @return the filename
+      */
+     @UnsupportedAppUsage
+     public byte[] getFilename() {
+         return (byte[]) mPartHeader.get(P_FILENAME);
+     }
+
+    @UnsupportedAppUsage
+    public String generateLocation() {
+        // Assumption: At least one of the content-location / name / filename
+        // or content-id should be set. This is guaranteed by the PduParser
+        // for incoming messages and by MM composer for outgoing messages.
+        byte[] location = (byte[]) mPartHeader.get(P_NAME);
+        if(null == location) {
+            location = (byte[]) mPartHeader.get(P_FILENAME);
+
+            if (null == location) {
+                location = (byte[]) mPartHeader.get(P_CONTENT_LOCATION);
+            }
+        }
+
+        if (null == location) {
+            byte[] contentId = (byte[]) mPartHeader.get(P_CONTENT_ID);
+            return "cid:" + new String(contentId);
+        } else {
+            return new String(location);
+        }
+    }
+}
+
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
new file mode 100755
index 0000000..93f3065
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -0,0 +1,1573 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.drm.DrmManagerClient;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.provider.Telephony;
+import android.provider.Telephony.Mms;
+import android.provider.Telephony.Mms.Addr;
+import android.provider.Telephony.Mms.Part;
+import android.provider.Telephony.MmsSms;
+import android.provider.Telephony.MmsSms.PendingMessages;
+import android.provider.Telephony.Threads;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.ContentType;
+import com.google.android.mms.InvalidHeaderValueException;
+import com.google.android.mms.MmsException;
+import com.google.android.mms.util.DownloadDrmHelper;
+import com.google.android.mms.util.DrmConvertSession;
+import com.google.android.mms.util.PduCache;
+import com.google.android.mms.util.PduCacheEntry;
+import com.google.android.mms.util.SqliteWrapper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This class is the high-level manager of PDU storage.
+ */
+public class PduPersister {
+    private static final String TAG = "PduPersister";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = false;
+
+    private static final long DUMMY_THREAD_ID = Long.MAX_VALUE;
+
+    /**
+     * The uri of temporary drm objects.
+     */
+    public static final String TEMPORARY_DRM_OBJECT_URI =
+        "content://mms/" + Long.MAX_VALUE + "/part";
+    /**
+     * Indicate that we transiently failed to process a MM.
+     */
+    public static final int PROC_STATUS_TRANSIENT_FAILURE   = 1;
+    /**
+     * Indicate that we permanently failed to process a MM.
+     */
+    public static final int PROC_STATUS_PERMANENTLY_FAILURE = 2;
+    /**
+     * Indicate that we have successfully processed a MM.
+     */
+    public static final int PROC_STATUS_COMPLETED           = 3;
+
+    private static PduPersister sPersister;
+    @UnsupportedAppUsage
+    private static final PduCache PDU_CACHE_INSTANCE;
+
+    @UnsupportedAppUsage
+    private static final int[] ADDRESS_FIELDS = new int[] {
+            PduHeaders.BCC,
+            PduHeaders.CC,
+            PduHeaders.FROM,
+            PduHeaders.TO
+    };
+
+    private static final String[] PDU_PROJECTION = new String[] {
+        Mms._ID,
+        Mms.MESSAGE_BOX,
+        Mms.THREAD_ID,
+        Mms.RETRIEVE_TEXT,
+        Mms.SUBJECT,
+        Mms.CONTENT_LOCATION,
+        Mms.CONTENT_TYPE,
+        Mms.MESSAGE_CLASS,
+        Mms.MESSAGE_ID,
+        Mms.RESPONSE_TEXT,
+        Mms.TRANSACTION_ID,
+        Mms.CONTENT_CLASS,
+        Mms.DELIVERY_REPORT,
+        Mms.MESSAGE_TYPE,
+        Mms.MMS_VERSION,
+        Mms.PRIORITY,
+        Mms.READ_REPORT,
+        Mms.READ_STATUS,
+        Mms.REPORT_ALLOWED,
+        Mms.RETRIEVE_STATUS,
+        Mms.STATUS,
+        Mms.DATE,
+        Mms.DELIVERY_TIME,
+        Mms.EXPIRY,
+        Mms.MESSAGE_SIZE,
+        Mms.SUBJECT_CHARSET,
+        Mms.RETRIEVE_TEXT_CHARSET,
+    };
+
+    private static final int PDU_COLUMN_ID                    = 0;
+    private static final int PDU_COLUMN_MESSAGE_BOX           = 1;
+    private static final int PDU_COLUMN_THREAD_ID             = 2;
+    private static final int PDU_COLUMN_RETRIEVE_TEXT         = 3;
+    private static final int PDU_COLUMN_SUBJECT               = 4;
+    private static final int PDU_COLUMN_CONTENT_LOCATION      = 5;
+    private static final int PDU_COLUMN_CONTENT_TYPE          = 6;
+    private static final int PDU_COLUMN_MESSAGE_CLASS         = 7;
+    private static final int PDU_COLUMN_MESSAGE_ID            = 8;
+    private static final int PDU_COLUMN_RESPONSE_TEXT         = 9;
+    private static final int PDU_COLUMN_TRANSACTION_ID        = 10;
+    private static final int PDU_COLUMN_CONTENT_CLASS         = 11;
+    private static final int PDU_COLUMN_DELIVERY_REPORT       = 12;
+    private static final int PDU_COLUMN_MESSAGE_TYPE          = 13;
+    private static final int PDU_COLUMN_MMS_VERSION           = 14;
+    private static final int PDU_COLUMN_PRIORITY              = 15;
+    private static final int PDU_COLUMN_READ_REPORT           = 16;
+    private static final int PDU_COLUMN_READ_STATUS           = 17;
+    private static final int PDU_COLUMN_REPORT_ALLOWED        = 18;
+    private static final int PDU_COLUMN_RETRIEVE_STATUS       = 19;
+    private static final int PDU_COLUMN_STATUS                = 20;
+    private static final int PDU_COLUMN_DATE                  = 21;
+    private static final int PDU_COLUMN_DELIVERY_TIME         = 22;
+    private static final int PDU_COLUMN_EXPIRY                = 23;
+    private static final int PDU_COLUMN_MESSAGE_SIZE          = 24;
+    private static final int PDU_COLUMN_SUBJECT_CHARSET       = 25;
+    private static final int PDU_COLUMN_RETRIEVE_TEXT_CHARSET = 26;
+
+    @UnsupportedAppUsage
+    private static final String[] PART_PROJECTION = new String[] {
+        Part._ID,
+        Part.CHARSET,
+        Part.CONTENT_DISPOSITION,
+        Part.CONTENT_ID,
+        Part.CONTENT_LOCATION,
+        Part.CONTENT_TYPE,
+        Part.FILENAME,
+        Part.NAME,
+        Part.TEXT
+    };
+
+    private static final int PART_COLUMN_ID                  = 0;
+    private static final int PART_COLUMN_CHARSET             = 1;
+    private static final int PART_COLUMN_CONTENT_DISPOSITION = 2;
+    private static final int PART_COLUMN_CONTENT_ID          = 3;
+    private static final int PART_COLUMN_CONTENT_LOCATION    = 4;
+    private static final int PART_COLUMN_CONTENT_TYPE        = 5;
+    private static final int PART_COLUMN_FILENAME            = 6;
+    private static final int PART_COLUMN_NAME                = 7;
+    private static final int PART_COLUMN_TEXT                = 8;
+
+    @UnsupportedAppUsage
+    private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP;
+    // These map are used for convenience in persist() and load().
+    private static final HashMap<Integer, Integer> CHARSET_COLUMN_INDEX_MAP;
+    private static final HashMap<Integer, Integer> ENCODED_STRING_COLUMN_INDEX_MAP;
+    private static final HashMap<Integer, Integer> TEXT_STRING_COLUMN_INDEX_MAP;
+    private static final HashMap<Integer, Integer> OCTET_COLUMN_INDEX_MAP;
+    private static final HashMap<Integer, Integer> LONG_COLUMN_INDEX_MAP;
+    @UnsupportedAppUsage
+    private static final HashMap<Integer, String> CHARSET_COLUMN_NAME_MAP;
+    @UnsupportedAppUsage
+    private static final HashMap<Integer, String> ENCODED_STRING_COLUMN_NAME_MAP;
+    @UnsupportedAppUsage
+    private static final HashMap<Integer, String> TEXT_STRING_COLUMN_NAME_MAP;
+    @UnsupportedAppUsage
+    private static final HashMap<Integer, String> OCTET_COLUMN_NAME_MAP;
+    @UnsupportedAppUsage
+    private static final HashMap<Integer, String> LONG_COLUMN_NAME_MAP;
+
+    static {
+        MESSAGE_BOX_MAP = new HashMap<Uri, Integer>();
+        MESSAGE_BOX_MAP.put(Mms.Inbox.CONTENT_URI,  Mms.MESSAGE_BOX_INBOX);
+        MESSAGE_BOX_MAP.put(Mms.Sent.CONTENT_URI,   Mms.MESSAGE_BOX_SENT);
+        MESSAGE_BOX_MAP.put(Mms.Draft.CONTENT_URI,  Mms.MESSAGE_BOX_DRAFTS);
+        MESSAGE_BOX_MAP.put(Mms.Outbox.CONTENT_URI, Mms.MESSAGE_BOX_OUTBOX);
+
+        CHARSET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
+        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT_CHARSET);
+        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT_CHARSET);
+
+        CHARSET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
+        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT_CHARSET);
+        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT_CHARSET);
+
+        // Encoded string field code -> column index/name map.
+        ENCODED_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
+        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT);
+        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT);
+
+        ENCODED_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
+        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT);
+        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT);
+
+        // Text string field code -> column index/name map.
+        TEXT_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_LOCATION, PDU_COLUMN_CONTENT_LOCATION);
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_TYPE, PDU_COLUMN_CONTENT_TYPE);
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_CLASS, PDU_COLUMN_MESSAGE_CLASS);
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_ID, PDU_COLUMN_MESSAGE_ID);
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RESPONSE_TEXT, PDU_COLUMN_RESPONSE_TEXT);
+        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.TRANSACTION_ID, PDU_COLUMN_TRANSACTION_ID);
+
+        TEXT_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_LOCATION, Mms.CONTENT_LOCATION);
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_TYPE, Mms.CONTENT_TYPE);
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_CLASS, Mms.MESSAGE_CLASS);
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_ID, Mms.MESSAGE_ID);
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.RESPONSE_TEXT, Mms.RESPONSE_TEXT);
+        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.TRANSACTION_ID, Mms.TRANSACTION_ID);
+
+        // Octet field code -> column index/name map.
+        OCTET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_CLASS, PDU_COLUMN_CONTENT_CLASS);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_REPORT, PDU_COLUMN_DELIVERY_REPORT);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_TYPE, PDU_COLUMN_MESSAGE_TYPE);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MMS_VERSION, PDU_COLUMN_MMS_VERSION);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.PRIORITY, PDU_COLUMN_PRIORITY);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_REPORT, PDU_COLUMN_READ_REPORT);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_STATUS, PDU_COLUMN_READ_STATUS);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.REPORT_ALLOWED, PDU_COLUMN_REPORT_ALLOWED);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_STATUS, PDU_COLUMN_RETRIEVE_STATUS);
+        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.STATUS, PDU_COLUMN_STATUS);
+
+        OCTET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_CLASS, Mms.CONTENT_CLASS);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_REPORT, Mms.DELIVERY_REPORT);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_TYPE, Mms.MESSAGE_TYPE);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MMS_VERSION, Mms.MMS_VERSION);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.PRIORITY, Mms.PRIORITY);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_REPORT, Mms.READ_REPORT);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_STATUS, Mms.READ_STATUS);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.REPORT_ALLOWED, Mms.REPORT_ALLOWED);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_STATUS, Mms.RETRIEVE_STATUS);
+        OCTET_COLUMN_NAME_MAP.put(PduHeaders.STATUS, Mms.STATUS);
+
+        // Long field code -> column index/name map.
+        LONG_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
+        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DATE, PDU_COLUMN_DATE);
+        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_TIME, PDU_COLUMN_DELIVERY_TIME);
+        LONG_COLUMN_INDEX_MAP.put(PduHeaders.EXPIRY, PDU_COLUMN_EXPIRY);
+        LONG_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_SIZE, PDU_COLUMN_MESSAGE_SIZE);
+
+        LONG_COLUMN_NAME_MAP = new HashMap<Integer, String>();
+        LONG_COLUMN_NAME_MAP.put(PduHeaders.DATE, Mms.DATE);
+        LONG_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_TIME, Mms.DELIVERY_TIME);
+        LONG_COLUMN_NAME_MAP.put(PduHeaders.EXPIRY, Mms.EXPIRY);
+        LONG_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_SIZE, Mms.MESSAGE_SIZE);
+
+        PDU_CACHE_INSTANCE = PduCache.getInstance();
+     }
+
+    @UnsupportedAppUsage
+    private final Context mContext;
+    @UnsupportedAppUsage
+    private final ContentResolver mContentResolver;
+    private final DrmManagerClient mDrmManagerClient;
+    @UnsupportedAppUsage
+    private final TelephonyManager mTelephonyManager;
+
+    private PduPersister(Context context) {
+        mContext = context;
+        mContentResolver = context.getContentResolver();
+        mDrmManagerClient = new DrmManagerClient(context);
+        mTelephonyManager = (TelephonyManager)context
+                .getSystemService(Context.TELEPHONY_SERVICE);
+     }
+
+    /** Get(or create if not exist) an instance of PduPersister */
+    @UnsupportedAppUsage
+    public static PduPersister getPduPersister(Context context) {
+        if ((sPersister == null)) {
+            sPersister = new PduPersister(context);
+        } else if (!context.equals(sPersister.mContext)) {
+            sPersister.release();
+            sPersister = new PduPersister(context);
+        }
+
+        return sPersister;
+    }
+
+    private void setEncodedStringValueToHeaders(
+            Cursor c, int columnIndex,
+            PduHeaders headers, int mapColumn) {
+        String s = c.getString(columnIndex);
+        if ((s != null) && (s.length() > 0)) {
+            int charsetColumnIndex = CHARSET_COLUMN_INDEX_MAP.get(mapColumn);
+            int charset = c.getInt(charsetColumnIndex);
+            EncodedStringValue value = new EncodedStringValue(
+                    charset, getBytes(s));
+            headers.setEncodedStringValue(value, mapColumn);
+        }
+    }
+
+    private void setTextStringToHeaders(
+            Cursor c, int columnIndex,
+            PduHeaders headers, int mapColumn) {
+        String s = c.getString(columnIndex);
+        if (s != null) {
+            headers.setTextString(getBytes(s), mapColumn);
+        }
+    }
+
+    private void setOctetToHeaders(
+            Cursor c, int columnIndex,
+            PduHeaders headers, int mapColumn) throws InvalidHeaderValueException {
+        if (!c.isNull(columnIndex)) {
+            int b = c.getInt(columnIndex);
+            headers.setOctet(b, mapColumn);
+        }
+    }
+
+    private void setLongToHeaders(
+            Cursor c, int columnIndex,
+            PduHeaders headers, int mapColumn) {
+        if (!c.isNull(columnIndex)) {
+            long l = c.getLong(columnIndex);
+            headers.setLongInteger(l, mapColumn);
+        }
+    }
+
+    @UnsupportedAppUsage
+    private Integer getIntegerFromPartColumn(Cursor c, int columnIndex) {
+        if (!c.isNull(columnIndex)) {
+            return c.getInt(columnIndex);
+        }
+        return null;
+    }
+
+    @UnsupportedAppUsage
+    private byte[] getByteArrayFromPartColumn(Cursor c, int columnIndex) {
+        if (!c.isNull(columnIndex)) {
+            return getBytes(c.getString(columnIndex));
+        }
+        return null;
+    }
+
+    private PduPart[] loadParts(long msgId) throws MmsException {
+        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
+                Uri.parse("content://mms/" + msgId + "/part"),
+                PART_PROJECTION, null, null, null);
+
+        PduPart[] parts = null;
+
+        try {
+            if ((c == null) || (c.getCount() == 0)) {
+                if (LOCAL_LOGV) {
+                    Log.v(TAG, "loadParts(" + msgId + "): no part to load.");
+                }
+                return null;
+            }
+
+            int partCount = c.getCount();
+            int partIdx = 0;
+            parts = new PduPart[partCount];
+            while (c.moveToNext()) {
+                PduPart part = new PduPart();
+                Integer charset = getIntegerFromPartColumn(
+                        c, PART_COLUMN_CHARSET);
+                if (charset != null) {
+                    part.setCharset(charset);
+                }
+
+                byte[] contentDisposition = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_CONTENT_DISPOSITION);
+                if (contentDisposition != null) {
+                    part.setContentDisposition(contentDisposition);
+                }
+
+                byte[] contentId = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_CONTENT_ID);
+                if (contentId != null) {
+                    part.setContentId(contentId);
+                }
+
+                byte[] contentLocation = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_CONTENT_LOCATION);
+                if (contentLocation != null) {
+                    part.setContentLocation(contentLocation);
+                }
+
+                byte[] contentType = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_CONTENT_TYPE);
+                if (contentType != null) {
+                    part.setContentType(contentType);
+                } else {
+                    throw new MmsException("Content-Type must be set.");
+                }
+
+                byte[] fileName = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_FILENAME);
+                if (fileName != null) {
+                    part.setFilename(fileName);
+                }
+
+                byte[] name = getByteArrayFromPartColumn(
+                        c, PART_COLUMN_NAME);
+                if (name != null) {
+                    part.setName(name);
+                }
+
+                // Construct a Uri for this part.
+                long partId = c.getLong(PART_COLUMN_ID);
+                Uri partURI = Uri.parse("content://mms/part/" + partId);
+                part.setDataUri(partURI);
+
+                // For images/audio/video, we won't keep their data in Part
+                // because their renderer accept Uri as source.
+                String type = toIsoString(contentType);
+                if (!ContentType.isImageType(type)
+                        && !ContentType.isAudioType(type)
+                        && !ContentType.isVideoType(type)) {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    InputStream is = null;
+
+                    // Store simple string values directly in the database instead of an
+                    // external file.  This makes the text searchable and retrieval slightly
+                    // faster.
+                    if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type)
+                            || ContentType.TEXT_HTML.equals(type)) {
+                        String text = c.getString(PART_COLUMN_TEXT);
+                        byte [] blob = new EncodedStringValue(text != null ? text : "")
+                            .getTextString();
+                        baos.write(blob, 0, blob.length);
+                    } else {
+
+                        try {
+                            is = mContentResolver.openInputStream(partURI);
+
+                            byte[] buffer = new byte[256];
+                            int len = is.read(buffer);
+                            while (len >= 0) {
+                                baos.write(buffer, 0, len);
+                                len = is.read(buffer);
+                            }
+                        } catch (IOException e) {
+                            Log.e(TAG, "Failed to load part data", e);
+                            c.close();
+                            throw new MmsException(e);
+                        } finally {
+                            if (is != null) {
+                                try {
+                                    is.close();
+                                } catch (IOException e) {
+                                    Log.e(TAG, "Failed to close stream", e);
+                                } // Ignore
+                            }
+                        }
+                    }
+                    part.setData(baos.toByteArray());
+                }
+                parts[partIdx++] = part;
+            }
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+
+        return parts;
+    }
+
+    private void loadAddress(long msgId, PduHeaders headers) {
+        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
+                Uri.parse("content://mms/" + msgId + "/addr"),
+                new String[] { Addr.ADDRESS, Addr.CHARSET, Addr.TYPE },
+                null, null, null);
+
+        if (c != null) {
+            try {
+                while (c.moveToNext()) {
+                    String addr = c.getString(0);
+                    if (!TextUtils.isEmpty(addr)) {
+                        int addrType = c.getInt(2);
+                        switch (addrType) {
+                            case PduHeaders.FROM:
+                                headers.setEncodedStringValue(
+                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
+                                        addrType);
+                                break;
+                            case PduHeaders.TO:
+                            case PduHeaders.CC:
+                            case PduHeaders.BCC:
+                                headers.appendEncodedStringValue(
+                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
+                                        addrType);
+                                break;
+                            default:
+                                Log.e(TAG, "Unknown address type: " + addrType);
+                                break;
+                        }
+                    }
+                }
+            } finally {
+                c.close();
+            }
+        }
+    }
+
+    /**
+     * Load a PDU from storage by given Uri.
+     *
+     * @param uri The Uri of the PDU to be loaded.
+     * @return A generic PDU object, it may be cast to dedicated PDU.
+     * @throws MmsException Failed to load some fields of a PDU.
+     */
+    @UnsupportedAppUsage
+    public GenericPdu load(Uri uri) throws MmsException {
+        GenericPdu pdu = null;
+        PduCacheEntry cacheEntry = null;
+        int msgBox = 0;
+        long threadId = -1;
+        try {
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "load: " + uri + " blocked by isUpdating()");
+                    }
+                    try {
+                        PDU_CACHE_INSTANCE.wait();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "load: ", e);
+                    }
+                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
+                    if (cacheEntry != null) {
+                        return cacheEntry.getPdu();
+                    }
+                }
+                // Tell the cache to indicate to other callers that this item
+                // is currently being updated.
+                PDU_CACHE_INSTANCE.setUpdating(uri, true);
+            }
+
+            Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
+                    PDU_PROJECTION, null, null, null);
+            PduHeaders headers = new PduHeaders();
+            Set<Entry<Integer, Integer>> set;
+            long msgId = ContentUris.parseId(uri);
+
+            try {
+                if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
+                    throw new MmsException("Bad uri: " + uri);
+                }
+
+                msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
+                threadId = c.getLong(PDU_COLUMN_THREAD_ID);
+
+                set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setEncodedStringValueToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setTextStringToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = OCTET_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setOctetToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+
+                set = LONG_COLUMN_INDEX_MAP.entrySet();
+                for (Entry<Integer, Integer> e : set) {
+                    setLongToHeaders(
+                            c, e.getValue(), headers, e.getKey());
+                }
+            } finally {
+                if (c != null) {
+                    c.close();
+                }
+            }
+
+            // Check whether 'msgId' has been assigned a valid value.
+            if (msgId == -1L) {
+                throw new MmsException("Error! ID of the message: -1.");
+            }
+
+            // Load address information of the MM.
+            loadAddress(msgId, headers);
+
+            int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
+            PduBody body = new PduBody();
+
+            // For PDU which type is M_retrieve.conf or Send.req, we should
+            // load multiparts and put them into the body of the PDU.
+            if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
+                    || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
+                PduPart[] parts = loadParts(msgId);
+                if (parts != null) {
+                    int partsNum = parts.length;
+                    for (int i = 0; i < partsNum; i++) {
+                        body.addPart(parts[i]);
+                    }
+                }
+            }
+
+            switch (msgType) {
+            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
+                pdu = new NotificationInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
+                pdu = new DeliveryInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
+                pdu = new ReadOrigInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
+                pdu = new RetrieveConf(headers, body);
+                break;
+            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
+                pdu = new SendReq(headers, body);
+                break;
+            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
+                pdu = new AcknowledgeInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
+                pdu = new NotifyRespInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
+                pdu = new ReadRecInd(headers);
+                break;
+            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
+            case PduHeaders.MESSAGE_TYPE_FORWARD_REQ:
+            case PduHeaders.MESSAGE_TYPE_FORWARD_CONF:
+            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ:
+            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF:
+            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ:
+            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF:
+            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ:
+            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF:
+            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ:
+            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF:
+            case PduHeaders.MESSAGE_TYPE_MBOX_DESCR:
+            case PduHeaders.MESSAGE_TYPE_DELETE_REQ:
+            case PduHeaders.MESSAGE_TYPE_DELETE_CONF:
+            case PduHeaders.MESSAGE_TYPE_CANCEL_REQ:
+            case PduHeaders.MESSAGE_TYPE_CANCEL_CONF:
+                throw new MmsException(
+                        "Unsupported PDU type: " + Integer.toHexString(msgType));
+
+            default:
+                throw new MmsException(
+                        "Unrecognized PDU type: " + Integer.toHexString(msgType));
+            }
+        } finally {
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (pdu != null) {
+                    assert(PDU_CACHE_INSTANCE.get(uri) == null);
+                    // Update the cache entry with the real info
+                    cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
+                    PDU_CACHE_INSTANCE.put(uri, cacheEntry);
+                }
+                PDU_CACHE_INSTANCE.setUpdating(uri, false);
+                PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead
+            }
+        }
+        return pdu;
+    }
+
+    @UnsupportedAppUsage
+    private void persistAddress(
+            long msgId, int type, EncodedStringValue[] array) {
+        ContentValues values = new ContentValues(3);
+
+        for (EncodedStringValue addr : array) {
+            values.clear(); // Clear all values first.
+            values.put(Addr.ADDRESS, toIsoString(addr.getTextString()));
+            values.put(Addr.CHARSET, addr.getCharacterSet());
+            values.put(Addr.TYPE, type);
+
+            Uri uri = Uri.parse("content://mms/" + msgId + "/addr");
+            SqliteWrapper.insert(mContext, mContentResolver, uri, values);
+        }
+    }
+
+    @UnsupportedAppUsage
+    private static String getPartContentType(PduPart part) {
+        return part.getContentType() == null ? null : toIsoString(part.getContentType());
+    }
+
+    @UnsupportedAppUsage
+    public Uri persistPart(PduPart part, long msgId, HashMap<Uri, InputStream> preOpenedFiles)
+            throws MmsException {
+        Uri uri = Uri.parse("content://mms/" + msgId + "/part");
+        ContentValues values = new ContentValues(8);
+
+        int charset = part.getCharset();
+        if (charset != 0 ) {
+            values.put(Part.CHARSET, charset);
+        }
+
+        String contentType = getPartContentType(part);
+        if (contentType != null) {
+            // There is no "image/jpg" in Android (and it's an invalid mimetype).
+            // Change it to "image/jpeg"
+            if (ContentType.IMAGE_JPG.equals(contentType)) {
+                contentType = ContentType.IMAGE_JPEG;
+            }
+
+            values.put(Part.CONTENT_TYPE, contentType);
+            // To ensure the SMIL part is always the first part.
+            if (ContentType.APP_SMIL.equals(contentType)) {
+                values.put(Part.SEQ, -1);
+            }
+        } else {
+            throw new MmsException("MIME type of the part must be set.");
+        }
+
+        if (part.getFilename() != null) {
+            String fileName = new String(part.getFilename());
+            values.put(Part.FILENAME, fileName);
+        }
+
+        if (part.getName() != null) {
+            String name = new String(part.getName());
+            values.put(Part.NAME, name);
+        }
+
+        Object value = null;
+        if (part.getContentDisposition() != null) {
+            value = toIsoString(part.getContentDisposition());
+            values.put(Part.CONTENT_DISPOSITION, (String) value);
+        }
+
+        if (part.getContentId() != null) {
+            value = toIsoString(part.getContentId());
+            values.put(Part.CONTENT_ID, (String) value);
+        }
+
+        if (part.getContentLocation() != null) {
+            value = toIsoString(part.getContentLocation());
+            values.put(Part.CONTENT_LOCATION, (String) value);
+        }
+
+        Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
+        if (res == null) {
+            throw new MmsException("Failed to persist part, return null.");
+        }
+
+        persistData(part, res, contentType, preOpenedFiles);
+        // After successfully store the data, we should update
+        // the dataUri of the part.
+        part.setDataUri(res);
+
+        return res;
+    }
+
+    /**
+     * Save data of the part into storage. The source data may be given
+     * by a byte[] or a Uri. If it's a byte[], directly save it
+     * into storage, otherwise load source data from the dataUri and then
+     * save it. If the data is an image, we may scale down it according
+     * to user preference.
+     *
+     * @param part The PDU part which contains data to be saved.
+     * @param uri The URI of the part.
+     * @param contentType The MIME type of the part.
+     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
+     * @throws MmsException Cannot find source data or error occurred
+     *         while saving the data.
+     */
+    private void persistData(PduPart part, Uri uri,
+            String contentType, HashMap<Uri, InputStream> preOpenedFiles)
+            throws MmsException {
+        OutputStream os = null;
+        InputStream is = null;
+        DrmConvertSession drmConvertSession = null;
+        Uri dataUri = null;
+        String path = null;
+
+        try {
+            byte[] data = part.getData();
+            if (ContentType.TEXT_PLAIN.equals(contentType)
+                    || ContentType.APP_SMIL.equals(contentType)
+                    || ContentType.TEXT_HTML.equals(contentType)) {
+                ContentValues cv = new ContentValues();
+                if (data == null) {
+                    data = new String("").getBytes(CharacterSets.DEFAULT_CHARSET_NAME);
+                }
+                cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString());
+                if (mContentResolver.update(uri, cv, null, null) != 1) {
+                    throw new MmsException("unable to update " + uri.toString());
+                }
+            } else {
+                boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
+                if (isDrm) {
+                    if (uri != null) {
+                        try (ParcelFileDescriptor pfd =
+                                mContentResolver.openFileDescriptor(uri, "r")) {
+                            if (pfd.getStatSize() > 0) {
+                                // we're not going to re-persist and re-encrypt an already
+                                // converted drm file
+                                return;
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
+                        }
+                    }
+                    // We haven't converted the file yet, start the conversion
+                    drmConvertSession = DrmConvertSession.open(mContext, contentType);
+                    if (drmConvertSession == null) {
+                        throw new MmsException("Mimetype " + contentType +
+                                " can not be converted.");
+                    }
+                }
+                // uri can look like:
+                // content://mms/part/98
+                os = mContentResolver.openOutputStream(uri);
+                if (data == null) {
+                    dataUri = part.getDataUri();
+                    if ((dataUri == null) || (dataUri.equals(uri))) {
+                        Log.w(TAG, "Can't find data for this part.");
+                        return;
+                    }
+                    // dataUri can look like:
+                    // content://com.google.android.gallery3d.provider/picasa/item/5720646660183715586
+                    if (preOpenedFiles != null && preOpenedFiles.containsKey(dataUri)) {
+                        is = preOpenedFiles.get(dataUri);
+                    }
+                    if (is == null) {
+                        is = mContentResolver.openInputStream(dataUri);
+                    }
+
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "Saving data to: " + uri);
+                    }
+
+                    byte[] buffer = new byte[8192];
+                    for (int len = 0; (len = is.read(buffer)) != -1; ) {
+                        if (!isDrm) {
+                            os.write(buffer, 0, len);
+                        } else {
+                            byte[] convertedData = drmConvertSession.convert(buffer, len);
+                            if (convertedData != null) {
+                                os.write(convertedData, 0, convertedData.length);
+                            } else {
+                                throw new MmsException("Error converting drm data.");
+                            }
+                        }
+                    }
+                } else {
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "Saving data to: " + uri);
+                    }
+                    if (!isDrm) {
+                        os.write(data);
+                    } else {
+                        dataUri = uri;
+                        byte[] convertedData = drmConvertSession.convert(data, data.length);
+                        if (convertedData != null) {
+                            os.write(convertedData, 0, convertedData.length);
+                        } else {
+                            throw new MmsException("Error converting drm data.");
+                        }
+                    }
+                }
+            }
+        } catch (FileNotFoundException e) {
+            Log.e(TAG, "Failed to open Input/Output stream.", e);
+            throw new MmsException(e);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to read/write data.", e);
+            throw new MmsException(e);
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "IOException while closing: " + os, e);
+                } // Ignore
+            }
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "IOException while closing: " + is, e);
+                } // Ignore
+            }
+            if (drmConvertSession != null) {
+                drmConvertSession.close(path);
+
+                // Reset the permissions on the encrypted part file so everyone has only read
+                // permission.
+                File f = new File(path);
+                ContentValues values = new ContentValues(0);
+                SqliteWrapper.update(mContext, mContentResolver,
+                                     Uri.parse("content://mms/resetFilePerm/" + f.getName()),
+                                     values, null, null);
+            }
+        }
+    }
+
+    @UnsupportedAppUsage
+    private void updateAddress(
+            long msgId, int type, EncodedStringValue[] array) {
+        // Delete old address information and then insert new ones.
+        SqliteWrapper.delete(mContext, mContentResolver,
+                Uri.parse("content://mms/" + msgId + "/addr"),
+                Addr.TYPE + "=" + type, null);
+
+        persistAddress(msgId, type, array);
+    }
+
+    /**
+     * Update headers of a SendReq.
+     *
+     * @param uri The PDU which need to be updated.
+     * @param pdu New headers.
+     * @throws MmsException Bad URI or updating failed.
+     */
+    @UnsupportedAppUsage
+    public void updateHeaders(Uri uri, SendReq sendReq) {
+        synchronized(PDU_CACHE_INSTANCE) {
+            // If the cache item is getting updated, wait until it's done updating before
+            // purging it.
+            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                if (LOCAL_LOGV) {
+                    Log.v(TAG, "updateHeaders: " + uri + " blocked by isUpdating()");
+                }
+                try {
+                    PDU_CACHE_INSTANCE.wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "updateHeaders: ", e);
+                }
+            }
+        }
+        PDU_CACHE_INSTANCE.purge(uri);
+
+        ContentValues values = new ContentValues(10);
+        byte[] contentType = sendReq.getContentType();
+        if (contentType != null) {
+            values.put(Mms.CONTENT_TYPE, toIsoString(contentType));
+        }
+
+        long date = sendReq.getDate();
+        if (date != -1) {
+            values.put(Mms.DATE, date);
+        }
+
+        int deliveryReport = sendReq.getDeliveryReport();
+        if (deliveryReport != 0) {
+            values.put(Mms.DELIVERY_REPORT, deliveryReport);
+        }
+
+        long expiry = sendReq.getExpiry();
+        if (expiry != -1) {
+            values.put(Mms.EXPIRY, expiry);
+        }
+
+        byte[] msgClass = sendReq.getMessageClass();
+        if (msgClass != null) {
+            values.put(Mms.MESSAGE_CLASS, toIsoString(msgClass));
+        }
+
+        int priority = sendReq.getPriority();
+        if (priority != 0) {
+            values.put(Mms.PRIORITY, priority);
+        }
+
+        int readReport = sendReq.getReadReport();
+        if (readReport != 0) {
+            values.put(Mms.READ_REPORT, readReport);
+        }
+
+        byte[] transId = sendReq.getTransactionId();
+        if (transId != null) {
+            values.put(Mms.TRANSACTION_ID, toIsoString(transId));
+        }
+
+        EncodedStringValue subject = sendReq.getSubject();
+        if (subject != null) {
+            values.put(Mms.SUBJECT, toIsoString(subject.getTextString()));
+            values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet());
+        } else {
+            values.put(Mms.SUBJECT, "");
+        }
+
+        long messageSize = sendReq.getMessageSize();
+        if (messageSize > 0) {
+            values.put(Mms.MESSAGE_SIZE, messageSize);
+        }
+
+        PduHeaders headers = sendReq.getPduHeaders();
+        HashSet<String> recipients = new HashSet<String>();
+        for (int addrType : ADDRESS_FIELDS) {
+            EncodedStringValue[] array = null;
+            if (addrType == PduHeaders.FROM) {
+                EncodedStringValue v = headers.getEncodedStringValue(addrType);
+                if (v != null) {
+                    array = new EncodedStringValue[1];
+                    array[0] = v;
+                }
+            } else {
+                array = headers.getEncodedStringValues(addrType);
+            }
+
+            if (array != null) {
+                long msgId = ContentUris.parseId(uri);
+                updateAddress(msgId, addrType, array);
+                if (addrType == PduHeaders.TO) {
+                    for (EncodedStringValue v : array) {
+                        if (v != null) {
+                            recipients.add(v.getString());
+                        }
+                    }
+                }
+            }
+        }
+        if (!recipients.isEmpty()) {
+            long threadId = Threads.getOrCreateThreadId(mContext, recipients);
+            values.put(Mms.THREAD_ID, threadId);
+        }
+
+        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
+    }
+
+    private void updatePart(Uri uri, PduPart part, HashMap<Uri, InputStream> preOpenedFiles)
+            throws MmsException {
+        ContentValues values = new ContentValues(7);
+
+        int charset = part.getCharset();
+        if (charset != 0 ) {
+            values.put(Part.CHARSET, charset);
+        }
+
+        String contentType = null;
+        if (part.getContentType() != null) {
+            contentType = toIsoString(part.getContentType());
+            values.put(Part.CONTENT_TYPE, contentType);
+        } else {
+            throw new MmsException("MIME type of the part must be set.");
+        }
+
+        if (part.getFilename() != null) {
+            String fileName = new String(part.getFilename());
+            values.put(Part.FILENAME, fileName);
+        }
+
+        if (part.getName() != null) {
+            String name = new String(part.getName());
+            values.put(Part.NAME, name);
+        }
+
+        Object value = null;
+        if (part.getContentDisposition() != null) {
+            value = toIsoString(part.getContentDisposition());
+            values.put(Part.CONTENT_DISPOSITION, (String) value);
+        }
+
+        if (part.getContentId() != null) {
+            value = toIsoString(part.getContentId());
+            values.put(Part.CONTENT_ID, (String) value);
+        }
+
+        if (part.getContentLocation() != null) {
+            value = toIsoString(part.getContentLocation());
+            values.put(Part.CONTENT_LOCATION, (String) value);
+        }
+
+        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
+
+        // Only update the data when:
+        // 1. New binary data supplied or
+        // 2. The Uri of the part is different from the current one.
+        if ((part.getData() != null)
+                || (!uri.equals(part.getDataUri()))) {
+            persistData(part, uri, contentType, preOpenedFiles);
+        }
+    }
+
+    /**
+     * Update all parts of a PDU.
+     *
+     * @param uri The PDU which need to be updated.
+     * @param body New message body of the PDU.
+     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
+     * @throws MmsException Bad URI or updating failed.
+     */
+    @UnsupportedAppUsage
+    public void updateParts(Uri uri, PduBody body, HashMap<Uri, InputStream> preOpenedFiles)
+            throws MmsException {
+        try {
+            PduCacheEntry cacheEntry;
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                    if (LOCAL_LOGV) {
+                        Log.v(TAG, "updateParts: " + uri + " blocked by isUpdating()");
+                    }
+                    try {
+                        PDU_CACHE_INSTANCE.wait();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "updateParts: ", e);
+                    }
+                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
+                    if (cacheEntry != null) {
+                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
+                    }
+                }
+                // Tell the cache to indicate to other callers that this item
+                // is currently being updated.
+                PDU_CACHE_INSTANCE.setUpdating(uri, true);
+            }
+
+            ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
+            HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();
+
+            int partsNum = body.getPartsNum();
+            StringBuilder filter = new StringBuilder().append('(');
+            for (int i = 0; i < partsNum; i++) {
+                PduPart part = body.getPart(i);
+                Uri partUri = part.getDataUri();
+                if ((partUri == null) || TextUtils.isEmpty(partUri.getAuthority())
+                        || !partUri.getAuthority().startsWith("mms")) {
+                    toBeCreated.add(part);
+                } else {
+                    toBeUpdated.put(partUri, part);
+
+                    // Don't use 'i > 0' to determine whether we should append
+                    // 'AND' since 'i = 0' may be skipped in another branch.
+                    if (filter.length() > 1) {
+                        filter.append(" AND ");
+                    }
+
+                    filter.append(Part._ID);
+                    filter.append("!=");
+                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
+                }
+            }
+            filter.append(')');
+
+            long msgId = ContentUris.parseId(uri);
+
+            // Remove the parts which doesn't exist anymore.
+            SqliteWrapper.delete(mContext, mContentResolver,
+                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
+                    filter.length() > 2 ? filter.toString() : null, null);
+
+            // Create new parts which didn't exist before.
+            for (PduPart part : toBeCreated) {
+                persistPart(part, msgId, preOpenedFiles);
+            }
+
+            // Update the modified parts.
+            for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
+                updatePart(e.getKey(), e.getValue(), preOpenedFiles);
+            }
+        } finally {
+            synchronized(PDU_CACHE_INSTANCE) {
+                PDU_CACHE_INSTANCE.setUpdating(uri, false);
+                PDU_CACHE_INSTANCE.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Persist a PDU object to specific location in the storage.
+     *
+     * @param pdu The PDU object to be stored.
+     * @param uri Where to store the given PDU object.
+     * @param createThreadId if true, this function may create a thread id for the recipients
+     * @param groupMmsEnabled if true, all of the recipients addressed in the PDU will be used
+     *  to create the associated thread. When false, only the sender will be used in finding or
+     *  creating the appropriate thread or conversation.
+     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
+     * @return A Uri which can be used to access the stored PDU.
+     */
+
+    @UnsupportedAppUsage
+    public Uri persist(GenericPdu pdu, Uri uri, boolean createThreadId, boolean groupMmsEnabled,
+            HashMap<Uri, InputStream> preOpenedFiles)
+            throws MmsException {
+        if (uri == null) {
+            throw new MmsException("Uri may not be null.");
+        }
+        long msgId = -1;
+        try {
+            msgId = ContentUris.parseId(uri);
+        } catch (NumberFormatException e) {
+            // the uri ends with "inbox" or something else like that
+        }
+        boolean existingUri = msgId != -1;
+
+        if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
+            throw new MmsException(
+                    "Bad destination, must be one of "
+                    + "content://mms/inbox, content://mms/sent, "
+                    + "content://mms/drafts, content://mms/outbox, "
+                    + "content://mms/temp.");
+        }
+        synchronized(PDU_CACHE_INSTANCE) {
+            // If the cache item is getting updated, wait until it's done updating before
+            // purging it.
+            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                if (LOCAL_LOGV) {
+                    Log.v(TAG, "persist: " + uri + " blocked by isUpdating()");
+                }
+                try {
+                    PDU_CACHE_INSTANCE.wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "persist1: ", e);
+                }
+            }
+        }
+        PDU_CACHE_INSTANCE.purge(uri);
+
+        PduHeaders header = pdu.getPduHeaders();
+        PduBody body = null;
+        ContentValues values = new ContentValues();
+        Set<Entry<Integer, String>> set;
+
+        set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet();
+        for (Entry<Integer, String> e : set) {
+            int field = e.getKey();
+            EncodedStringValue encodedString = header.getEncodedStringValue(field);
+            if (encodedString != null) {
+                String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field);
+                values.put(e.getValue(), toIsoString(encodedString.getTextString()));
+                values.put(charsetColumn, encodedString.getCharacterSet());
+            }
+        }
+
+        set = TEXT_STRING_COLUMN_NAME_MAP.entrySet();
+        for (Entry<Integer, String> e : set){
+            byte[] text = header.getTextString(e.getKey());
+            if (text != null) {
+                values.put(e.getValue(), toIsoString(text));
+            }
+        }
+
+        set = OCTET_COLUMN_NAME_MAP.entrySet();
+        for (Entry<Integer, String> e : set){
+            int b = header.getOctet(e.getKey());
+            if (b != 0) {
+                values.put(e.getValue(), b);
+            }
+        }
+
+        set = LONG_COLUMN_NAME_MAP.entrySet();
+        for (Entry<Integer, String> e : set){
+            long l = header.getLongInteger(e.getKey());
+            if (l != -1L) {
+                values.put(e.getValue(), l);
+            }
+        }
+
+        HashMap<Integer, EncodedStringValue[]> addressMap =
+                new HashMap<Integer, EncodedStringValue[]>(ADDRESS_FIELDS.length);
+        // Save address information.
+        for (int addrType : ADDRESS_FIELDS) {
+            EncodedStringValue[] array = null;
+            if (addrType == PduHeaders.FROM) {
+                EncodedStringValue v = header.getEncodedStringValue(addrType);
+                if (v != null) {
+                    array = new EncodedStringValue[1];
+                    array[0] = v;
+                }
+            } else {
+                array = header.getEncodedStringValues(addrType);
+            }
+            addressMap.put(addrType, array);
+        }
+
+        HashSet<String> recipients = new HashSet<String>();
+        int msgType = pdu.getMessageType();
+        // Here we only allocate thread ID for M-Notification.ind,
+        // M-Retrieve.conf and M-Send.req.
+        // Some of other PDU types may be allocated a thread ID outside
+        // this scope.
+        if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
+                || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
+                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
+            switch (msgType) {
+                case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
+                case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
+                    loadRecipients(PduHeaders.FROM, recipients, addressMap, false);
+
+                    // For received messages when group MMS is enabled, we want to associate this
+                    // message with the thread composed of all the recipients -- all but our own
+                    // number, that is. This includes the person who sent the
+                    // message or the FROM field (above) in addition to the other people the message
+                    // was addressed to or the TO field. Our own number is in that TO field and
+                    // we have to ignore it in loadRecipients.
+                    if (groupMmsEnabled) {
+                        loadRecipients(PduHeaders.TO, recipients, addressMap, true);
+
+                        // Also load any numbers in the CC field to address group messaging
+                        // compatibility issues with devices that place numbers in this field
+                        // for group messages.
+                        loadRecipients(PduHeaders.CC, recipients, addressMap, true);
+                    }
+                    break;
+                case PduHeaders.MESSAGE_TYPE_SEND_REQ:
+                    loadRecipients(PduHeaders.TO, recipients, addressMap, false);
+                    break;
+            }
+            long threadId = 0;
+            if (createThreadId && !recipients.isEmpty()) {
+                // Given all the recipients associated with this message, find (or create) the
+                // correct thread.
+                threadId = Threads.getOrCreateThreadId(mContext, recipients);
+            }
+            values.put(Mms.THREAD_ID, threadId);
+        }
+
+        // Save parts first to avoid inconsistent message is loaded
+        // while saving the parts.
+        long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
+
+        // Figure out if this PDU is a text-only message
+        boolean textOnly = true;
+
+        // Sum up the total message size
+        int messageSize = 0;
+
+        // Get body if the PDU is a RetrieveConf or SendReq.
+        if (pdu instanceof MultimediaMessagePdu) {
+            body = ((MultimediaMessagePdu) pdu).getBody();
+            // Start saving parts if necessary.
+            if (body != null) {
+                int partsNum = body.getPartsNum();
+                if (partsNum > 2) {
+                    // For a text-only message there will be two parts: 1-the SMIL, 2-the text.
+                    // Down a few lines below we're checking to make sure we've only got SMIL or
+                    // text. We also have to check then we don't have more than two parts.
+                    // Otherwise, a slideshow with two text slides would be marked as textOnly.
+                    textOnly = false;
+                }
+                for (int i = 0; i < partsNum; i++) {
+                    PduPart part = body.getPart(i);
+                    messageSize += part.getDataLength();
+                    persistPart(part, dummyId, preOpenedFiles);
+
+                    // If we've got anything besides text/plain or SMIL part, then we've got
+                    // an mms message with some other type of attachment.
+                    String contentType = getPartContentType(part);
+                    if (contentType != null && !ContentType.APP_SMIL.equals(contentType)
+                            && !ContentType.TEXT_PLAIN.equals(contentType)) {
+                        textOnly = false;
+                    }
+                }
+            }
+        }
+        // Record whether this mms message is a simple plain text or not. This is a hint for the
+        // UI.
+        values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0);
+        // The message-size might already have been inserted when parsing the
+        // PDU header. If not, then we insert the message size as well.
+        if (values.getAsInteger(Mms.MESSAGE_SIZE) == null) {
+            values.put(Mms.MESSAGE_SIZE, messageSize);
+        }
+
+        Uri res = null;
+        if (existingUri) {
+            res = uri;
+            SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
+        } else {
+            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
+            if (res == null) {
+                throw new MmsException("persist() failed: return null.");
+            }
+            // Get the real ID of the PDU and update all parts which were
+            // saved with the dummy ID.
+            msgId = ContentUris.parseId(res);
+        }
+
+        values = new ContentValues(1);
+        values.put(Part.MSG_ID, msgId);
+        SqliteWrapper.update(mContext, mContentResolver,
+                             Uri.parse("content://mms/" + dummyId + "/part"),
+                             values, null, null);
+        // We should return the longest URI of the persisted PDU, for
+        // example, if input URI is "content://mms/inbox" and the _ID of
+        // persisted PDU is '8', we should return "content://mms/inbox/8"
+        // instead of "content://mms/8".
+        // FIXME: Should the MmsProvider be responsible for this???
+        if (!existingUri) {
+            res = Uri.parse(uri + "/" + msgId);
+        }
+
+        // Save address information.
+        for (int addrType : ADDRESS_FIELDS) {
+            EncodedStringValue[] array = addressMap.get(addrType);
+            if (array != null) {
+                persistAddress(msgId, addrType, array);
+            }
+        }
+
+        return res;
+    }
+
+    /**
+     * For a given address type, extract the recipients from the headers.
+     *
+     * @param addressType can be PduHeaders.FROM, PduHeaders.TO or PduHeaders.CC
+     * @param recipients a HashSet that is loaded with the recipients from the FROM, TO or CC headers
+     * @param addressMap a HashMap of the addresses from the ADDRESS_FIELDS header
+     * @param excludeMyNumber if true, the number of this phone will be excluded from recipients
+     */
+    @UnsupportedAppUsage
+    private void loadRecipients(int addressType, HashSet<String> recipients,
+            HashMap<Integer, EncodedStringValue[]> addressMap, boolean excludeMyNumber) {
+        EncodedStringValue[] array = addressMap.get(addressType);
+        if (array == null) {
+            return;
+        }
+        // If the TO recipients is only a single address, then we can skip loadRecipients when
+        // we're excluding our own number because we know that address is our own.
+        if (excludeMyNumber && array.length == 1) {
+            return;
+        }
+        final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext);
+        final Set<String> myPhoneNumbers = new HashSet<String>();
+        if (excludeMyNumber) {
+            // Build a list of my phone numbers from the various sims.
+            for (int subid : subscriptionManager.getActiveSubscriptionIdList()) {
+                final String myNumber = mTelephonyManager.getLine1Number(subid);
+                if (myNumber != null) {
+                    myPhoneNumbers.add(myNumber);
+                }
+            }
+        }
+
+        for (EncodedStringValue v : array) {
+            if (v != null) {
+                final String number = v.getString();
+                if (excludeMyNumber) {
+                    for (final String myNumber : myPhoneNumbers) {
+                        if (!PhoneNumberUtils.compare(number, myNumber)
+                                && !recipients.contains(number)) {
+                            // Only add numbers which aren't my own number.
+                            recipients.add(number);
+                            break;
+                        }
+                    }
+                } else if (!recipients.contains(number)){
+                    recipients.add(number);
+                }
+            }
+        }
+    }
+
+    /**
+     * Move a PDU object from one location to another.
+     *
+     * @param from Specify the PDU object to be moved.
+     * @param to The destination location, should be one of the following:
+     *        "content://mms/inbox", "content://mms/sent",
+     *        "content://mms/drafts", "content://mms/outbox",
+     *        "content://mms/trash".
+     * @return New Uri of the moved PDU.
+     * @throws MmsException Error occurred while moving the message.
+     */
+    @UnsupportedAppUsage
+    public Uri move(Uri from, Uri to) throws MmsException {
+        // Check whether the 'msgId' has been assigned a valid value.
+        long msgId = ContentUris.parseId(from);
+        if (msgId == -1L) {
+            throw new MmsException("Error! ID of the message: -1.");
+        }
+
+        // Get corresponding int value of destination box.
+        Integer msgBox = MESSAGE_BOX_MAP.get(to);
+        if (msgBox == null) {
+            throw new MmsException(
+                    "Bad destination, must be one of "
+                    + "content://mms/inbox, content://mms/sent, "
+                    + "content://mms/drafts, content://mms/outbox, "
+                    + "content://mms/temp.");
+        }
+
+        ContentValues values = new ContentValues(1);
+        values.put(Mms.MESSAGE_BOX, msgBox);
+        SqliteWrapper.update(mContext, mContentResolver, from, values, null, null);
+        return ContentUris.withAppendedId(to, msgId);
+    }
+
+    /**
+     * Wrap a byte[] into a String.
+     */
+    @UnsupportedAppUsage
+    public static String toIsoString(byte[] bytes) {
+        try {
+            return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
+        } catch (UnsupportedEncodingException e) {
+            // Impossible to reach here!
+            Log.e(TAG, "ISO_8859_1 must be supported!", e);
+            return "";
+        }
+    }
+
+    /**
+     * Unpack a given String into a byte[].
+     */
+    @UnsupportedAppUsage
+    public static byte[] getBytes(String data) {
+        try {
+            return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
+        } catch (UnsupportedEncodingException e) {
+            // Impossible to reach here!
+            Log.e(TAG, "ISO_8859_1 must be supported!", e);
+            return new byte[0];
+        }
+    }
+
+    /**
+     * Remove all objects in the temporary path.
+     */
+    public void release() {
+        Uri uri = Uri.parse(TEMPORARY_DRM_OBJECT_URI);
+        SqliteWrapper.delete(mContext, mContentResolver, uri, null, null);
+    }
+
+    /**
+     * Find all messages to be sent or downloaded before certain time.
+     */
+    @UnsupportedAppUsage
+    public Cursor getPendingMessages(long dueTime) {
+        Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon();
+        uriBuilder.appendQueryParameter("protocol", "mms");
+
+        String selection = PendingMessages.ERROR_TYPE + " < ?"
+                + " AND " + PendingMessages.DUE_TIME + " <= ?";
+
+        String[] selectionArgs = new String[] {
+                String.valueOf(MmsSms.ERR_TYPE_GENERIC_PERMANENT),
+                String.valueOf(dueTime)
+        };
+
+        return SqliteWrapper.query(mContext, mContentResolver,
+                uriBuilder.build(), null, selection, selectionArgs,
+                PendingMessages.DUE_TIME);
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
new file mode 100644
index 0000000..9d6535c
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.io.ByteArrayOutputStream;
+
+public class QuotedPrintable {
+    private static byte ESCAPE_CHAR = '=';
+
+    /**
+     * Decodes an array quoted-printable characters into an array of original bytes.
+     * Escaped characters are converted back to their original representation.
+     *
+     * <p>
+     * This function implements a subset of
+     * quoted-printable encoding specification (rule #1 and rule #2)
+     * as defined in RFC 1521.
+     * </p>
+     *
+     * @param bytes array of quoted-printable characters
+     * @return array of original bytes,
+     *         null if quoted-printable decoding is unsuccessful.
+     */
+    @UnsupportedAppUsage
+    public static final byte[] decodeQuotedPrintable(byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        for (int i = 0; i < bytes.length; i++) {
+            int b = bytes[i];
+            if (b == ESCAPE_CHAR) {
+                try {
+                    if('\r' == (char)bytes[i + 1] &&
+                            '\n' == (char)bytes[i + 2]) {
+                        i += 2;
+                        continue;
+                    }
+                    int u = Character.digit((char) bytes[++i], 16);
+                    int l = Character.digit((char) bytes[++i], 16);
+                    if (u == -1 || l == -1) {
+                        return null;
+                    }
+                    buffer.write((char) ((u << 4) + l));
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    return null;
+                }
+            } else {
+                buffer.write(b);
+            }
+        }
+        return buffer.toByteArray();
+    }
+}
diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
new file mode 100644
index 0000000..e38c62d
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+public class ReadOrigInd extends GenericPdu {
+    /**
+     * Empty constructor.
+     * Since the Pdu corresponding to this class is constructed
+     * by the Proxy-Relay server, this class is only instantiated
+     * by the Pdu Parser.
+     *
+     * @throws InvalidHeaderValueException if error occurs.
+     */
+    public ReadOrigInd() throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_READ_ORIG_IND);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    ReadOrigInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get Date value.
+     *
+     * @return the value
+     */
+    public long getDate() {
+        return mPduHeaders.getLongInteger(PduHeaders.DATE);
+    }
+
+    /**
+     * Set Date value.
+     *
+     * @param value the value
+     */
+    public void setDate(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.DATE);
+    }
+
+    /**
+     * Get From value.
+     * From-value = Value-length
+     *      (Address-present-token Encoded-string-value | Insert-address-token)
+     *
+     * @return the value
+     */
+    public EncodedStringValue getFrom() {
+       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+    }
+
+    /**
+     * Set From value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setFrom(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+    }
+
+    /**
+     * Get Message-ID value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageId() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Set Message-ID value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setMessageId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Get X-MMS-Read-status value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getReadStatus() {
+        return mPduHeaders.getOctet(PduHeaders.READ_STATUS);
+    }
+
+    /**
+     * Set X-MMS-Read-status value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    public void setReadStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.READ_STATUS);
+    }
+
+    /**
+     * Get To value.
+     *
+     * @return the value
+     */
+    public EncodedStringValue[] getTo() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.TO);
+    }
+
+    /**
+     * Set To value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setTo(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.TO);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
new file mode 100644
index 0000000..9696bc2
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+public class ReadRecInd extends GenericPdu {
+    /**
+     * Constructor, used when composing a M-ReadRec.ind pdu.
+     *
+     * @param from the from value
+     * @param messageId the message ID value
+     * @param mmsVersion current viersion of mms
+     * @param readStatus the read status value
+     * @param to the to value
+     * @throws InvalidHeaderValueException if parameters are invalid.
+     *         NullPointerException if messageId or to is null.
+     */
+    @UnsupportedAppUsage
+    public ReadRecInd(EncodedStringValue from,
+                      byte[] messageId,
+                      int mmsVersion,
+                      int readStatus,
+                      EncodedStringValue[] to) throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_READ_REC_IND);
+        setFrom(from);
+        setMessageId(messageId);
+        setMmsVersion(mmsVersion);
+        setTo(to);
+        setReadStatus(readStatus);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    ReadRecInd(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get Date value.
+     *
+     * @return the value
+     */
+    public long getDate() {
+        return mPduHeaders.getLongInteger(PduHeaders.DATE);
+    }
+
+    /**
+     * Set Date value.
+     *
+     * @param value the value
+     */
+    @UnsupportedAppUsage
+    public void setDate(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.DATE);
+    }
+
+    /**
+     * Get Message-ID value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageId() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Set Message-ID value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setMessageId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Get To value.
+     *
+     * @return the value
+     */
+    public EncodedStringValue[] getTo() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.TO);
+    }
+
+    /**
+     * Set To value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setTo(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.TO);
+    }
+
+    /**
+     * Get X-MMS-Read-status value.
+     *
+     * @return the value
+     */
+    public int getReadStatus() {
+        return mPduHeaders.getOctet(PduHeaders.READ_STATUS);
+    }
+
+    /**
+     * Set X-MMS-Read-status value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    public void setReadStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.READ_STATUS);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
new file mode 100644
index 0000000..03755af
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+/**
+ * M-Retrieve.conf Pdu.
+ */
+public class RetrieveConf extends MultimediaMessagePdu {
+    /**
+     * Empty constructor.
+     * Since the Pdu corresponding to this class is constructed
+     * by the Proxy-Relay server, this class is only instantiated
+     * by the Pdu Parser.
+     *
+     * @throws InvalidHeaderValueException if error occurs.
+     */
+    @UnsupportedAppUsage
+    public RetrieveConf() throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    RetrieveConf(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Constructor with given headers and body
+     *
+     * @param headers Headers for this PDU.
+     * @param body Body of this PDu.
+     */
+    @UnsupportedAppUsage
+    RetrieveConf(PduHeaders headers, PduBody body) {
+        super(headers, body);
+    }
+
+    /**
+     * Get CC value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue[] getCc() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.CC);
+    }
+
+    /**
+     * Add a "CC" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void addCc(EncodedStringValue value) {
+        mPduHeaders.appendEncodedStringValue(value, PduHeaders.CC);
+    }
+
+    /**
+     * Get Content-type value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getContentType() {
+        return mPduHeaders.getTextString(PduHeaders.CONTENT_TYPE);
+    }
+
+    /**
+     * Set Content-type value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setContentType(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.CONTENT_TYPE);
+    }
+
+    /**
+     * Get X-Mms-Delivery-Report value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getDeliveryReport() {
+        return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT);
+    }
+
+    /**
+     * Set X-Mms-Delivery-Report value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setDeliveryReport(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT);
+    }
+
+    /**
+     * Get From value.
+     * From-value = Value-length
+     *      (Address-present-token Encoded-string-value | Insert-address-token)
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getFrom() {
+       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+    }
+
+    /**
+     * Set From value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setFrom(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+    }
+
+    /**
+     * Get X-Mms-Message-Class value.
+     * Message-class-value = Class-identifier | Token-text
+     * Class-identifier = Personal | Advertisement | Informational | Auto
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageClass() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Set X-Mms-Message-Class value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setMessageClass(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Get Message-ID value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageId() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Set Message-ID value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setMessageId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Get X-Mms-Read-Report value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getReadReport() {
+        return mPduHeaders.getOctet(PduHeaders.READ_REPORT);
+    }
+
+    /**
+     * Set X-Mms-Read-Report value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setReadReport(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.READ_REPORT);
+    }
+
+    /**
+     * Get X-Mms-Retrieve-Status value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getRetrieveStatus() {
+        return mPduHeaders.getOctet(PduHeaders.RETRIEVE_STATUS);
+    }
+
+    /**
+     * Set X-Mms-Retrieve-Status value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setRetrieveStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.RETRIEVE_STATUS);
+    }
+
+    /**
+     * Get X-Mms-Retrieve-Text value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue getRetrieveText() {
+        return mPduHeaders.getEncodedStringValue(PduHeaders.RETRIEVE_TEXT);
+    }
+
+    /**
+     * Set X-Mms-Retrieve-Text value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setRetrieveText(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.RETRIEVE_TEXT);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setTransactionId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte getContentClass() {return 0x00;}
+     *     public void setApplicId(byte value) {}
+     *
+     *     public byte getDrmContent() {return 0x00;}
+     *     public void setDrmContent(byte value) {}
+     *
+     *     public byte getDistributionIndicator() {return 0x00;}
+     *     public void setDistributionIndicator(byte value) {}
+     *
+     *     public PreviouslySentByValue getPreviouslySentBy() {return null;}
+     *     public void setPreviouslySentBy(PreviouslySentByValue value) {}
+     *
+     *     public PreviouslySentDateValue getPreviouslySentDate() {}
+     *     public void setPreviouslySentDate(PreviouslySentDateValue value) {}
+     *
+     *     public MmFlagsValue getMmFlags() {return null;}
+     *     public void setMmFlags(MmFlagsValue value) {}
+     *
+     *     public MmStateValue getMmState() {return null;}
+     *     public void getMmState(MmStateValue value) {}
+     *
+     *     public byte[] getReplaceId() {return 0x00;}
+     *     public void setReplaceId(byte[] value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     *
+     *     public byte getReplyCharging() {return 0x00;}
+     *     public void setReplyCharging(byte value) {}
+     *
+     *     public byte getReplyChargingDeadline() {return 0x00;}
+     *     public void setReplyChargingDeadline(byte value) {}
+     *
+     *     public byte[] getReplyChargingId() {return 0x00;}
+     *     public void setReplyChargingId(byte[] value) {}
+     *
+     *     public long getReplyChargingSize() {return 0;}
+     *     public void setReplyChargingSize(long value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java
new file mode 100644
index 0000000..b859827
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/SendConf.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 Esmertec AG.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+public class SendConf extends GenericPdu {
+    /**
+     * Empty constructor.
+     * Since the Pdu corresponding to this class is constructed
+     * by the Proxy-Relay server, this class is only instantiated
+     * by the Pdu Parser.
+     *
+     * @throws InvalidHeaderValueException if error occurs.
+     */
+    @UnsupportedAppUsage
+    public SendConf() throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_SEND_CONF);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    @UnsupportedAppUsage
+    SendConf(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Get Message-ID value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageId() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Set Message-ID value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setMessageId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_ID);
+    }
+
+    /**
+     * Get X-Mms-Response-Status.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getResponseStatus() {
+        return mPduHeaders.getOctet(PduHeaders.RESPONSE_STATUS);
+    }
+
+    /**
+     * Set X-Mms-Response-Status.
+     *
+     * @param value the values
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    public void setResponseStatus(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.RESPONSE_STATUS);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    @UnsupportedAppUsage
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id field value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setTransactionId(byte[] value) {
+            mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *    public byte[] getContentLocation() {return null;}
+     *    public void setContentLocation(byte[] value) {}
+     *
+     *    public EncodedStringValue getResponseText() {return null;}
+     *    public void setResponseText(EncodedStringValue value) {}
+     *
+     *    public byte getStoreStatus() {return 0x00;}
+     *    public void setStoreStatus(byte value) {}
+     *
+     *    public byte[] getStoreStatusText() {return null;}
+     *    public void setStoreStatusText(byte[] value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java
new file mode 100644
index 0000000..c1b7f93
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/SendReq.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2007-2008 Esmertec AG.
+ * Copyright (C) 2007-2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.pdu;
+
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.InvalidHeaderValueException;
+
+public class SendReq extends MultimediaMessagePdu {
+    private static final String TAG = "SendReq";
+
+    @UnsupportedAppUsage
+    public SendReq() {
+        super();
+
+        try {
+            setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ);
+            setMmsVersion(PduHeaders.CURRENT_MMS_VERSION);
+            // FIXME: Content-type must be decided according to whether
+            // SMIL part present.
+            setContentType("application/vnd.wap.multipart.related".getBytes());
+            setFrom(new EncodedStringValue(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.getBytes()));
+            setTransactionId(generateTransactionId());
+        } catch (InvalidHeaderValueException e) {
+            // Impossible to reach here since all headers we set above are valid.
+            Log.e(TAG, "Unexpected InvalidHeaderValueException.", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    private byte[] generateTransactionId() {
+        String transactionId = "T" + Long.toHexString(System.currentTimeMillis());
+        return transactionId.getBytes();
+    }
+
+    /**
+     * Constructor, used when composing a M-Send.req pdu.
+     *
+     * @param contentType the content type value
+     * @param from the from value
+     * @param mmsVersion current viersion of mms
+     * @param transactionId the transaction-id value
+     * @throws InvalidHeaderValueException if parameters are invalid.
+     *         NullPointerException if contentType, form or transactionId is null.
+     */
+    public SendReq(byte[] contentType,
+                   EncodedStringValue from,
+                   int mmsVersion,
+                   byte[] transactionId) throws InvalidHeaderValueException {
+        super();
+        setMessageType(PduHeaders.MESSAGE_TYPE_SEND_REQ);
+        setContentType(contentType);
+        setFrom(from);
+        setMmsVersion(mmsVersion);
+        setTransactionId(transactionId);
+    }
+
+    /**
+     * Constructor with given headers.
+     *
+     * @param headers Headers for this PDU.
+     */
+    SendReq(PduHeaders headers) {
+        super(headers);
+    }
+
+    /**
+     * Constructor with given headers and body
+     *
+     * @param headers Headers for this PDU.
+     * @param body Body of this PDu.
+     */
+    @UnsupportedAppUsage
+    SendReq(PduHeaders headers, PduBody body) {
+        super(headers, body);
+    }
+
+    /**
+     * Get Bcc value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue[] getBcc() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.BCC);
+    }
+
+    /**
+     * Add a "BCC" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void addBcc(EncodedStringValue value) {
+        mPduHeaders.appendEncodedStringValue(value, PduHeaders.BCC);
+    }
+
+    /**
+     * Set "BCC" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setBcc(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.BCC);
+    }
+
+    /**
+     * Get CC value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public EncodedStringValue[] getCc() {
+        return mPduHeaders.getEncodedStringValues(PduHeaders.CC);
+    }
+
+    /**
+     * Add a "CC" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void addCc(EncodedStringValue value) {
+        mPduHeaders.appendEncodedStringValue(value, PduHeaders.CC);
+    }
+
+    /**
+     * Set "CC" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setCc(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.CC);
+    }
+
+    /**
+     * Get Content-type value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getContentType() {
+        return mPduHeaders.getTextString(PduHeaders.CONTENT_TYPE);
+    }
+
+    /**
+     * Set Content-type value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setContentType(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.CONTENT_TYPE);
+    }
+
+    /**
+     * Get X-Mms-Delivery-Report value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getDeliveryReport() {
+        return mPduHeaders.getOctet(PduHeaders.DELIVERY_REPORT);
+    }
+
+    /**
+     * Set X-Mms-Delivery-Report value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setDeliveryReport(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.DELIVERY_REPORT);
+    }
+
+    /**
+     * Get X-Mms-Expiry value.
+     *
+     * Expiry-value = Value-length
+     *      (Absolute-token Date-value | Relative-token Delta-seconds-value)
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getExpiry() {
+        return mPduHeaders.getLongInteger(PduHeaders.EXPIRY);
+    }
+
+    /**
+     * Set X-Mms-Expiry value.
+     *
+     * @param value the value
+     */
+    @UnsupportedAppUsage
+    public void setExpiry(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.EXPIRY);
+    }
+
+    /**
+     * Get X-Mms-MessageSize value.
+     *
+     * Expiry-value = size of message
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public long getMessageSize() {
+        return mPduHeaders.getLongInteger(PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
+     * Set X-Mms-MessageSize value.
+     *
+     * @param value the value
+     */
+    @UnsupportedAppUsage
+    public void setMessageSize(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
+     * Get X-Mms-Message-Class value.
+     * Message-class-value = Class-identifier | Token-text
+     * Class-identifier = Personal | Advertisement | Informational | Auto
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public byte[] getMessageClass() {
+        return mPduHeaders.getTextString(PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Set X-Mms-Message-Class value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setMessageClass(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.MESSAGE_CLASS);
+    }
+
+    /**
+     * Get X-Mms-Read-Report value.
+     *
+     * @return the value
+     */
+    @UnsupportedAppUsage
+    public int getReadReport() {
+        return mPduHeaders.getOctet(PduHeaders.READ_REPORT);
+    }
+
+    /**
+     * Set X-Mms-Read-Report value.
+     *
+     * @param value the value
+     * @throws InvalidHeaderValueException if the value is invalid.
+     */
+    @UnsupportedAppUsage
+    public void setReadReport(int value) throws InvalidHeaderValueException {
+        mPduHeaders.setOctet(value, PduHeaders.READ_REPORT);
+    }
+
+    /**
+     * Set "To" value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setTo(EncodedStringValue[] value) {
+        mPduHeaders.setEncodedStringValues(value, PduHeaders.TO);
+    }
+
+    /**
+     * Get X-Mms-Transaction-Id field value.
+     *
+     * @return the X-Mms-Report-Allowed value
+     */
+    @UnsupportedAppUsage
+    public byte[] getTransactionId() {
+        return mPduHeaders.getTextString(PduHeaders.TRANSACTION_ID);
+    }
+
+    /**
+     * Set X-Mms-Transaction-Id field value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    @UnsupportedAppUsage
+    public void setTransactionId(byte[] value) {
+        mPduHeaders.setTextString(value, PduHeaders.TRANSACTION_ID);
+    }
+
+    /*
+     * Optional, not supported header fields:
+     *
+     *     public byte getAdaptationAllowed() {return 0};
+     *     public void setAdaptationAllowed(btye value) {};
+     *
+     *     public byte[] getApplicId() {return null;}
+     *     public void setApplicId(byte[] value) {}
+     *
+     *     public byte[] getAuxApplicId() {return null;}
+     *     public void getAuxApplicId(byte[] value) {}
+     *
+     *     public byte getContentClass() {return 0x00;}
+     *     public void setApplicId(byte value) {}
+     *
+     *     public long getDeliveryTime() {return 0};
+     *     public void setDeliveryTime(long value) {};
+     *
+     *     public byte getDrmContent() {return 0x00;}
+     *     public void setDrmContent(byte value) {}
+     *
+     *     public MmFlagsValue getMmFlags() {return null;}
+     *     public void setMmFlags(MmFlagsValue value) {}
+     *
+     *     public MmStateValue getMmState() {return null;}
+     *     public void getMmState(MmStateValue value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     *
+     *     public byte getReplyCharging() {return 0x00;}
+     *     public void setReplyCharging(byte value) {}
+     *
+     *     public byte getReplyChargingDeadline() {return 0x00;}
+     *     public void setReplyChargingDeadline(byte value) {}
+     *
+     *     public byte[] getReplyChargingId() {return 0x00;}
+     *     public void setReplyChargingId(byte[] value) {}
+     *
+     *     public long getReplyChargingSize() {return 0;}
+     *     public void setReplyChargingSize(long value) {}
+     *
+     *     public byte[] getReplyApplicId() {return 0x00;}
+     *     public void setReplyApplicId(byte[] value) {}
+     *
+     *     public byte getStore() {return 0x00;}
+     *     public void setStore(byte value) {}
+     */
+}
diff --git a/telephony/common/com/google/android/mms/pdu/package.html b/telephony/common/com/google/android/mms/pdu/package.html
new file mode 100755
index 0000000..c9f96a6
--- /dev/null
+++ b/telephony/common/com/google/android/mms/pdu/package.html
@@ -0,0 +1,5 @@
+<body>
+
+{@hide}
+
+</body>
diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java
new file mode 100644
index 0000000..ab5d48a
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/AbstractCache.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2008 Esmertec AG.
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.util;
+
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.util.HashMap;
+
+public abstract class AbstractCache<K, V> {
+    private static final String TAG = "AbstractCache";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = false;
+
+    private static final int MAX_CACHED_ITEMS  = 500;
+
+    private final HashMap<K, CacheEntry<V>> mCacheMap;
+
+    @UnsupportedAppUsage
+    protected AbstractCache() {
+        mCacheMap = new HashMap<K, CacheEntry<V>>();
+    }
+
+    @UnsupportedAppUsage
+    public boolean put(K key, V value) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Trying to put " + key + " into cache.");
+        }
+
+        if (mCacheMap.size() >= MAX_CACHED_ITEMS) {
+            // TODO Should remove the oldest or least hit cached entry
+            // and then cache the new one.
+            if (LOCAL_LOGV) {
+                Log.v(TAG, "Failed! size limitation reached.");
+            }
+            return false;
+        }
+
+        if (key != null) {
+            CacheEntry<V> cacheEntry = new CacheEntry<V>();
+            cacheEntry.value = value;
+            mCacheMap.put(key, cacheEntry);
+
+            if (LOCAL_LOGV) {
+                Log.v(TAG, key + " cached, " + mCacheMap.size() + " items total.");
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @UnsupportedAppUsage
+    public V get(K key) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Trying to get " + key + " from cache.");
+        }
+
+        if (key != null) {
+            CacheEntry<V> cacheEntry = mCacheMap.get(key);
+            if (cacheEntry != null) {
+                cacheEntry.hit++;
+                if (LOCAL_LOGV) {
+                    Log.v(TAG, key + " hit " + cacheEntry.hit + " times.");
+                }
+                return cacheEntry.value;
+            }
+        }
+        return null;
+    }
+
+    @UnsupportedAppUsage
+    public V purge(K key) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Trying to purge " + key);
+        }
+
+        CacheEntry<V> v = mCacheMap.remove(key);
+
+        if (LOCAL_LOGV) {
+            Log.v(TAG, mCacheMap.size() + " items cached.");
+        }
+
+        return v != null ? v.value : null;
+    }
+
+    @UnsupportedAppUsage
+    public void purgeAll() {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Purging cache, " + mCacheMap.size()
+                    + " items dropped.");
+        }
+        mCacheMap.clear();
+    }
+
+    public int size() {
+        return mCacheMap.size();
+    }
+
+    private static class CacheEntry<V> {
+        int hit;
+        V value;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
new file mode 100644
index 0000000..118de46
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+public class DownloadDrmHelper {
+    private static final String TAG = "DownloadDrmHelper";
+
+    /** The MIME type of special DRM files */
+    public static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+
+    /** The extensions of special DRM files */
+    public static final String EXTENSION_DRM_MESSAGE = ".dm";
+
+    public static final String EXTENSION_INTERNAL_FWDL = ".fl";
+
+    /**
+     * Checks if the Media Type is a DRM Media Type
+     *
+     * @param drmManagerClient A DrmManagerClient
+     * @param mimetype Media Type to check
+     * @return True if the Media Type is DRM else false
+     */
+    public static boolean isDrmMimeType(Context context, String mimetype) {
+        boolean result = false;
+        if (context != null) {
+            try {
+                DrmManagerClient drmClient = new DrmManagerClient(context);
+                if (drmClient != null && mimetype != null && mimetype.length() > 0) {
+                    result = drmClient.canHandle("", mimetype);
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG,
+                        "DrmManagerClient instance could not be created, context is Illegal.");
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Checks if the Media Type needs to be DRM converted
+     *
+     * @param mimetype Media type of the content
+     * @return True if convert is needed else false
+     */
+    @UnsupportedAppUsage
+    public static boolean isDrmConvertNeeded(String mimetype) {
+        return MIMETYPE_DRM_MESSAGE.equals(mimetype);
+    }
+
+    /**
+     * Modifies the file extension for a DRM Forward Lock file NOTE: This
+     * function shouldn't be called if the file shouldn't be DRM converted
+     */
+    @UnsupportedAppUsage
+    public static String modifyDrmFwLockFileExtension(String filename) {
+        if (filename != null) {
+            int extensionIndex;
+            extensionIndex = filename.lastIndexOf(".");
+            if (extensionIndex != -1) {
+                filename = filename.substring(0, extensionIndex);
+            }
+            filename = filename.concat(EXTENSION_INTERNAL_FWDL);
+        }
+        return filename;
+    }
+
+    /**
+     * Gets the original mime type of DRM protected content.
+     *
+     * @param context The context
+     * @param path Path to the file
+     * @param containingMime The current mime type of the file i.e. the
+     *            containing mime type
+     * @return The original mime type of the file if DRM protected else the
+     *         currentMime
+     */
+    public static String getOriginalMimeType(Context context, String path, String containingMime) {
+        String result = containingMime;
+        DrmManagerClient drmClient = new DrmManagerClient(context);
+        try {
+            if (drmClient.canHandle(path, null)) {
+                result = drmClient.getOriginalMimeType(path);
+            }
+        } catch (IllegalArgumentException ex) {
+            Log.w(TAG,
+                    "Can't get original mime type since path is null or empty string.");
+        } catch (IllegalStateException ex) {
+            Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+        }
+        return result;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
new file mode 100644
index 0000000..0e8ec91
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.provider.Downloads;
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+public class DrmConvertSession {
+    private DrmManagerClient mDrmClient;
+    private int mConvertSessionId;
+    private static final String TAG = "DrmConvertSession";
+
+    private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) {
+        mDrmClient = drmClient;
+        mConvertSessionId = convertSessionId;
+    }
+
+    /**
+     * Start of converting a file.
+     *
+     * @param context The context of the application running the convert session.
+     * @param mimeType Mimetype of content that shall be converted.
+     * @return A convert session or null in case an error occurs.
+     */
+    @UnsupportedAppUsage
+    public static DrmConvertSession open(Context context, String mimeType) {
+        DrmManagerClient drmClient = null;
+        int convertSessionId = -1;
+        if (context != null && mimeType != null && !mimeType.equals("")) {
+            try {
+                drmClient = new DrmManagerClient(context);
+                try {
+                    convertSessionId = drmClient.openConvertSession(mimeType);
+                } catch (IllegalArgumentException e) {
+                    Log.w(TAG, "Conversion of Mimetype: " + mimeType
+                            + " is not supported.", e);
+                } catch (IllegalStateException e) {
+                    Log.w(TAG, "Could not access Open DrmFramework.", e);
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG,
+                        "DrmManagerClient instance could not be created, context is Illegal.");
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+            }
+        }
+
+        if (drmClient == null || convertSessionId < 0) {
+            return null;
+        } else {
+            return new DrmConvertSession(drmClient, convertSessionId);
+        }
+    }
+    /**
+     * Convert a buffer of data to protected format.
+     *
+     * @param buffer Buffer filled with data to convert.
+     * @param size The number of bytes that shall be converted.
+     * @return A Buffer filled with converted data, if execution is ok, in all
+     *         other case null.
+     */
+    @UnsupportedAppUsage
+    public byte [] convert(byte[] inBuffer, int size) {
+        byte[] result = null;
+        if (inBuffer != null) {
+            DrmConvertedStatus convertedStatus = null;
+            try {
+                if (size != inBuffer.length) {
+                    byte[] buf = new byte[size];
+                    System.arraycopy(inBuffer, 0, buf, 0, size);
+                    convertedStatus = mDrmClient.convertData(mConvertSessionId, buf);
+                } else {
+                    convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer);
+                }
+
+                if (convertedStatus != null &&
+                        convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK &&
+                        convertedStatus.convertedData != null) {
+                    result = convertedStatus.convertedData;
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+                        + mConvertSessionId, e);
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not convert data. Convertsession: " +
+                        mConvertSessionId, e);
+            }
+        } else {
+            throw new IllegalArgumentException("Parameter inBuffer is null");
+        }
+        return result;
+    }
+
+    /**
+     * Ends a conversion session of a file.
+     *
+     * @param fileName The filename of the converted file.
+     * @return Downloads.Impl.STATUS_SUCCESS if execution is ok.
+     *         Downloads.Impl.STATUS_FILE_ERROR in case converted file can not
+     *         be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem
+     *         occurs when accessing drm framework.
+     *         Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred.
+     */
+    @UnsupportedAppUsage
+    public int close(String filename) {
+        DrmConvertedStatus convertedStatus = null;
+        int result = Downloads.Impl.STATUS_UNKNOWN_ERROR;
+        if (mDrmClient != null && mConvertSessionId >= 0) {
+            try {
+                convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId);
+                if (convertedStatus == null ||
+                        convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+                        convertedStatus.convertedData == null) {
+                    result = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
+                } else {
+                    RandomAccessFile rndAccessFile = null;
+                    try {
+                        rndAccessFile = new RandomAccessFile(filename, "rw");
+                        rndAccessFile.seek(convertedStatus.offset);
+                        rndAccessFile.write(convertedStatus.convertedData);
+                        result = Downloads.Impl.STATUS_SUCCESS;
+                    } catch (FileNotFoundException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "File: " + filename + " could not be found.", e);
+                    } catch (IOException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "Could not access File: " + filename + " .", e);
+                    } catch (IllegalArgumentException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "Could not open file in mode: rw", e);
+                    } catch (SecurityException e) {
+                        Log.w(TAG, "Access to File: " + filename +
+                                " was denied denied by SecurityManager.", e);
+                    } finally {
+                        if (rndAccessFile != null) {
+                            try {
+                                rndAccessFile.close();
+                            } catch (IOException e) {
+                                result = Downloads.Impl.STATUS_FILE_ERROR;
+                                Log.w(TAG, "Failed to close File:" + filename
+                                        + ".", e);
+                            }
+                        }
+                    }
+                }
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not close convertsession. Convertsession: " +
+                        mConvertSessionId, e);
+            }
+        }
+        return result;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java
new file mode 100644
index 0000000..94e3894
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/PduCache.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2008 Esmertec AG.
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.util;
+
+import android.content.ContentUris;
+import android.content.UriMatcher;
+import android.net.Uri;
+import android.provider.Telephony.Mms;
+import android.util.Log;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+public final class PduCache extends AbstractCache<Uri, PduCacheEntry> {
+    private static final String TAG = "PduCache";
+    private static final boolean DEBUG = false;
+    private static final boolean LOCAL_LOGV = false;
+
+    private static final int MMS_ALL             = 0;
+    private static final int MMS_ALL_ID          = 1;
+    private static final int MMS_INBOX           = 2;
+    private static final int MMS_INBOX_ID        = 3;
+    private static final int MMS_SENT            = 4;
+    private static final int MMS_SENT_ID         = 5;
+    private static final int MMS_DRAFTS          = 6;
+    private static final int MMS_DRAFTS_ID       = 7;
+    private static final int MMS_OUTBOX          = 8;
+    private static final int MMS_OUTBOX_ID       = 9;
+    private static final int MMS_CONVERSATION    = 10;
+    private static final int MMS_CONVERSATION_ID = 11;
+
+    private static final UriMatcher URI_MATCHER;
+    private static final HashMap<Integer, Integer> MATCH_TO_MSGBOX_ID_MAP;
+
+    private static PduCache sInstance;
+
+    static {
+        URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+        URI_MATCHER.addURI("mms", null,         MMS_ALL);
+        URI_MATCHER.addURI("mms", "#",          MMS_ALL_ID);
+        URI_MATCHER.addURI("mms", "inbox",      MMS_INBOX);
+        URI_MATCHER.addURI("mms", "inbox/#",    MMS_INBOX_ID);
+        URI_MATCHER.addURI("mms", "sent",       MMS_SENT);
+        URI_MATCHER.addURI("mms", "sent/#",     MMS_SENT_ID);
+        URI_MATCHER.addURI("mms", "drafts",     MMS_DRAFTS);
+        URI_MATCHER.addURI("mms", "drafts/#",   MMS_DRAFTS_ID);
+        URI_MATCHER.addURI("mms", "outbox",     MMS_OUTBOX);
+        URI_MATCHER.addURI("mms", "outbox/#",   MMS_OUTBOX_ID);
+        URI_MATCHER.addURI("mms-sms", "conversations",   MMS_CONVERSATION);
+        URI_MATCHER.addURI("mms-sms", "conversations/#", MMS_CONVERSATION_ID);
+
+        MATCH_TO_MSGBOX_ID_MAP = new HashMap<Integer, Integer>();
+        MATCH_TO_MSGBOX_ID_MAP.put(MMS_INBOX,  Mms.MESSAGE_BOX_INBOX);
+        MATCH_TO_MSGBOX_ID_MAP.put(MMS_SENT,   Mms.MESSAGE_BOX_SENT);
+        MATCH_TO_MSGBOX_ID_MAP.put(MMS_DRAFTS, Mms.MESSAGE_BOX_DRAFTS);
+        MATCH_TO_MSGBOX_ID_MAP.put(MMS_OUTBOX, Mms.MESSAGE_BOX_OUTBOX);
+    }
+
+    private final HashMap<Integer, HashSet<Uri>> mMessageBoxes;
+    private final HashMap<Long, HashSet<Uri>> mThreads;
+    private final HashSet<Uri> mUpdating;
+
+    @UnsupportedAppUsage
+    private PduCache() {
+        mMessageBoxes = new HashMap<Integer, HashSet<Uri>>();
+        mThreads = new HashMap<Long, HashSet<Uri>>();
+        mUpdating = new HashSet<Uri>();
+    }
+
+    @UnsupportedAppUsage
+    synchronized public static final PduCache getInstance() {
+        if (sInstance == null) {
+            if (LOCAL_LOGV) {
+                Log.v(TAG, "Constructing new PduCache instance.");
+            }
+            sInstance = new PduCache();
+        }
+        return sInstance;
+    }
+
+    @Override
+    synchronized public boolean put(Uri uri, PduCacheEntry entry) {
+        int msgBoxId = entry.getMessageBox();
+        HashSet<Uri> msgBox = mMessageBoxes.get(msgBoxId);
+        if (msgBox == null) {
+            msgBox = new HashSet<Uri>();
+            mMessageBoxes.put(msgBoxId, msgBox);
+        }
+
+        long threadId = entry.getThreadId();
+        HashSet<Uri> thread = mThreads.get(threadId);
+        if (thread == null) {
+            thread = new HashSet<Uri>();
+            mThreads.put(threadId, thread);
+        }
+
+        Uri finalKey = normalizeKey(uri);
+        boolean result = super.put(finalKey, entry);
+        if (result) {
+            msgBox.add(finalKey);
+            thread.add(finalKey);
+        }
+        setUpdating(uri, false);
+        return result;
+    }
+
+    synchronized public void setUpdating(Uri uri, boolean updating) {
+        if (updating) {
+            mUpdating.add(uri);
+        } else {
+            mUpdating.remove(uri);
+        }
+    }
+
+    @UnsupportedAppUsage
+    synchronized public boolean isUpdating(Uri uri) {
+        return mUpdating.contains(uri);
+    }
+
+    @Override
+    @UnsupportedAppUsage
+    synchronized public PduCacheEntry purge(Uri uri) {
+        int match = URI_MATCHER.match(uri);
+        switch (match) {
+            case MMS_ALL_ID:
+                return purgeSingleEntry(uri);
+            case MMS_INBOX_ID:
+            case MMS_SENT_ID:
+            case MMS_DRAFTS_ID:
+            case MMS_OUTBOX_ID:
+                String msgId = uri.getLastPathSegment();
+                return purgeSingleEntry(Uri.withAppendedPath(Mms.CONTENT_URI, msgId));
+            // Implicit batch of purge, return null.
+            case MMS_ALL:
+            case MMS_CONVERSATION:
+                purgeAll();
+                return null;
+            case MMS_INBOX:
+            case MMS_SENT:
+            case MMS_DRAFTS:
+            case MMS_OUTBOX:
+                purgeByMessageBox(MATCH_TO_MSGBOX_ID_MAP.get(match));
+                return null;
+            case MMS_CONVERSATION_ID:
+                purgeByThreadId(ContentUris.parseId(uri));
+                return null;
+            default:
+                return null;
+        }
+    }
+
+    private PduCacheEntry purgeSingleEntry(Uri key) {
+        mUpdating.remove(key);
+        PduCacheEntry entry = super.purge(key);
+        if (entry != null) {
+            removeFromThreads(key, entry);
+            removeFromMessageBoxes(key, entry);
+            return entry;
+        }
+        return null;
+    }
+
+    @UnsupportedAppUsage
+    @Override
+    synchronized public void purgeAll() {
+        super.purgeAll();
+
+        mMessageBoxes.clear();
+        mThreads.clear();
+        mUpdating.clear();
+    }
+
+    /**
+     * @param uri The Uri to be normalized.
+     * @return Uri The normalized key of cached entry.
+     */
+    private Uri normalizeKey(Uri uri) {
+        int match = URI_MATCHER.match(uri);
+        Uri normalizedKey = null;
+
+        switch (match) {
+            case MMS_ALL_ID:
+                normalizedKey = uri;
+                break;
+            case MMS_INBOX_ID:
+            case MMS_SENT_ID:
+            case MMS_DRAFTS_ID:
+            case MMS_OUTBOX_ID:
+                String msgId = uri.getLastPathSegment();
+                normalizedKey = Uri.withAppendedPath(Mms.CONTENT_URI, msgId);
+                break;
+            default:
+                return null;
+        }
+
+        if (LOCAL_LOGV) {
+            Log.v(TAG, uri + " -> " + normalizedKey);
+        }
+        return normalizedKey;
+    }
+
+    private void purgeByMessageBox(Integer msgBoxId) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Purge cache in message box: " + msgBoxId);
+        }
+
+        if (msgBoxId != null) {
+            HashSet<Uri> msgBox = mMessageBoxes.remove(msgBoxId);
+            if (msgBox != null) {
+                for (Uri key : msgBox) {
+                    mUpdating.remove(key);
+                    PduCacheEntry entry = super.purge(key);
+                    if (entry != null) {
+                        removeFromThreads(key, entry);
+                    }
+                }
+            }
+        }
+    }
+
+    private void removeFromThreads(Uri key, PduCacheEntry entry) {
+        HashSet<Uri> thread = mThreads.get(entry.getThreadId());
+        if (thread != null) {
+            thread.remove(key);
+        }
+    }
+
+    private void purgeByThreadId(long threadId) {
+        if (LOCAL_LOGV) {
+            Log.v(TAG, "Purge cache in thread: " + threadId);
+        }
+
+        HashSet<Uri> thread = mThreads.remove(threadId);
+        if (thread != null) {
+            for (Uri key : thread) {
+                mUpdating.remove(key);
+                PduCacheEntry entry = super.purge(key);
+                if (entry != null) {
+                    removeFromMessageBoxes(key, entry);
+                }
+            }
+        }
+    }
+
+    private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
+        HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox()));
+        if (msgBox != null) {
+            msgBox.remove(key);
+        }
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
new file mode 100644
index 0000000..1ecd1bf
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Esmertec AG.
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.util;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import com.google.android.mms.pdu.GenericPdu;
+
+public final class PduCacheEntry {
+    private final GenericPdu mPdu;
+    private final int mMessageBox;
+    private final long mThreadId;
+
+    @UnsupportedAppUsage
+    public PduCacheEntry(GenericPdu pdu, int msgBox, long threadId) {
+        mPdu = pdu;
+        mMessageBox = msgBox;
+        mThreadId = threadId;
+    }
+
+    @UnsupportedAppUsage
+    public GenericPdu getPdu() {
+        return mPdu;
+    }
+
+    @UnsupportedAppUsage
+    public int getMessageBox() {
+        return mMessageBox;
+    }
+
+    @UnsupportedAppUsage
+    public long getThreadId() {
+        return mThreadId;
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
new file mode 100644
index 0000000..2dd1dc1
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 Esmertec AG.
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.mms.util;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.net.Uri;
+import android.util.Log;
+import android.widget.Toast;
+
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
+public final class SqliteWrapper {
+    private static final String TAG = "SqliteWrapper";
+    private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
+                = "unable to open database file";
+
+    private SqliteWrapper() {
+        // Forbidden being instantiated.
+    }
+
+    // FIXME: It looks like outInfo.lowMemory does not work well as we expected.
+    // after run command: adb shell fillup -p 100, outInfo.lowMemory is still false.
+    private static boolean isLowMemory(Context context) {
+        if (null == context) {
+            return false;
+        }
+
+        ActivityManager am = (ActivityManager)
+                        context.getSystemService(Context.ACTIVITY_SERVICE);
+        ActivityManager.MemoryInfo outInfo = new ActivityManager.MemoryInfo();
+        am.getMemoryInfo(outInfo);
+
+        return outInfo.lowMemory;
+    }
+
+    // FIXME: need to optimize this method.
+    private static boolean isLowMemory(SQLiteException e) {
+        return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
+    }
+
+    @UnsupportedAppUsage
+    public static void checkSQLiteException(Context context, SQLiteException e) {
+        if (isLowMemory(e)) {
+            Toast.makeText(context, com.android.internal.R.string.low_memory,
+                    Toast.LENGTH_SHORT).show();
+        } else {
+            throw e;
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static Cursor query(Context context, ContentResolver resolver, Uri uri,
+            String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+        try {
+            return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Catch a SQLiteException when query: ", e);
+            checkSQLiteException(context, e);
+            return null;
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static boolean requery(Context context, Cursor cursor) {
+        try {
+            return cursor.requery();
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Catch a SQLiteException when requery: ", e);
+            checkSQLiteException(context, e);
+            return false;
+        }
+    }
+    @UnsupportedAppUsage
+    public static int update(Context context, ContentResolver resolver, Uri uri,
+            ContentValues values, String where, String[] selectionArgs) {
+        try {
+            return resolver.update(uri, values, where, selectionArgs);
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Catch a SQLiteException when update: ", e);
+            checkSQLiteException(context, e);
+            return -1;
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static int delete(Context context, ContentResolver resolver, Uri uri,
+            String where, String[] selectionArgs) {
+        try {
+            return resolver.delete(uri, where, selectionArgs);
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Catch a SQLiteException when delete: ", e);
+            checkSQLiteException(context, e);
+            return -1;
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static Uri insert(Context context, ContentResolver resolver,
+            Uri uri, ContentValues values) {
+        try {
+            return resolver.insert(uri, values);
+        } catch (SQLiteException e) {
+            Log.e(TAG, "Catch a SQLiteException when insert: ", e);
+            checkSQLiteException(context, e);
+            return null;
+        }
+    }
+}
diff --git a/telephony/common/com/google/android/mms/util/package.html b/telephony/common/com/google/android/mms/util/package.html
new file mode 100755
index 0000000..c9f96a6
--- /dev/null
+++ b/telephony/common/com/google/android/mms/util/package.html
@@ -0,0 +1,5 @@
+<body>
+
+{@hide}
+
+</body>
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
new file mode 100644
index 0000000..a884a70
--- /dev/null
+++ b/telephony/java/android/telephony/Annotation.java
@@ -0,0 +1,472 @@
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.telephony.data.ApnSetting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Telephony Annotations.
+ * Telephony sdk is a mainline module and others cannot reference hidden @IntDef. Moving some
+ * telephony annotations to a separate class to allow others statically link to it.
+ *
+ * @hide
+ */
+public class Annotation {
+    @IntDef(prefix = {"DATA_"}, value = {
+            TelephonyManager.DATA_ACTIVITY_NONE,
+            TelephonyManager.DATA_ACTIVITY_IN,
+            TelephonyManager.DATA_ACTIVITY_OUT,
+            TelephonyManager.DATA_ACTIVITY_INOUT,
+            TelephonyManager.DATA_ACTIVITY_DORMANT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataActivityType {
+    }
+
+    @IntDef(prefix = {"DATA_"}, value = {
+            TelephonyManager.DATA_UNKNOWN,
+            TelephonyManager.DATA_DISCONNECTED,
+            TelephonyManager.DATA_CONNECTING,
+            TelephonyManager.DATA_CONNECTED,
+            TelephonyManager.DATA_SUSPENDED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataState {
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RADIO_POWER_"},
+            value = {
+                    TelephonyManager.RADIO_POWER_OFF,
+                    TelephonyManager.RADIO_POWER_ON,
+                    TelephonyManager.RADIO_POWER_UNAVAILABLE,
+            })
+    public @interface RadioPowerState {
+    }
+
+    @IntDef({
+            TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN,
+            TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING,
+            TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED,
+            TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED,
+            TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SimActivationState {
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SRVCC_STATE_"},
+            value = {
+                    TelephonyManager.SRVCC_STATE_HANDOVER_NONE,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_STARTED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_FAILED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED})
+    public @interface SrvccState {
+    }
+
+    @IntDef(prefix = {"CALL_STATE_"}, value = {
+            TelephonyManager.CALL_STATE_IDLE,
+            TelephonyManager.CALL_STATE_RINGING,
+            TelephonyManager.CALL_STATE_OFFHOOK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallState {
+    }
+
+    @IntDef({
+            TelephonyManager.NETWORK_TYPE_UNKNOWN,
+            TelephonyManager.NETWORK_TYPE_GPRS,
+            TelephonyManager.NETWORK_TYPE_EDGE,
+            TelephonyManager.NETWORK_TYPE_UMTS,
+            TelephonyManager.NETWORK_TYPE_CDMA,
+            TelephonyManager.NETWORK_TYPE_EVDO_0,
+            TelephonyManager.NETWORK_TYPE_EVDO_A,
+            TelephonyManager.NETWORK_TYPE_1xRTT,
+            TelephonyManager.NETWORK_TYPE_HSDPA,
+            TelephonyManager.NETWORK_TYPE_HSUPA,
+            TelephonyManager.NETWORK_TYPE_HSPA,
+            TelephonyManager.NETWORK_TYPE_IDEN,
+            TelephonyManager.NETWORK_TYPE_EVDO_B,
+            TelephonyManager.NETWORK_TYPE_LTE,
+            TelephonyManager.NETWORK_TYPE_EHRPD,
+            TelephonyManager.NETWORK_TYPE_HSPAP,
+            TelephonyManager.NETWORK_TYPE_GSM,
+            TelephonyManager.NETWORK_TYPE_TD_SCDMA,
+            TelephonyManager.NETWORK_TYPE_IWLAN,
+            TelephonyManager.NETWORK_TYPE_LTE_CA,
+            TelephonyManager.NETWORK_TYPE_NR,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkType {
+    }
+
+    @IntDef(flag = true, prefix = {"TYPE_"}, value = {
+            ApnSetting.TYPE_DEFAULT,
+            ApnSetting.TYPE_MMS,
+            ApnSetting.TYPE_SUPL,
+            ApnSetting.TYPE_DUN,
+            ApnSetting.TYPE_HIPRI,
+            ApnSetting.TYPE_FOTA,
+            ApnSetting.TYPE_IMS,
+            ApnSetting.TYPE_CBS,
+            ApnSetting.TYPE_IA,
+            ApnSetting.TYPE_EMERGENCY,
+            ApnSetting.TYPE_MCX
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApnType {
+    }
+
+    @IntDef(value = {
+            DataFailCause.NONE,
+            DataFailCause.OPERATOR_BARRED,
+            DataFailCause.NAS_SIGNALLING,
+            DataFailCause.LLC_SNDCP,
+            DataFailCause.INSUFFICIENT_RESOURCES,
+            DataFailCause.MISSING_UNKNOWN_APN,
+            DataFailCause.UNKNOWN_PDP_ADDRESS_TYPE,
+            DataFailCause.USER_AUTHENTICATION,
+            DataFailCause.ACTIVATION_REJECT_GGSN,
+            DataFailCause.ACTIVATION_REJECT_UNSPECIFIED,
+            DataFailCause.SERVICE_OPTION_NOT_SUPPORTED,
+            DataFailCause.SERVICE_OPTION_NOT_SUBSCRIBED,
+            DataFailCause.SERVICE_OPTION_OUT_OF_ORDER,
+            DataFailCause.NSAPI_IN_USE,
+            DataFailCause.REGULAR_DEACTIVATION,
+            DataFailCause.QOS_NOT_ACCEPTED,
+            DataFailCause.NETWORK_FAILURE,
+            DataFailCause.UMTS_REACTIVATION_REQ,
+            DataFailCause.FEATURE_NOT_SUPP,
+            DataFailCause.TFT_SEMANTIC_ERROR,
+            DataFailCause.TFT_SYTAX_ERROR,
+            DataFailCause.UNKNOWN_PDP_CONTEXT,
+            DataFailCause.FILTER_SEMANTIC_ERROR,
+            DataFailCause.FILTER_SYTAX_ERROR,
+            DataFailCause.PDP_WITHOUT_ACTIVE_TFT,
+            DataFailCause.ACTIVATION_REJECTED_BCM_VIOLATION,
+            DataFailCause.ONLY_IPV4_ALLOWED,
+            DataFailCause.ONLY_IPV6_ALLOWED,
+            DataFailCause.ONLY_SINGLE_BEARER_ALLOWED,
+            DataFailCause.ESM_INFO_NOT_RECEIVED,
+            DataFailCause.PDN_CONN_DOES_NOT_EXIST,
+            DataFailCause.MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+            DataFailCause.COLLISION_WITH_NETWORK_INITIATED_REQUEST,
+            DataFailCause.ONLY_IPV4V6_ALLOWED,
+            DataFailCause.ONLY_NON_IP_ALLOWED,
+            DataFailCause.UNSUPPORTED_QCI_VALUE,
+            DataFailCause.BEARER_HANDLING_NOT_SUPPORTED,
+            DataFailCause.ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
+            DataFailCause.UNSUPPORTED_APN_IN_CURRENT_PLMN,
+            DataFailCause.INVALID_TRANSACTION_ID,
+            DataFailCause.MESSAGE_INCORRECT_SEMANTIC,
+            DataFailCause.INVALID_MANDATORY_INFO,
+            DataFailCause.MESSAGE_TYPE_UNSUPPORTED,
+            DataFailCause.MSG_TYPE_NONCOMPATIBLE_STATE,
+            DataFailCause.UNKNOWN_INFO_ELEMENT,
+            DataFailCause.CONDITIONAL_IE_ERROR,
+            DataFailCause.MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+            DataFailCause.PROTOCOL_ERRORS,
+            DataFailCause.APN_TYPE_CONFLICT,
+            DataFailCause.INVALID_PCSCF_ADDR,
+            DataFailCause.INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+            DataFailCause.EMM_ACCESS_BARRED,
+            DataFailCause.EMERGENCY_IFACE_ONLY,
+            DataFailCause.IFACE_MISMATCH,
+            DataFailCause.COMPANION_IFACE_IN_USE,
+            DataFailCause.IP_ADDRESS_MISMATCH,
+            DataFailCause.IFACE_AND_POL_FAMILY_MISMATCH,
+            DataFailCause.EMM_ACCESS_BARRED_INFINITE_RETRY,
+            DataFailCause.AUTH_FAILURE_ON_EMERGENCY_CALL,
+            DataFailCause.INVALID_DNS_ADDR,
+            DataFailCause.INVALID_PCSCF_OR_DNS_ADDRESS,
+            DataFailCause.CALL_PREEMPT_BY_EMERGENCY_APN,
+            DataFailCause.UE_INITIATED_DETACH_OR_DISCONNECT,
+            DataFailCause.MIP_FA_REASON_UNSPECIFIED,
+            DataFailCause.MIP_FA_ADMIN_PROHIBITED,
+            DataFailCause.MIP_FA_INSUFFICIENT_RESOURCES,
+            DataFailCause.MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_FA_REQUESTED_LIFETIME_TOO_LONG,
+            DataFailCause.MIP_FA_MALFORMED_REQUEST,
+            DataFailCause.MIP_FA_MALFORMED_REPLY,
+            DataFailCause.MIP_FA_ENCAPSULATION_UNAVAILABLE,
+            DataFailCause.MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
+            DataFailCause.MIP_FA_REVERSE_TUNNEL_UNAVAILABLE,
+            DataFailCause.MIP_FA_REVERSE_TUNNEL_IS_MANDATORY,
+            DataFailCause.MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
+            DataFailCause.MIP_FA_MISSING_NAI,
+            DataFailCause.MIP_FA_MISSING_HOME_AGENT,
+            DataFailCause.MIP_FA_MISSING_HOME_ADDRESS,
+            DataFailCause.MIP_FA_UNKNOWN_CHALLENGE,
+            DataFailCause.MIP_FA_MISSING_CHALLENGE,
+            DataFailCause.MIP_FA_STALE_CHALLENGE,
+            DataFailCause.MIP_HA_REASON_UNSPECIFIED,
+            DataFailCause.MIP_HA_ADMIN_PROHIBITED,
+            DataFailCause.MIP_HA_INSUFFICIENT_RESOURCES,
+            DataFailCause.MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_HA_REGISTRATION_ID_MISMATCH,
+            DataFailCause.MIP_HA_MALFORMED_REQUEST,
+            DataFailCause.MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS,
+            DataFailCause.MIP_HA_REVERSE_TUNNEL_UNAVAILABLE,
+            DataFailCause.MIP_HA_REVERSE_TUNNEL_IS_MANDATORY,
+            DataFailCause.MIP_HA_ENCAPSULATION_UNAVAILABLE,
+            DataFailCause.CLOSE_IN_PROGRESS,
+            DataFailCause.NETWORK_INITIATED_TERMINATION,
+            DataFailCause.MODEM_APP_PREEMPTED,
+            DataFailCause.PDN_IPV4_CALL_DISALLOWED,
+            DataFailCause.PDN_IPV4_CALL_THROTTLED,
+            DataFailCause.PDN_IPV6_CALL_DISALLOWED,
+            DataFailCause.PDN_IPV6_CALL_THROTTLED,
+            DataFailCause.MODEM_RESTART,
+            DataFailCause.PDP_PPP_NOT_SUPPORTED,
+            DataFailCause.UNPREFERRED_RAT,
+            DataFailCause.PHYSICAL_LINK_CLOSE_IN_PROGRESS,
+            DataFailCause.APN_PENDING_HANDOVER,
+            DataFailCause.PROFILE_BEARER_INCOMPATIBLE,
+            DataFailCause.SIM_CARD_CHANGED,
+            DataFailCause.LOW_POWER_MODE_OR_POWERING_DOWN,
+            DataFailCause.APN_DISABLED,
+            DataFailCause.MAX_PPP_INACTIVITY_TIMER_EXPIRED,
+            DataFailCause.IPV6_ADDRESS_TRANSFER_FAILED,
+            DataFailCause.TRAT_SWAP_FAILED,
+            DataFailCause.EHRPD_TO_HRPD_FALLBACK,
+            DataFailCause.MIP_CONFIG_FAILURE,
+            DataFailCause.PDN_INACTIVITY_TIMER_EXPIRED,
+            DataFailCause.MAX_IPV4_CONNECTIONS,
+            DataFailCause.MAX_IPV6_CONNECTIONS,
+            DataFailCause.APN_MISMATCH,
+            DataFailCause.IP_VERSION_MISMATCH,
+            DataFailCause.DUN_CALL_DISALLOWED,
+            DataFailCause.INTERNAL_EPC_NONEPC_TRANSITION,
+            DataFailCause.INTERFACE_IN_USE,
+            DataFailCause.APN_DISALLOWED_ON_ROAMING,
+            DataFailCause.APN_PARAMETERS_CHANGED,
+            DataFailCause.NULL_APN_DISALLOWED,
+            DataFailCause.THERMAL_MITIGATION,
+            DataFailCause.DATA_SETTINGS_DISABLED,
+            DataFailCause.DATA_ROAMING_SETTINGS_DISABLED,
+            DataFailCause.DDS_SWITCHED,
+            DataFailCause.FORBIDDEN_APN_NAME,
+            DataFailCause.DDS_SWITCH_IN_PROGRESS,
+            DataFailCause.CALL_DISALLOWED_IN_ROAMING,
+            DataFailCause.NON_IP_NOT_SUPPORTED,
+            DataFailCause.PDN_NON_IP_CALL_THROTTLED,
+            DataFailCause.PDN_NON_IP_CALL_DISALLOWED,
+            DataFailCause.CDMA_LOCK,
+            DataFailCause.CDMA_INTERCEPT,
+            DataFailCause.CDMA_REORDER,
+            DataFailCause.CDMA_RELEASE_DUE_TO_SO_REJECTION,
+            DataFailCause.CDMA_INCOMING_CALL,
+            DataFailCause.CDMA_ALERT_STOP,
+            DataFailCause.CHANNEL_ACQUISITION_FAILURE,
+            DataFailCause.MAX_ACCESS_PROBE,
+            DataFailCause.CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
+            DataFailCause.NO_RESPONSE_FROM_BASE_STATION,
+            DataFailCause.REJECTED_BY_BASE_STATION,
+            DataFailCause.CONCURRENT_SERVICES_INCOMPATIBLE,
+            DataFailCause.NO_CDMA_SERVICE,
+            DataFailCause.RUIM_NOT_PRESENT,
+            DataFailCause.CDMA_RETRY_ORDER,
+            DataFailCause.ACCESS_BLOCK,
+            DataFailCause.ACCESS_BLOCK_ALL,
+            DataFailCause.IS707B_MAX_ACCESS_PROBES,
+            DataFailCause.THERMAL_EMERGENCY,
+            DataFailCause.CONCURRENT_SERVICES_NOT_ALLOWED,
+            DataFailCause.INCOMING_CALL_REJECTED,
+            DataFailCause.NO_SERVICE_ON_GATEWAY,
+            DataFailCause.NO_GPRS_CONTEXT,
+            DataFailCause.ILLEGAL_MS,
+            DataFailCause.ILLEGAL_ME,
+            DataFailCause.GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
+            DataFailCause.GPRS_SERVICES_NOT_ALLOWED,
+            DataFailCause.MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
+            DataFailCause.IMPLICITLY_DETACHED,
+            DataFailCause.PLMN_NOT_ALLOWED,
+            DataFailCause.LOCATION_AREA_NOT_ALLOWED,
+            DataFailCause.GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
+            DataFailCause.PDP_DUPLICATE,
+            DataFailCause.UE_RAT_CHANGE,
+            DataFailCause.CONGESTION,
+            DataFailCause.NO_PDP_CONTEXT_ACTIVATED,
+            DataFailCause.ACCESS_CLASS_DSAC_REJECTION,
+            DataFailCause.PDP_ACTIVATE_MAX_RETRY_FAILED,
+            DataFailCause.RADIO_ACCESS_BEARER_FAILURE,
+            DataFailCause.ESM_UNKNOWN_EPS_BEARER_CONTEXT,
+            DataFailCause.DRB_RELEASED_BY_RRC,
+            DataFailCause.CONNECTION_RELEASED,
+            DataFailCause.EMM_DETACHED,
+            DataFailCause.EMM_ATTACH_FAILED,
+            DataFailCause.EMM_ATTACH_STARTED,
+            DataFailCause.LTE_NAS_SERVICE_REQUEST_FAILED,
+            DataFailCause.DUPLICATE_BEARER_ID,
+            DataFailCause.ESM_COLLISION_SCENARIOS,
+            DataFailCause.ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
+            DataFailCause.ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
+            DataFailCause.ESM_BAD_OTA_MESSAGE,
+            DataFailCause.ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
+            DataFailCause.ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
+            DataFailCause.DS_EXPLICIT_DEACTIVATION,
+            DataFailCause.ESM_LOCAL_CAUSE_NONE,
+            DataFailCause.LTE_THROTTLING_NOT_REQUIRED,
+            DataFailCause.ACCESS_CONTROL_LIST_CHECK_FAILURE,
+            DataFailCause.SERVICE_NOT_ALLOWED_ON_PLMN,
+            DataFailCause.EMM_T3417_EXPIRED,
+            DataFailCause.EMM_T3417_EXT_EXPIRED,
+            DataFailCause.RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
+            DataFailCause.RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
+            DataFailCause.RRC_UPLINK_CONNECTION_RELEASE,
+            DataFailCause.RRC_UPLINK_RADIO_LINK_FAILURE,
+            DataFailCause.RRC_UPLINK_ERROR_REQUEST_FROM_NAS,
+            DataFailCause.RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
+            DataFailCause.RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
+            DataFailCause.RRC_CONNECTION_ACCESS_BARRED,
+            DataFailCause.RRC_CONNECTION_CELL_RESELECTION,
+            DataFailCause.RRC_CONNECTION_CONFIG_FAILURE,
+            DataFailCause.RRC_CONNECTION_TIMER_EXPIRED,
+            DataFailCause.RRC_CONNECTION_LINK_FAILURE,
+            DataFailCause.RRC_CONNECTION_CELL_NOT_CAMPED,
+            DataFailCause.RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
+            DataFailCause.RRC_CONNECTION_REJECT_BY_NETWORK,
+            DataFailCause.RRC_CONNECTION_NORMAL_RELEASE,
+            DataFailCause.RRC_CONNECTION_RADIO_LINK_FAILURE,
+            DataFailCause.RRC_CONNECTION_REESTABLISHMENT_FAILURE,
+            DataFailCause.RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
+            DataFailCause.RRC_CONNECTION_ABORT_REQUEST,
+            DataFailCause.RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
+            DataFailCause.NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
+            DataFailCause.NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
+            DataFailCause.ESM_PROCEDURE_TIME_OUT,
+            DataFailCause.INVALID_CONNECTION_ID,
+            DataFailCause.MAXIMIUM_NSAPIS_EXCEEDED,
+            DataFailCause.INVALID_PRIMARY_NSAPI,
+            DataFailCause.CANNOT_ENCODE_OTA_MESSAGE,
+            DataFailCause.RADIO_ACCESS_BEARER_SETUP_FAILURE,
+            DataFailCause.PDP_ESTABLISH_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_MODIFY_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_INACTIVE_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_LOWERLAYER_ERROR,
+            DataFailCause.PDP_MODIFY_COLLISION,
+            DataFailCause.MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
+            DataFailCause.NAS_REQUEST_REJECTED_BY_NETWORK,
+            DataFailCause.RRC_CONNECTION_INVALID_REQUEST,
+            DataFailCause.RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
+            DataFailCause.RRC_CONNECTION_RF_UNAVAILABLE,
+            DataFailCause.RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
+            DataFailCause.RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
+            DataFailCause.RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
+            DataFailCause.RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
+            DataFailCause.RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
+            DataFailCause.IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
+            DataFailCause.IMEI_NOT_ACCEPTED,
+            DataFailCause.EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
+            DataFailCause.EPS_SERVICES_NOT_ALLOWED_IN_PLMN,
+            DataFailCause.MSC_TEMPORARILY_NOT_REACHABLE,
+            DataFailCause.CS_DOMAIN_NOT_AVAILABLE,
+            DataFailCause.ESM_FAILURE,
+            DataFailCause.MAC_FAILURE,
+            DataFailCause.SYNCHRONIZATION_FAILURE,
+            DataFailCause.UE_SECURITY_CAPABILITIES_MISMATCH,
+            DataFailCause.SECURITY_MODE_REJECTED,
+            DataFailCause.UNACCEPTABLE_NON_EPS_AUTHENTICATION,
+            DataFailCause.CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
+            DataFailCause.NO_EPS_BEARER_CONTEXT_ACTIVATED,
+            DataFailCause.INVALID_EMM_STATE,
+            DataFailCause.NAS_LAYER_FAILURE,
+            DataFailCause.MULTIPLE_PDP_CALL_NOT_ALLOWED,
+            DataFailCause.EMBMS_NOT_ENABLED,
+            DataFailCause.IRAT_HANDOVER_FAILED,
+            DataFailCause.EMBMS_REGULAR_DEACTIVATION,
+            DataFailCause.TEST_LOOPBACK_REGULAR_DEACTIVATION,
+            DataFailCause.LOWER_LAYER_REGISTRATION_FAILURE,
+            DataFailCause.DATA_PLAN_EXPIRED,
+            DataFailCause.UMTS_HANDOVER_TO_IWLAN,
+            DataFailCause.EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
+            DataFailCause.EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
+            DataFailCause.EVDO_HDR_CHANGED,
+            DataFailCause.EVDO_HDR_EXITED,
+            DataFailCause.EVDO_HDR_NO_SESSION,
+            DataFailCause.EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
+            DataFailCause.EVDO_HDR_CONNECTION_SETUP_TIMEOUT,
+            DataFailCause.FAILED_TO_ACQUIRE_COLOCATED_HDR,
+            DataFailCause.OTASP_COMMIT_IN_PROGRESS,
+            DataFailCause.NO_HYBRID_HDR_SERVICE,
+            DataFailCause.HDR_NO_LOCK_GRANTED,
+            DataFailCause.DBM_OR_SMS_IN_PROGRESS,
+            DataFailCause.HDR_FADE,
+            DataFailCause.HDR_ACCESS_FAILURE,
+            DataFailCause.UNSUPPORTED_1X_PREV,
+            DataFailCause.LOCAL_END,
+            DataFailCause.NO_SERVICE,
+            DataFailCause.FADE,
+            DataFailCause.NORMAL_RELEASE,
+            DataFailCause.ACCESS_ATTEMPT_ALREADY_IN_PROGRESS,
+            DataFailCause.REDIRECTION_OR_HANDOFF_IN_PROGRESS,
+            DataFailCause.EMERGENCY_MODE,
+            DataFailCause.PHONE_IN_USE,
+            DataFailCause.INVALID_MODE,
+            DataFailCause.INVALID_SIM_STATE,
+            DataFailCause.NO_COLLOCATED_HDR,
+            DataFailCause.UE_IS_ENTERING_POWERSAVE_MODE,
+            DataFailCause.DUAL_SWITCH,
+            DataFailCause.PPP_TIMEOUT,
+            DataFailCause.PPP_AUTH_FAILURE,
+            DataFailCause.PPP_OPTION_MISMATCH,
+            DataFailCause.PPP_PAP_FAILURE,
+            DataFailCause.PPP_CHAP_FAILURE,
+            DataFailCause.PPP_CLOSE_IN_PROGRESS,
+            DataFailCause.LIMITED_TO_IPV4,
+            DataFailCause.LIMITED_TO_IPV6,
+            DataFailCause.VSNCP_TIMEOUT,
+            DataFailCause.VSNCP_GEN_ERROR,
+            DataFailCause.VSNCP_APN_UNATHORIZED,
+            DataFailCause.VSNCP_PDN_LIMIT_EXCEEDED,
+            DataFailCause.VSNCP_NO_PDN_GATEWAY_ADDRESS,
+            DataFailCause.VSNCP_PDN_GATEWAY_UNREACHABLE,
+            DataFailCause.VSNCP_PDN_GATEWAY_REJECT,
+            DataFailCause.VSNCP_INSUFFICIENT_PARAMETERS,
+            DataFailCause.VSNCP_RESOURCE_UNAVAILABLE,
+            DataFailCause.VSNCP_ADMINISTRATIVELY_PROHIBITED,
+            DataFailCause.VSNCP_PDN_ID_IN_USE,
+            DataFailCause.VSNCP_SUBSCRIBER_LIMITATION,
+            DataFailCause.VSNCP_PDN_EXISTS_FOR_THIS_APN,
+            DataFailCause.VSNCP_RECONNECT_NOT_ALLOWED,
+            DataFailCause.IPV6_PREFIX_UNAVAILABLE,
+            DataFailCause.HANDOFF_PREFERENCE_CHANGED,
+            DataFailCause.OEM_DCFAILCAUSE_1,
+            DataFailCause.OEM_DCFAILCAUSE_2,
+            DataFailCause.OEM_DCFAILCAUSE_3,
+            DataFailCause.OEM_DCFAILCAUSE_4,
+            DataFailCause.OEM_DCFAILCAUSE_5,
+            DataFailCause.OEM_DCFAILCAUSE_6,
+            DataFailCause.OEM_DCFAILCAUSE_7,
+            DataFailCause.OEM_DCFAILCAUSE_8,
+            DataFailCause.OEM_DCFAILCAUSE_9,
+            DataFailCause.OEM_DCFAILCAUSE_10,
+            DataFailCause.OEM_DCFAILCAUSE_11,
+            DataFailCause.OEM_DCFAILCAUSE_12,
+            DataFailCause.OEM_DCFAILCAUSE_13,
+            DataFailCause.OEM_DCFAILCAUSE_14,
+            DataFailCause.OEM_DCFAILCAUSE_15,
+            DataFailCause.REGISTRATION_FAIL,
+            DataFailCause.GPRS_REGISTRATION_FAIL,
+            DataFailCause.SIGNAL_LOST,
+            DataFailCause.PREF_RADIO_TECH_CHANGED,
+            DataFailCause.RADIO_POWER_OFF,
+            DataFailCause.TETHERED_CALL_ACTIVE,
+            DataFailCause.ERROR_UNSPECIFIED,
+            DataFailCause.UNKNOWN,
+            DataFailCause.RADIO_NOT_AVAILABLE,
+            DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
+            DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+            DataFailCause.LOST_CONNECTION,
+            DataFailCause.RESET_BY_FRAMEWORK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataFailureCause {
+    }
+}
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 1c03d80..cd830ad 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -21,8 +21,8 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.util.Objects;
 
 /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e458ae6..e9249df2 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2833,6 +2833,16 @@
             "always_show_primary_signal_bar_in_opportunistic_network_boolean";
 
     /**
+     * Upon data switching between subscriptions within a carrier group, if switch depends on
+     * validation result, this value defines customized value of how long we wait for validation
+     * success before we fail and revoke the switch.
+     * Time out is in milliseconds.
+     * @hide
+     */
+    public static final String KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG =
+            "data_switch_validation_timeout_long";
+
+    /**
      * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
      * @hide
      */
@@ -3613,6 +3623,7 @@
         sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
                 new int[] {4 /* BUSY */});
         sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
+        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellBroadcastService.java b/telephony/java/android/telephony/CellBroadcastService.java
index d5e447e..f841df2 100644
--- a/telephony/java/android/telephony/CellBroadcastService.java
+++ b/telephony/java/android/telephony/CellBroadcastService.java
@@ -17,10 +17,18 @@
 package android.telephony;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+
+import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * A service which exposes the cell broadcast handling module to the system.
@@ -45,6 +53,7 @@
  *   </service>
  * </manifest>
  * }</pre>
+ *
  * @hide
  */
 @SystemApi
@@ -61,17 +70,36 @@
 
     /**
      * Handle a GSM cell broadcast SMS message forwarded from the system.
+     *
      * @param slotIndex the index of the slot which received the message
-     * @param message the SMS PDU
+     * @param message   the SMS PDU
      */
-    public abstract void onGsmCellBroadcastSms(int slotIndex, byte[] message);
+    public abstract void onGsmCellBroadcastSms(int slotIndex, @NonNull byte[] message);
 
     /**
      * Handle a CDMA cell broadcast SMS message forwarded from the system.
-     * @param slotIndex the index of the slot which received the message
-     * @param message the SMS PDU
+     *
+     * @param slotIndex       the index of the slot which received the message
+     * @param bearerData      the CDMA SMS bearer data
+     * @param serviceCategory the CDMA SCPT service category
      */
-    public abstract void onCdmaCellBroadcastSms(int slotIndex, byte[] message);
+    public abstract void onCdmaCellBroadcastSms(int slotIndex, @NonNull byte[] bearerData,
+            @CdmaSmsCbProgramData.Category int serviceCategory);
+
+    /**
+     * Handle a CDMA cell broadcast SMS message forwarded from the system.
+     *
+     * @param slotIndex          the index of the slot which received the message
+     * @param smsCbProgramData   the SMS CB program data of the message
+     * @param originatingAddress the originating address of the message, as a non-separated dial
+     *                           string
+     * @param callback           a callback to run after each cell broadcast receiver has handled
+     *                           the SCP message. The bundle will contain a non-separated
+     *                           dial string as and an ArrayList of {@link CdmaSmsCbProgramResults}.
+     */
+    public abstract void onCdmaScpMessage(int slotIndex,
+            @NonNull List<CdmaSmsCbProgramData> smsCbProgramData,
+            @NonNull String originatingAddress, @NonNull Consumer<Bundle> callback);
 
     /**
      * If overriding this method, call through to the super method for any unknown actions.
@@ -79,20 +107,23 @@
      */
     @Override
     @CallSuper
-    public IBinder onBind(Intent intent) {
+    @NonNull
+    public IBinder onBind(@Nullable Intent intent) {
         return mStubWrapper;
     }
 
     /**
      * A wrapper around ICellBroadcastService that forwards calls to implementations of
      * {@link CellBroadcastService}.
+     *
      * @hide
      */
     public class ICellBroadcastServiceWrapper extends ICellBroadcastService.Stub {
         /**
          * Handle a GSM cell broadcast SMS.
+         *
          * @param slotIndex the index of the slot which received the broadcast
-         * @param message the SMS message PDU
+         * @param message   the SMS message PDU
          */
         @Override
         public void handleGsmCellBroadcastSms(int slotIndex, byte[] message) {
@@ -101,12 +132,36 @@
 
         /**
          * Handle a CDMA cell broadcast SMS.
-         * @param slotIndex the index of the slot which received the broadcast
-         * @param message the SMS message PDU
+         *
+         * @param slotIndex       the index of the slot which received the broadcast
+         * @param bearerData      the CDMA SMS bearer data
+         * @param serviceCategory the CDMA SCPT service category
          */
         @Override
-        public void handleCdmaCellBroadcastSms(int slotIndex, byte[] message) {
-            CellBroadcastService.this.onCdmaCellBroadcastSms(slotIndex, message);
+        public void handleCdmaCellBroadcastSms(int slotIndex, byte[] bearerData,
+                int serviceCategory) {
+            CellBroadcastService.this.onCdmaCellBroadcastSms(slotIndex, bearerData,
+                    serviceCategory);
+        }
+
+        /**
+         * Handle a CDMA Service Category Program message.
+         *
+         * @param slotIndex          the index of the slot which received the message
+         * @param smsCbProgramData   the SMS CB program data of the message
+         * @param originatingAddress the originating address of the message
+         * @param callback           a callback to run after each cell broadcast receiver has
+         *                           handled the SCP message
+         */
+        @Override
+        public void handleCdmaScpMessage(int slotIndex,
+                List<CdmaSmsCbProgramData> smsCbProgramData, String originatingAddress,
+                RemoteCallback callback) {
+            Consumer<Bundle> consumer = bundle -> {
+                callback.sendResult(bundle);
+            };
+            CellBroadcastService.this.onCdmaScpMessage(slotIndex, smsCbProgramData,
+                    originatingAddress, consumer);
         }
     }
 }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 7edc91c..18687d4 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -189,11 +189,15 @@
         mTimeStamp = ts;
     }
 
-    /** @hide */
+    /**
+     * @return a {@link CellIdentity} instance.
+     */
     @NonNull
     public abstract CellIdentity getCellIdentity();
 
-    /** @hide */
+    /**
+     * @return a {@link CellSignalStrength} instance.
+     */
     @NonNull
     public abstract CellSignalStrength getCellSignalStrength();
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 1912c60..f9b7f6d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -194,13 +194,13 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+        if (mSsRsrp == CellInfo.UNAVAILABLE) {
             mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_GREAT;
-        } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_GOOD;
-        } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_MODERATE;
         } else {
             mLevel = SIGNAL_STRENGTH_POOR;
@@ -212,7 +212,7 @@
      *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
-     * @return RSCP in ASU 0..97, 255, or UNAVAILABLE
+     * @return RSRP in ASU 0..97, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
@@ -231,11 +231,11 @@
     }
 
     /**
-     * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     * Get the SS-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
-        return mCsiRsrp;
+        return mSsRsrp;
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index cdf01da..4dc54f0 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -245,9 +245,12 @@
     }
 
     /**
-     * Get the Ec/No as dB
+     * Get the Ec/No (Energy per chip over the noise spectral density) as dB.
      *
-     * @hide
+     * Reference: TS 25.133 Section 9.1.2.3
+     *
+     * @return the Ec/No of the measured cell in the range [-24, 1] or
+     * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable
      */
     public int getEcNo() {
         return mEcNo;
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index ca264f7..246bec7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.os.PersistableBundle;
 
+import android.telephony.Annotation.DataFailureCause;
 import com.android.internal.util.ArrayUtils;
 
 import java.lang.annotation.Retention;
@@ -968,355 +969,6 @@
      */
     public static final int HANDOVER_FAILED = 0x10006;
 
-    /** @hide */
-    @IntDef(value = {
-            NONE,
-            OPERATOR_BARRED,
-            NAS_SIGNALLING,
-            LLC_SNDCP,
-            INSUFFICIENT_RESOURCES,
-            MISSING_UNKNOWN_APN,
-            UNKNOWN_PDP_ADDRESS_TYPE,
-            USER_AUTHENTICATION,
-            ACTIVATION_REJECT_GGSN,
-            ACTIVATION_REJECT_UNSPECIFIED,
-            SERVICE_OPTION_NOT_SUPPORTED,
-            SERVICE_OPTION_NOT_SUBSCRIBED,
-            SERVICE_OPTION_OUT_OF_ORDER,
-            NSAPI_IN_USE,
-            REGULAR_DEACTIVATION,
-            QOS_NOT_ACCEPTED,
-            NETWORK_FAILURE,
-            UMTS_REACTIVATION_REQ,
-            FEATURE_NOT_SUPP,
-            TFT_SEMANTIC_ERROR,
-            TFT_SYTAX_ERROR,
-            UNKNOWN_PDP_CONTEXT,
-            FILTER_SEMANTIC_ERROR,
-            FILTER_SYTAX_ERROR,
-            PDP_WITHOUT_ACTIVE_TFT,
-            ACTIVATION_REJECTED_BCM_VIOLATION,
-            ONLY_IPV4_ALLOWED,
-            ONLY_IPV6_ALLOWED,
-            ONLY_SINGLE_BEARER_ALLOWED,
-            ESM_INFO_NOT_RECEIVED,
-            PDN_CONN_DOES_NOT_EXIST,
-            MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
-            COLLISION_WITH_NETWORK_INITIATED_REQUEST,
-            ONLY_IPV4V6_ALLOWED,
-            ONLY_NON_IP_ALLOWED,
-            UNSUPPORTED_QCI_VALUE,
-            BEARER_HANDLING_NOT_SUPPORTED,
-            ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
-            UNSUPPORTED_APN_IN_CURRENT_PLMN,
-            INVALID_TRANSACTION_ID,
-            MESSAGE_INCORRECT_SEMANTIC,
-            INVALID_MANDATORY_INFO,
-            MESSAGE_TYPE_UNSUPPORTED,
-            MSG_TYPE_NONCOMPATIBLE_STATE,
-            UNKNOWN_INFO_ELEMENT,
-            CONDITIONAL_IE_ERROR,
-            MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
-            PROTOCOL_ERRORS,
-            APN_TYPE_CONFLICT,
-            INVALID_PCSCF_ADDR,
-            INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
-            EMM_ACCESS_BARRED,
-            EMERGENCY_IFACE_ONLY,
-            IFACE_MISMATCH,
-            COMPANION_IFACE_IN_USE,
-            IP_ADDRESS_MISMATCH,
-            IFACE_AND_POL_FAMILY_MISMATCH,
-            EMM_ACCESS_BARRED_INFINITE_RETRY,
-            AUTH_FAILURE_ON_EMERGENCY_CALL,
-            INVALID_DNS_ADDR,
-            INVALID_PCSCF_OR_DNS_ADDRESS,
-            CALL_PREEMPT_BY_EMERGENCY_APN,
-            UE_INITIATED_DETACH_OR_DISCONNECT,
-            MIP_FA_REASON_UNSPECIFIED,
-            MIP_FA_ADMIN_PROHIBITED,
-            MIP_FA_INSUFFICIENT_RESOURCES,
-            MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
-            MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
-            MIP_FA_REQUESTED_LIFETIME_TOO_LONG,
-            MIP_FA_MALFORMED_REQUEST,
-            MIP_FA_MALFORMED_REPLY,
-            MIP_FA_ENCAPSULATION_UNAVAILABLE,
-            MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
-            MIP_FA_REVERSE_TUNNEL_UNAVAILABLE,
-            MIP_FA_REVERSE_TUNNEL_IS_MANDATORY,
-            MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
-            MIP_FA_MISSING_NAI,
-            MIP_FA_MISSING_HOME_AGENT,
-            MIP_FA_MISSING_HOME_ADDRESS,
-            MIP_FA_UNKNOWN_CHALLENGE,
-            MIP_FA_MISSING_CHALLENGE,
-            MIP_FA_STALE_CHALLENGE,
-            MIP_HA_REASON_UNSPECIFIED,
-            MIP_HA_ADMIN_PROHIBITED,
-            MIP_HA_INSUFFICIENT_RESOURCES,
-            MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
-            MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
-            MIP_HA_REGISTRATION_ID_MISMATCH,
-            MIP_HA_MALFORMED_REQUEST,
-            MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS,
-            MIP_HA_REVERSE_TUNNEL_UNAVAILABLE,
-            MIP_HA_REVERSE_TUNNEL_IS_MANDATORY,
-            MIP_HA_ENCAPSULATION_UNAVAILABLE,
-            CLOSE_IN_PROGRESS,
-            NETWORK_INITIATED_TERMINATION,
-            MODEM_APP_PREEMPTED,
-            PDN_IPV4_CALL_DISALLOWED,
-            PDN_IPV4_CALL_THROTTLED,
-            PDN_IPV6_CALL_DISALLOWED,
-            PDN_IPV6_CALL_THROTTLED,
-            MODEM_RESTART,
-            PDP_PPP_NOT_SUPPORTED,
-            UNPREFERRED_RAT,
-            PHYSICAL_LINK_CLOSE_IN_PROGRESS,
-            APN_PENDING_HANDOVER,
-            PROFILE_BEARER_INCOMPATIBLE,
-            SIM_CARD_CHANGED,
-            LOW_POWER_MODE_OR_POWERING_DOWN,
-            APN_DISABLED,
-            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
-            IPV6_ADDRESS_TRANSFER_FAILED,
-            TRAT_SWAP_FAILED,
-            EHRPD_TO_HRPD_FALLBACK,
-            MIP_CONFIG_FAILURE,
-            PDN_INACTIVITY_TIMER_EXPIRED,
-            MAX_IPV4_CONNECTIONS,
-            MAX_IPV6_CONNECTIONS,
-            APN_MISMATCH,
-            IP_VERSION_MISMATCH,
-            DUN_CALL_DISALLOWED,
-            INTERNAL_EPC_NONEPC_TRANSITION,
-            INTERFACE_IN_USE,
-            APN_DISALLOWED_ON_ROAMING,
-            APN_PARAMETERS_CHANGED,
-            NULL_APN_DISALLOWED,
-            THERMAL_MITIGATION,
-            DATA_SETTINGS_DISABLED,
-            DATA_ROAMING_SETTINGS_DISABLED,
-            DDS_SWITCHED,
-            FORBIDDEN_APN_NAME,
-            DDS_SWITCH_IN_PROGRESS,
-            CALL_DISALLOWED_IN_ROAMING,
-            NON_IP_NOT_SUPPORTED,
-            PDN_NON_IP_CALL_THROTTLED,
-            PDN_NON_IP_CALL_DISALLOWED,
-            CDMA_LOCK,
-            CDMA_INTERCEPT,
-            CDMA_REORDER,
-            CDMA_RELEASE_DUE_TO_SO_REJECTION,
-            CDMA_INCOMING_CALL,
-            CDMA_ALERT_STOP,
-            CHANNEL_ACQUISITION_FAILURE,
-            MAX_ACCESS_PROBE,
-            CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
-            NO_RESPONSE_FROM_BASE_STATION,
-            REJECTED_BY_BASE_STATION,
-            CONCURRENT_SERVICES_INCOMPATIBLE,
-            NO_CDMA_SERVICE,
-            RUIM_NOT_PRESENT,
-            CDMA_RETRY_ORDER,
-            ACCESS_BLOCK,
-            ACCESS_BLOCK_ALL,
-            IS707B_MAX_ACCESS_PROBES,
-            THERMAL_EMERGENCY,
-            CONCURRENT_SERVICES_NOT_ALLOWED,
-            INCOMING_CALL_REJECTED,
-            NO_SERVICE_ON_GATEWAY,
-            NO_GPRS_CONTEXT,
-            ILLEGAL_MS,
-            ILLEGAL_ME,
-            GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
-            GPRS_SERVICES_NOT_ALLOWED,
-            MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
-            IMPLICITLY_DETACHED,
-            PLMN_NOT_ALLOWED,
-            LOCATION_AREA_NOT_ALLOWED,
-            GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
-            PDP_DUPLICATE,
-            UE_RAT_CHANGE,
-            CONGESTION,
-            NO_PDP_CONTEXT_ACTIVATED,
-            ACCESS_CLASS_DSAC_REJECTION,
-            PDP_ACTIVATE_MAX_RETRY_FAILED,
-            RADIO_ACCESS_BEARER_FAILURE,
-            ESM_UNKNOWN_EPS_BEARER_CONTEXT,
-            DRB_RELEASED_BY_RRC,
-            CONNECTION_RELEASED,
-            EMM_DETACHED,
-            EMM_ATTACH_FAILED,
-            EMM_ATTACH_STARTED,
-            LTE_NAS_SERVICE_REQUEST_FAILED,
-            DUPLICATE_BEARER_ID,
-            ESM_COLLISION_SCENARIOS,
-            ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
-            ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
-            ESM_BAD_OTA_MESSAGE,
-            ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
-            ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
-            DS_EXPLICIT_DEACTIVATION,
-            ESM_LOCAL_CAUSE_NONE,
-            LTE_THROTTLING_NOT_REQUIRED,
-            ACCESS_CONTROL_LIST_CHECK_FAILURE,
-            SERVICE_NOT_ALLOWED_ON_PLMN,
-            EMM_T3417_EXPIRED,
-            EMM_T3417_EXT_EXPIRED,
-            RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
-            RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
-            RRC_UPLINK_CONNECTION_RELEASE,
-            RRC_UPLINK_RADIO_LINK_FAILURE,
-            RRC_UPLINK_ERROR_REQUEST_FROM_NAS,
-            RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
-            RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
-            RRC_CONNECTION_ACCESS_BARRED,
-            RRC_CONNECTION_CELL_RESELECTION,
-            RRC_CONNECTION_CONFIG_FAILURE,
-            RRC_CONNECTION_TIMER_EXPIRED,
-            RRC_CONNECTION_LINK_FAILURE,
-            RRC_CONNECTION_CELL_NOT_CAMPED,
-            RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
-            RRC_CONNECTION_REJECT_BY_NETWORK,
-            RRC_CONNECTION_NORMAL_RELEASE,
-            RRC_CONNECTION_RADIO_LINK_FAILURE,
-            RRC_CONNECTION_REESTABLISHMENT_FAILURE,
-            RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
-            RRC_CONNECTION_ABORT_REQUEST,
-            RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
-            NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
-            NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
-            ESM_PROCEDURE_TIME_OUT,
-            INVALID_CONNECTION_ID,
-            MAXIMIUM_NSAPIS_EXCEEDED,
-            INVALID_PRIMARY_NSAPI,
-            CANNOT_ENCODE_OTA_MESSAGE,
-            RADIO_ACCESS_BEARER_SETUP_FAILURE,
-            PDP_ESTABLISH_TIMEOUT_EXPIRED,
-            PDP_MODIFY_TIMEOUT_EXPIRED,
-            PDP_INACTIVE_TIMEOUT_EXPIRED,
-            PDP_LOWERLAYER_ERROR,
-            PDP_MODIFY_COLLISION,
-            MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
-            NAS_REQUEST_REJECTED_BY_NETWORK,
-            RRC_CONNECTION_INVALID_REQUEST,
-            RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
-            RRC_CONNECTION_RF_UNAVAILABLE,
-            RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
-            RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
-            RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
-            RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
-            RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
-            IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
-            IMEI_NOT_ACCEPTED,
-            EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
-            EPS_SERVICES_NOT_ALLOWED_IN_PLMN,
-            MSC_TEMPORARILY_NOT_REACHABLE,
-            CS_DOMAIN_NOT_AVAILABLE,
-            ESM_FAILURE,
-            MAC_FAILURE,
-            SYNCHRONIZATION_FAILURE,
-            UE_SECURITY_CAPABILITIES_MISMATCH,
-            SECURITY_MODE_REJECTED,
-            UNACCEPTABLE_NON_EPS_AUTHENTICATION,
-            CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
-            NO_EPS_BEARER_CONTEXT_ACTIVATED,
-            INVALID_EMM_STATE,
-            NAS_LAYER_FAILURE,
-            MULTIPLE_PDP_CALL_NOT_ALLOWED,
-            EMBMS_NOT_ENABLED,
-            IRAT_HANDOVER_FAILED,
-            EMBMS_REGULAR_DEACTIVATION,
-            TEST_LOOPBACK_REGULAR_DEACTIVATION,
-            LOWER_LAYER_REGISTRATION_FAILURE,
-            DATA_PLAN_EXPIRED,
-            UMTS_HANDOVER_TO_IWLAN,
-            EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
-            EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
-            EVDO_HDR_CHANGED,
-            EVDO_HDR_EXITED,
-            EVDO_HDR_NO_SESSION,
-            EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
-            EVDO_HDR_CONNECTION_SETUP_TIMEOUT,
-            FAILED_TO_ACQUIRE_COLOCATED_HDR,
-            OTASP_COMMIT_IN_PROGRESS,
-            NO_HYBRID_HDR_SERVICE,
-            HDR_NO_LOCK_GRANTED,
-            DBM_OR_SMS_IN_PROGRESS,
-            HDR_FADE,
-            HDR_ACCESS_FAILURE,
-            UNSUPPORTED_1X_PREV,
-            LOCAL_END,
-            NO_SERVICE,
-            FADE,
-            NORMAL_RELEASE,
-            ACCESS_ATTEMPT_ALREADY_IN_PROGRESS,
-            REDIRECTION_OR_HANDOFF_IN_PROGRESS,
-            EMERGENCY_MODE,
-            PHONE_IN_USE,
-            INVALID_MODE,
-            INVALID_SIM_STATE,
-            NO_COLLOCATED_HDR,
-            UE_IS_ENTERING_POWERSAVE_MODE,
-            DUAL_SWITCH,
-            PPP_TIMEOUT,
-            PPP_AUTH_FAILURE,
-            PPP_OPTION_MISMATCH,
-            PPP_PAP_FAILURE,
-            PPP_CHAP_FAILURE,
-            PPP_CLOSE_IN_PROGRESS,
-            LIMITED_TO_IPV4,
-            LIMITED_TO_IPV6,
-            VSNCP_TIMEOUT,
-            VSNCP_GEN_ERROR,
-            VSNCP_APN_UNATHORIZED,
-            VSNCP_PDN_LIMIT_EXCEEDED,
-            VSNCP_NO_PDN_GATEWAY_ADDRESS,
-            VSNCP_PDN_GATEWAY_UNREACHABLE,
-            VSNCP_PDN_GATEWAY_REJECT,
-            VSNCP_INSUFFICIENT_PARAMETERS,
-            VSNCP_RESOURCE_UNAVAILABLE,
-            VSNCP_ADMINISTRATIVELY_PROHIBITED,
-            VSNCP_PDN_ID_IN_USE,
-            VSNCP_SUBSCRIBER_LIMITATION,
-            VSNCP_PDN_EXISTS_FOR_THIS_APN,
-            VSNCP_RECONNECT_NOT_ALLOWED,
-            IPV6_PREFIX_UNAVAILABLE,
-            HANDOFF_PREFERENCE_CHANGED,
-            OEM_DCFAILCAUSE_1,
-            OEM_DCFAILCAUSE_2,
-            OEM_DCFAILCAUSE_3,
-            OEM_DCFAILCAUSE_4,
-            OEM_DCFAILCAUSE_5,
-            OEM_DCFAILCAUSE_6,
-            OEM_DCFAILCAUSE_7,
-            OEM_DCFAILCAUSE_8,
-            OEM_DCFAILCAUSE_9,
-            OEM_DCFAILCAUSE_10,
-            OEM_DCFAILCAUSE_11,
-            OEM_DCFAILCAUSE_12,
-            OEM_DCFAILCAUSE_13,
-            OEM_DCFAILCAUSE_14,
-            OEM_DCFAILCAUSE_15,
-            REGISTRATION_FAIL,
-            GPRS_REGISTRATION_FAIL,
-            SIGNAL_LOST,
-            PREF_RADIO_TECH_CHANGED,
-            RADIO_POWER_OFF,
-            TETHERED_CALL_ACTIVE,
-            ERROR_UNSPECIFIED,
-            UNKNOWN,
-            RADIO_NOT_AVAILABLE,
-            UNACCEPTABLE_NETWORK_PARAMETER,
-            CONNECTION_TO_DATACONNECTIONAC_BROKEN,
-            LOST_CONNECTION,
-            RESET_BY_FRAMEWORK
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FailCause{}
-
     private static final Map<Integer, String> sFailCauseMap;
     static {
         sFailCauseMap = new HashMap<>();
@@ -1737,7 +1389,8 @@
      *
      * @hide
      */
-    public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause,
+    public static boolean isRadioRestartFailure(@NonNull Context context,
+                                                @DataFailureCause int cause,
                                                 int subId) {
         CarrierConfigManager configManager = (CarrierConfigManager)
                 context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -1765,7 +1418,8 @@
     }
 
     /** @hide */
-    public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause,
+    public static boolean isPermanentFailure(@NonNull Context context,
+                                             @DataFailureCause int failCause,
                                              int subId) {
         synchronized (sPermanentFailureCache) {
 
@@ -1825,7 +1479,7 @@
     }
 
     /** @hide */
-    public static boolean isEventLoggable(@FailCause int dataFailCause) {
+    public static boolean isEventLoggable(@DataFailureCause int dataFailCause) {
         return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES)
                 || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE)
                 || (dataFailCause == USER_AUTHENTICATION)
@@ -1845,13 +1499,13 @@
     }
 
     /** @hide */
-    public static String toString(@FailCause int dataFailCause) {
+    public static String toString(@DataFailureCause int dataFailCause) {
         int cause = getFailCause(dataFailCause);
         return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause);
     }
 
     /** @hide */
-    public static int getFailCause(@FailCause int failCause) {
+    public static int getFailCause(@DataFailureCause int failCause) {
         if (sFailCauseMap.containsKey(failCause)) {
             return failCause;
         } else {
diff --git a/telephony/java/android/telephony/ICellBroadcastService.aidl b/telephony/java/android/telephony/ICellBroadcastService.aidl
index eff64a2..11263d9 100644
--- a/telephony/java/android/telephony/ICellBroadcastService.aidl
+++ b/telephony/java/android/telephony/ICellBroadcastService.aidl
@@ -16,6 +16,9 @@
 
 package android.telephony;
 
+import android.os.RemoteCallback;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+
 /**
  * Service bound to by the system to allow custom handling of cell broadcast messages.
  * <p>
@@ -28,5 +31,9 @@
     oneway void handleGsmCellBroadcastSms(int slotId, in byte[] message);
 
     /** @see android.telephony.CellBroadcastService#onCdmaCellBroadcastSms */
-    oneway void handleCdmaCellBroadcastSms(int slotId, in byte[] message);
+    oneway void handleCdmaCellBroadcastSms(int slotId, in byte[] bearerData, int serviceCategory);
+
+    /** @see android.telephony.CellBroadcastService#onCdmaScpMessage */
+    oneway void handleCdmaScpMessage(int slotId, in List<CdmaSmsCbProgramData> programData,
+            String originatingAddress, in RemoteCallback callback);
 }
diff --git a/telephony/java/android/telephony/ICellInfoCallback.aidl b/telephony/java/android/telephony/ICellInfoCallback.aidl
index ee3c1b1..60732a3 100644
--- a/telephony/java/android/telephony/ICellInfoCallback.aidl
+++ b/telephony/java/android/telephony/ICellInfoCallback.aidl
@@ -16,7 +16,6 @@
 
 package android.telephony;
 
-import android.os.ParcelableException;
 import android.telephony.CellInfo;
 
 import java.util.List;
@@ -28,5 +27,5 @@
 oneway interface ICellInfoCallback
 {
     void onCellInfo(in List<CellInfo> state);
-    void onError(in int errorCode, in ParcelableException detail);
+    void onError(in int errorCode, in String exceptionName, in String message);
 }
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
new file mode 100644
index 0000000..02d8be3
--- /dev/null
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 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.SystemService;
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+
+/**
+ * Provides access to information about Telephony IMS services on the device.
+ *
+ * @hide
+ */
+@SystemService(Context.TELEPHONY_IMS_SERVICE)
+public class ImsManager {
+
+    private Context mContext;
+
+    public ImsManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Create an instance of ImsRcsManager for the subscription id specified.
+     *
+     * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
+     * @throws IllegalArgumentException if the subscription is invalid.
+     * @return a ImsRcsManager instance with the specific subscription ID.
+     */
+    public ImsRcsManager getImsRcsManager(int subscriptionId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
+            throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
+        }
+
+        return new ImsRcsManager(mContext, subscriptionId);
+    }
+
+    /**
+     * Create an instance of ImsMmTelManager for the subscription id specified.
+     *
+     * @param subscriptionId The ID of the subscription that this ImsMmTelManager will use.
+     * @throws IllegalArgumentException if the subscription is invalid.
+     * @return a ImsMmTelManager instance with the specific subscription ID.
+     */
+    public ImsMmTelManager getImsMmTelManager(int subscriptionId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
+            throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
+        }
+
+        return new ImsMmTelManager(subscriptionId);
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index a76b8da..3e02871 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -24,8 +24,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 0ce552a..e5bfb4d 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -28,6 +28,10 @@
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
+import android.telephony.Annotation.SrvccState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 
@@ -567,7 +571,7 @@
      * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
      * passed as an argument.
      */
-    public void onCallStateChanged(@TelephonyManager.CallState int state, String phoneNumber) {
+    public void onCallStateChanged(@CallState int state, String phoneNumber) {
         // default implementation empty
     }
 
@@ -773,7 +777,7 @@
      * @hide
      */
     @SystemApi
-    public void onSrvccStateChanged(@TelephonyManager.SrvccState int srvccState) {
+    public void onSrvccStateChanged(@SrvccState int srvccState) {
 
     }
 
@@ -791,7 +795,7 @@
      * @hide
      */
     @SystemApi
-    public void onVoiceActivationStateChanged(@TelephonyManager.SimActivationState int state) {
+    public void onVoiceActivationStateChanged(@SimActivationState int state) {
     }
 
     /**
@@ -807,7 +811,7 @@
      * @param state is the current SIM data activation state
      * @hide
      */
-    public void onDataActivationStateChanged(@TelephonyManager.SimActivationState int state) {
+    public void onDataActivationStateChanged(@SimActivationState int state) {
     }
 
     /**
@@ -966,7 +970,7 @@
      * @hide
      */
     @SystemApi
-    public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+    public void onRadioPowerStateChanged(@RadioPowerState int state) {
         // default implementation empty
     }
 
@@ -1233,7 +1237,7 @@
                     () -> mExecutor.execute(() -> psl.onPhoneCapabilityChanged(capability)));
         }
 
-        public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+        public void onRadioPowerStateChanged(@RadioPowerState int state) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index e1763ab..4273f5a 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 701a375..f929649 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -41,7 +41,7 @@
  *   <li>Precise background call state.
  * </ul>
  *
- * @see android.telephony.TelephonyManager.CallState which contains generic call states.
+ * @see android.telephony.Annotation.CallState which contains generic call states.
  *
  * @hide
  */
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 90d443a..257d634 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -23,6 +23,10 @@
 import android.net.LinkProperties;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.data.ApnSetting;
 
 import java.util.Objects;
@@ -47,10 +51,10 @@
 @SystemApi
 public final class PreciseDataConnectionState implements Parcelable {
 
-    private @TelephonyManager.DataState int mState = TelephonyManager.DATA_UNKNOWN;
-    private @TelephonyManager.NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    private @DataFailCause.FailCause int mFailCause = DataFailCause.NONE;
-    private @ApnSetting.ApnType int mAPNTypes = ApnSetting.TYPE_NONE;
+    private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
+    private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private @DataFailureCause int mFailCause = DataFailCause.NONE;
+    private @ApnType int mAPNTypes = ApnSetting.TYPE_NONE;
     private String mAPN = "";
     private LinkProperties mLinkProperties = null;
 
@@ -60,11 +64,11 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseDataConnectionState(@TelephonyManager.DataState int state,
-                                      @TelephonyManager.NetworkType int networkType,
-                                      @ApnSetting.ApnType int apnTypes, String apn,
+    public PreciseDataConnectionState(@DataState int state,
+                                      @NetworkType int networkType,
+                                      @ApnType int apnTypes, String apn,
                                       LinkProperties linkProperties,
-                                      @DataFailCause.FailCause int failCause) {
+                                      @DataFailureCause int failCause) {
         mState = state;
         mNetworkType = networkType;
         mAPNTypes = apnTypes;
@@ -99,7 +103,7 @@
      * Returns the state of data connection that supported the apn types returned by
      * {@link #getDataConnectionApnTypeBitMask()}
      */
-    public @TelephonyManager.DataState int getDataConnectionState() {
+    public @DataState int getDataConnectionState() {
         return mState;
     }
 
@@ -107,7 +111,7 @@
      * Returns the network type associated with this data connection.
      * @hide
      */
-    public @TelephonyManager.NetworkType int getDataConnectionNetworkType() {
+    public @NetworkType int getDataConnectionNetworkType() {
         return mNetworkType;
     }
 
@@ -115,7 +119,7 @@
      * Returns the data connection APN types supported by this connection and triggers
      * {@link PreciseDataConnectionState} change.
      */
-    public @ApnSetting.ApnType int getDataConnectionApnTypeBitMask() {
+    public @ApnType int getDataConnectionApnTypeBitMask() {
         return mAPNTypes;
     }
 
@@ -139,7 +143,7 @@
     /**
      * Returns data connection fail cause, in case there was a failure.
      */
-    public @DataFailCause.FailCause int getDataConnectionFailCause() {
+    public @Annotation.DataFailureCause int getDataConnectionFailCause() {
         return mFailCause;
     }
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a985a6b..c575129 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -29,6 +29,7 @@
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.NetworkRegistrationInfo.Domain;
 import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
@@ -1617,7 +1618,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
-    public @TelephonyManager.NetworkType int getDataNetworkType() {
+    public @NetworkType int getDataNetworkType() {
         final NetworkRegistrationInfo iwlanRegInfo = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
         final NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
@@ -1644,7 +1645,7 @@
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
-    public @TelephonyManager.NetworkType int getVoiceNetworkType() {
+    public @NetworkType int getVoiceNetworkType() {
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 209d462..3157e12 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -27,13 +27,11 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
-import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -45,7 +43,6 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IIntegerConsumer;
-import com.android.internal.telephony.IMms;
 import com.android.internal.telephony.ISms;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.SmsRawData;
@@ -357,6 +354,68 @@
                 true /* persistMessage*/, ActivityThread.currentPackageName());
     }
 
+    /**
+     * Send a text based SMS with messaging options.
+     *
+     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
+     * suitable default subscription could be found. In this case, if {@code sentIntent} is
+     * non-null, then the {@link PendingIntent} will be sent with an error code
+     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
+     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
+     * where this operation may fail.
+     * </p>
+     *
+     * @param destinationAddress the address to send the message to
+     * @param scAddress is the service center address or null to use
+     *  the current default SMSC
+     * @param text the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is successfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK</code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param priority Priority level of the message
+     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+     *  ---------------------------------
+     *  PRIORITY      | Level of Priority
+     *  ---------------------------------
+     *      '00'      |     Normal
+     *      '01'      |     Interactive
+     *      '10'      |     Urgent
+     *      '11'      |     Emergency
+     *  ----------------------------------
+     *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
+     * @param expectMore is a boolean to indicate the sending messages through same link or not.
+     * @param validityPeriod Validity Period of the message in mins.
+     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+     *  Validity Period(Minimum) -> 5 mins
+     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+     *  Any Other values included Negative considered as Invalid Validity Period of the message.
+     *
+     * @throws IllegalArgumentException if destinationAddress or text are empty
+     * {@hide}
+     */
+    @UnsupportedAppUsage
+    public void sendTextMessage(
+            String destinationAddress, String scAddress, String text,
+            PendingIntent sentIntent, PendingIntent deliveryIntent,
+            int priority, boolean expectMore, int validityPeriod) {
+        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+                true /* persistMessage*/, priority, expectMore, validityPeriod);
+    }
+
     private void sendTextMessageInternal(String destinationAddress, String scAddress,
             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
             boolean persistMessage, String packageName) {
@@ -455,109 +514,6 @@
                 false /* persistMessage */, ActivityThread.currentPackageName());
     }
 
-    /**
-     * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the SMS being sent on the subscription associated with logical
-     * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
-     * correct subscription.
-     * </p>
-     *
-     * @param persistMessage whether to persist the sent message in the SMS app. the caller must be
-     * the Phone process if set to false.
-     *
-     * @hide
-     */
-    public void sendTextMessageWithSelfPermissions(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-
-        if (TextUtils.isEmpty(text)) {
-            throw new IllegalArgumentException("Invalid message body");
-        }
-
-        try {
-            ISms iSms = getISmsServiceOrThrow();
-            iSms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(),
-                    destinationAddress,
-                    scAddress, text, sentIntent, deliveryIntent, persistMessage);
-        } catch (RemoteException ex) {
-            notifySmsGenericError(sentIntent);
-        }
-    }
-
-    /**
-     * Send a text based SMS with messaging options.
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param destinationAddress the address to send the message to
-     * @param scAddress is the service center address or null to use
-     *  the current default SMSC
-     * @param text the body of the message to send
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed.
-     *  The result code will be <code>Activity.RESULT_OK</code> for success,
-     *  or one of these errors:<br>
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
-     *  The per-application based SMS control checks sentIntent. If sentIntent
-     *  is NULL the caller will be checked against all unknown applications,
-     *  which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is delivered to the recipient.  The
-     *  raw pdu of the status report is in the extended data ("pdu").
-     * @param priority Priority level of the message
-     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
-     *  ---------------------------------
-     *  PRIORITY      | Level of Priority
-     *  ---------------------------------
-     *      '00'      |     Normal
-     *      '01'      |     Interactive
-     *      '10'      |     Urgent
-     *      '11'      |     Emergency
-     *  ----------------------------------
-     *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
-     * @param expectMore is a boolean to indicate the sending messages through same link or not.
-     * @param validityPeriod Validity Period of the message in mins.
-     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
-     *  Validity Period(Minimum) -> 5 mins
-     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
-     *  Any Other values included Negative considered as Invalid Validity Period of the message.
-     *
-     * @throws IllegalArgumentException if destinationAddress or text are empty
-     * {@hide}
-     */
-    @UnsupportedAppUsage
-    public void sendTextMessage(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent,
-            int priority, boolean expectMore, int validityPeriod) {
-        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                true /* persistMessage*/, priority, expectMore, validityPeriod);
-    }
-
     private void sendTextMessageInternal(
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
@@ -1078,37 +1034,6 @@
     }
 
     /**
-     * Send a multi-part text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Requires Permission:
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
-     * privileges.
-     * </p>
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony
-     * framework and will never trigger an SMS disambiguation dialog. If this method is called on a
-     * device that has multiple active subscriptions, this {@link SmsManager} instance has been
-     * created with {@link #getDefault()}, and no user-defined default subscription is defined, the
-     * subscription ID associated with this message will be INVALID, which will result in the SMS
-     * being sent on the subscription associated with logical slot 0. Use
-     * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct
-     * subscription.
-     * </p>
-     *
-     * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
-     * ArrayList, int, boolean, int)
-     * @hide
-     **/
-    public void sendMultipartTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, List<String> parts,
-            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
-            int priority, boolean expectMore, int validityPeriod) {
-        sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, false /* persistMessage*/, priority, expectMore,
-                validityPeriod);
-    }
-
-    /**
      * Send a data based SMS to a specific application port.
      *
      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -1180,45 +1105,6 @@
     }
 
     /**
-     * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the SMS being sent on the subscription associated with logical
-     * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
-     * correct subscription.
-     * </p>
-     *
-     * @hide
-     */
-    public void sendDataMessageWithSelfPermissions(
-            String destinationAddress, String scAddress, short destinationPort,
-            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-
-        if (data == null || data.length == 0) {
-            throw new IllegalArgumentException("Invalid message data");
-        }
-
-        try {
-            ISms iSms = getISmsServiceOrThrow();
-            iSms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), destinationAddress, scAddress,
-                    destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
-        } catch (RemoteException e) {
-            Log.e(TAG, "sendDataMessageWithSelfPermissions: Couldn't send SMS - Exception: "
-                    + e.getMessage());
-            notifySmsGenericError(sentIntent);
-        }
-    }
-
-    /**
      * Get the SmsManager associated with the default subscription id. The instance will always be
      * associated with the default subscription id, even if the default subscription id changes.
      *
@@ -1650,100 +1536,6 @@
 
     /**
      * Enable reception of cell broadcast (SMS-CB) messages with the given
-     * message identifier and RAN type. The RAN type specify this message ID
-     * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
-     * enable the same message identifier, they must both disable it for the device to stop
-     * receiving those messages. All received messages will be broadcast in an
-     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
-     * Note: This call is blocking, callers may want to avoid calling it from
-     * the main thread of an application.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType the message format as defined in {@link SmsCbMessage]
-     * @return true if successful, false otherwise
-     * @see #disableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean enableCellBroadcast(int messageIdentifier,
-            @android.telephony.SmsCbMessage.MessageFormat int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iSms = getISmsService();
-            if (iSms != null) {
-                // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
-                // the default phone internally.
-                success = iSms.enableCellBroadcastForSubscriber(getSubscriptionId(),
-                        messageIdentifier, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Disable reception of cell broadcast (SMS-CB) messages with the given
-     * message identifier and RAN type. The RAN type specify this message ID
-     * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
-     * enable the same message identifier, they must both disable it for the
-     * device to stop receiving those messages.
-     * Note: This call is blocking, callers may want to avoid calling it from
-     * the main thread of an application.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType the message format as defined in {@link SmsCbMessage}
-     * @return true if successful, false otherwise
-     *
-     * @see #enableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean disableCellBroadcast(int messageIdentifier,
-            @android.telephony.SmsCbMessage.MessageFormat int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iSms = getISmsService();
-            if (iSms != null) {
-                // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
-                // the default phone internally.
-                success = iSms.disableCellBroadcastForSubscriber(getSubscriptionId(),
-                        messageIdentifier, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range and RAN type. The RAN type specifies if this message ID
      * belongs to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
      * the same message identifier, they must both disable it for the device to stop
@@ -2174,9 +1966,6 @@
     @SystemApi
     static public final int RESULT_REQUEST_NOT_SUPPORTED = 24;
 
-
-    static private final String PHONE_PACKAGE_NAME = "com.android.phone";
-
     /**
      * Send an MMS message
      *
@@ -2203,17 +1992,8 @@
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        try {
-            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-
-            iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
+        MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri,
                     locationUrl, configOverrides, sentIntent);
-        } catch (RemoteException e) {
-            // Ignore it
-        }
     }
 
     /**
@@ -2246,16 +2026,8 @@
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        try {
-            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-            iMms.downloadMessage(getSubscriptionId(), ActivityThread.currentPackageName(),
-                    locationUrl, contentUri, configOverrides, downloadedIntent);
-        } catch (RemoteException e) {
-            // Ignore it
-        }
+        MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl,
+                contentUri, configOverrides, downloadedIntent);
     }
 
     // MMS send/download failure result codes
@@ -2273,434 +2045,17 @@
     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
 
-    /**
-     * Import a text message into system's SMS store
-     *
-     * Only default SMS apps can import SMS
-     *
-     * @param address the destination(source) address of the sent(received) message
-     * @param type the type of the message
-     * @param text the message text
-     * @param timestampMillis the message timestamp in milliseconds
-     * @param seen if the message is seen
-     * @param read if the message is read
-     * @return the message URI, null if failed
-     * @hide
-     */
-    public Uri importTextMessage(String address, int type, String text, long timestampMillis,
-            boolean seen, boolean read) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.importTextMessage(ActivityThread.currentPackageName(),
-                        address, type, text, timestampMillis, seen, read);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
     /** Represents the received SMS message for importing {@hide} */
     public static final int SMS_TYPE_INCOMING = 0;
     /** Represents the sent SMS message for importing {@hide} */
     public static final int SMS_TYPE_OUTGOING = 1;
 
-    /**
-     * Import a multimedia message into system's MMS store. Only the following PDU type is
-     * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
-     *
-     * Only default SMS apps can import MMS
-     *
-     * @param contentUri the content uri from which to read the PDU of the message to import
-     * @param messageId the optional message id. Use null if not specifying
-     * @param timestampSecs the optional message timestamp. Use -1 if not specifying
-     * @param seen if the message is seen
-     * @param read if the message is read
-     * @return the message URI, null if failed
-     * @throws IllegalArgumentException if pdu is empty
-     * {@hide}
-     */
-    public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
-            boolean seen, boolean read) {
-        if (contentUri == null) {
-            throw new IllegalArgumentException("Uri contentUri null");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
-                        contentUri, messageId, timestampSecs, seen, read);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Delete a system stored SMS or MMS message
-     *
-     * Only default SMS apps can delete system stored SMS and MMS messages
-     *
-     * @param messageUri the URI of the stored message
-     * @return true if deletion is successful, false otherwise
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public boolean deleteStoredMessage(Uri messageUri) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Delete a system stored SMS or MMS thread
-     *
-     * Only default SMS apps can delete system stored SMS and MMS conversations
-     *
-     * @param conversationId the ID of the message conversation
-     * @return true if deletion is successful, false otherwise
-     * {@hide}
-     */
-    public boolean deleteStoredConversation(long conversationId) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.deleteStoredConversation(
-                        ActivityThread.currentPackageName(), conversationId);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Update the status properties of a system stored SMS or MMS message, e.g.
-     * the read status of a message, etc.
-     *
-     * @param messageUri the URI of the stored message
-     * @param statusValues a list of status properties in key-value pairs to update
-     * @return true if update is successful, false otherwise
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
-                        messageUri, statusValues);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
     /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
     public static final String MESSAGE_STATUS_SEEN = "seen";
     /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
     public static final String MESSAGE_STATUS_READ = "read";
 
     /**
-     * Archive or unarchive a stored conversation
-     *
-     * @param conversationId the ID of the message conversation
-     * @param archived true to archive the conversation, false to unarchive
-     * @return true if update is successful, false otherwise
-     * {@hide}
-     */
-    public boolean archiveStoredConversation(long conversationId, boolean archived) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
-                        conversationId, archived);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Add a text message draft to system SMS store
-     *
-     * Only default SMS apps can add SMS draft
-     *
-     * @param address the destination address of message
-     * @param text the body of the message to send
-     * @return the URI of the stored draft message
-     * {@hide}
-     */
-    public Uri addTextMessageDraft(String address, String text) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Add a multimedia message draft to system MMS store
-     *
-     * Only default SMS apps can add MMS draft
-     *
-     * @param contentUri the content uri from which to read the PDU data of the draft MMS
-     * @return the URI of the stored draft message
-     * @throws IllegalArgumentException if pdu is empty
-     * {@hide}
-     */
-    public Uri addMultimediaMessageDraft(Uri contentUri) {
-        if (contentUri == null) {
-            throw new IllegalArgumentException("Uri contentUri null");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
-                        contentUri);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Send a system stored text message.
-     *
-     * You can only send a failed text message or a draft text message.
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param scAddress is the service center address or null to use the current default SMSC
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed.
-     *  The result code will be <code>Activity.RESULT_OK</code> for success,
-     *  or one of these errors:<br>
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
-     *  The per-application based SMS control checks sentIntent. If sentIntent
-     *  is NULL the caller will be checked against all unknown applications,
-     *  which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is delivered to the recipient.  The
-     *  raw pdu of the status report is in the extended data ("pdu").
-     *
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
-            PendingIntent deliveryIntent) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        resolveSubscriptionForOperation(new SubscriptionResolverResult() {
-            @Override
-            public void onSuccess(int subId) {
-                try {
-                    ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendStoredText(subId, ActivityThread.currentPackageName(), messageUri,
-                            scAddress, sentIntent, deliveryIntent);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
-                            + e.getMessage());
-                    notifySmsGenericError(sentIntent);
-                }
-            }
-            @Override
-            public void onFailure() {
-                notifySmsErrorNoDefaultSet(context, sentIntent);
-            }
-        });
-    }
-
-    /**
-     * Send a system stored multi-part text message.
-     *
-     * You can only send a failed text message or a draft text message.
-     * The provided <code>PendingIntent</code> lists should match the part number of the
-     * divided text of the stored message by using <code>divideMessage</code>
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param scAddress is the service center address or null to use
-     *   the current default SMSC
-     * @param sentIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been sent.
-     *   The result code will be <code>Activity.RESULT_OK</code> for success,
-     *   or one of these errors:<br>
-     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *   <code>RESULT_ERROR_NULL_PDU</code><br>
-     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
-     *   the extra "errorCode" containing a radio technology specific value,
-     *   generally only useful for troubleshooting.<br>
-     *   The per-application based SMS control checks sentIntent. If sentIntent
-     *   is NULL the caller will be checked against all unknown applications,
-     *   which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been delivered
-     *   to the recipient.  The raw pdu of the status report is in the
-     *   extended data ("pdu").
-     *
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
-            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        resolveSubscriptionForOperation(new SubscriptionResolverResult() {
-            @Override
-            public void onSuccess(int subId) {
-                try {
-                    ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendStoredMultipartText(subId, ActivityThread.currentPackageName(),
-                            messageUri, scAddress, sentIntents, deliveryIntents);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
-                            + e.getMessage());
-                    notifySmsGenericError(sentIntents);
-                }
-            }
-            @Override
-            public void onFailure() {
-                notifySmsErrorNoDefaultSet(context, sentIntents);
-            }
-        });
-    }
-
-    /**
-     * Send a system stored MMS message
-     *
-     * This is used for sending a previously sent, but failed-to-send, message or
-     * for sending a text message that has been stored as a draft.
-     *
-     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param configOverrides the carrier-specific messaging configuration values to override for
-     *  sending the message.
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
-            PendingIntent sentIntent) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                iMms.sendStoredMessage(
-                        getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
-                        configOverrides, sentIntent);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
-     *
-     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
-     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
-     * automatically
-     *
-     * This flag can only be changed by default SMS apps
-     *
-     * @param enabled Whether to enable message auto persisting
-     * {@hide}
-     */
-    public void setAutoPersisting(boolean enabled) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
-     *
-     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
-     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
-     * automatically
-     *
-     * @return the current value of the auto persist flag
-     * {@hide}
-     */
-    public boolean getAutoPersisting() {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.getAutoPersisting();
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
      * Get carrier-dependent configuration values.
      *
      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
@@ -2716,15 +2071,7 @@
      * @return bundle key/values pairs of configuration values
      */
     public Bundle getCarrierConfigValues() {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.getCarrierConfigValues(getSubscriptionId());
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
+        return MmsManager.getInstance().getCarrierConfigValues(getSubscriptionId());
     }
 
     /**
@@ -2810,38 +2157,38 @@
     }
 
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The prefixes is a list of prefix {@code String} separated by this delimiter.
      * @hide
      */
     public static final String REGEX_PREFIX_DELIMITER = ",";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The success status to be added into the intent to be sent to the calling package.
      * @hide
      */
     public static final int RESULT_STATUS_SUCCESS = 0;
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The timeout status to be added into the intent to be sent to the calling package.
      * @hide
      */
     public static final int RESULT_STATUS_TIMEOUT = 1;
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * Intent extra key of the retrieved SMS message as a {@code String}.
      * @hide
      */
     public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * Intent extra key of SMS retriever status, which indicates whether the request for the
      * coming SMS message is SUCCESS or TIMEOUT
      * @hide
      */
     public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
      * @hide
      */
@@ -2891,74 +2238,6 @@
         }
     }
 
-    /**
-     * Filters a bundle to only contain MMS config variables.
-     *
-     * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
-     * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the
-     * supplied bundle.
-     *
-     * @param config a Bundle that contains MMS config variables and possibly more.
-     * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above.
-     * @hide
-     */
-    public static Bundle getMmsConfig(BaseBundle config) {
-        Bundle filtered = new Bundle();
-        filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID,
-                config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID));
-        filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED,
-                config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
-                config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO,
-                config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO));
-        filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED,
-                config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
-                config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
-        filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
-                config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
-        filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
-                config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
-        filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
-        filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
-        filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
-        filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT));
-        filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS));
-        filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS));
-        filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
-                config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
-        filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
-                config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
-        filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
-                config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
-        filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH,
-                config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH));
-        filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
-                config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
-        filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME,
-                config.getString(MMS_CONFIG_UA_PROF_TAG_NAME));
-        filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT));
-        filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL));
-        filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS));
-        filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
-                config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
-        filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX));
-        filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
-                config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
-        filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
-                config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
-        return filtered;
-    }
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SMS_CATEGORY_"},
@@ -3049,4 +2328,74 @@
         }
         return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE;
     }
+
+    /**
+     * Gets the SMSC address from (U)SIM.
+     *
+     * <p class="note"><strong>Note:</strong> Using this method requires that your app is the
+     * default SMS application, or READ_PRIVILEGED_PHONE_STATE permission, or has the carrier
+     * privileges.</p>
+     *
+     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
+     * dialog. If this method is called on a device that has multiple active subscriptions, this
+     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
+     * default subscription is defined, the subscription ID associated with this method will be
+     * INVALID, which will result in the operation being completed on the subscription associated
+     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation
+     * is performed on the correct subscription.
+     * </p>
+     *
+     * @return the SMSC address string, null if failed.
+     */
+    @SuppressAutoDoc // for carrier privileges and default SMS application.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Nullable
+    public String getSmscAddress() {
+        String smsc = null;
+
+        try {
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                smsc = iSms.getSmscAddressFromIccEfForSubscriber(
+                        getSubscriptionId(), ActivityThread.currentPackageName());
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return smsc;
+    }
+
+    /**
+     * Sets the SMSC address on (U)SIM.
+     *
+     * <p class="note"><strong>Note:</strong> Using this method requires that your app is the
+     * default SMS application, or has {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission, or has the carrier privileges.</p>
+     *
+     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
+     * dialog. If this method is called on a device that has multiple active subscriptions, this
+     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
+     * default subscription is defined, the subscription ID associated with this method will be
+     * INVALID, which will result in the operation being completed on the subscription associated
+     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation
+     * is performed on the correct subscription.
+     * </p>
+     *
+     * @param smsc the SMSC address string.
+     * @return true for success, false otherwise.
+     */
+    @SuppressAutoDoc // for carrier privileges and default SMS application.
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setSmscAddress(@NonNull String smsc) {
+        try {
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                return iSms.setSmscAddressOnIccEfForSubscriber(
+                        smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4e93efd..3bd6578 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -54,6 +54,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
@@ -895,6 +896,11 @@
      */
     public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
 
+    /**
+     * Integer extra to specify SIM slot index.
+     */
+    public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
+
     private final Context mContext;
     private volatile INetworkPolicyManager mNetworkPolicy;
 
@@ -2095,13 +2101,13 @@
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static boolean isValidSlotIndex(int slotIndex) {
-        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSupportedModemCount();
+        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getActiveModemCount();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public static boolean isValidPhoneId(int phoneId) {
-        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getSupportedModemCount();
+        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getActiveModemCount();
     }
 
     /** @hide */
@@ -2122,6 +2128,7 @@
         if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
         intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId);
+        intent.putExtra(EXTRA_SLOT_INDEX, phoneId);
         intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c9440a6..63cd511 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -63,8 +63,13 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
 import android.telephony.VisualVoicemailService.VisualVoicemailTask;
-import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
 import android.telephony.ims.ImsMmTelManager;
@@ -254,17 +259,6 @@
      */
     public static final int UNINITIALIZED_CARD_ID = -2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"SRVCC_STATE_"},
-            value = {
-                    SRVCC_STATE_HANDOVER_NONE,
-                    SRVCC_STATE_HANDOVER_STARTED,
-                    SRVCC_STATE_HANDOVER_COMPLETED,
-                    SRVCC_STATE_HANDOVER_FAILED,
-                    SRVCC_STATE_HANDOVER_CANCELED})
-    public @interface SrvccState {}
-
     private final Context mContext;
     private final int mSubId;
     @UnsupportedAppUsage
@@ -2499,41 +2493,37 @@
      * @return the lowercase 2 character ISO-3166 country code, or empty string if not available.
      */
     public String getNetworkCountryIso() {
-        return getNetworkCountryIsoForPhone(getPhoneId());
+        return getNetworkCountryIso(getPhoneId());
     }
 
     /**
-     * Returns the ISO country code equivalent of the MCC (Mobile Country Code) of the current
+     * Returns the ISO-3166 country code equivalent of the MCC (Mobile Country Code) of the current
      * registered operator or the cell nearby, if available.
      * <p>
+     * The ISO-3166 country code is provided in lowercase 2 character format.
+     * <p>
+     * Note: In multi-sim, this returns a shared emergency network country iso from other
+     * subscription if the subscription used to create the TelephonyManager doesn't camp on
+     * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding
+     * slot.
      * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine
      * if on a CDMA network).
-     *
-     * @param subId for which Network CountryIso is returned
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public String getNetworkCountryIso(int subId) {
-        return getNetworkCountryIsoForPhone(getPhoneId(subId));
-    }
-
-    /**
-     * Returns the ISO country code equivalent of the current registered
-     * operator's MCC (Mobile Country Code) of a subscription.
      * <p>
-     * Availability: Only when user is registered to a network. Result may be
-     * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
-     * on a CDMA network).
      *
-     * @param phoneId for which Network CountryIso is returned
+     * @param slotIndex the SIM slot index to get network country ISO.
+     *
+     * @return the lowercase 2 character ISO-3166 country code, or empty string if not available.
+     *
+     * {@hide}
      */
-    /** {@hide} */
-    @UnsupportedAppUsage
-    public String getNetworkCountryIsoForPhone(int phoneId) {
+    @SystemApi
+    @TestApi
+    @NonNull
+    public String getNetworkCountryIso(int slotIndex) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null) return "";
-            return telephony.getNetworkCountryIsoForPhone(phoneId);
+            return telephony.getNetworkCountryIsoForPhone(slotIndex);
         } catch (RemoteException ex) {
             return "";
         }
@@ -2592,33 +2582,6 @@
     /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
     public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_NR;
 
-    /** @hide */
-    @IntDef({
-            NETWORK_TYPE_UNKNOWN,
-            NETWORK_TYPE_GPRS,
-            NETWORK_TYPE_EDGE,
-            NETWORK_TYPE_UMTS,
-            NETWORK_TYPE_CDMA,
-            NETWORK_TYPE_EVDO_0,
-            NETWORK_TYPE_EVDO_A,
-            NETWORK_TYPE_1xRTT,
-            NETWORK_TYPE_HSDPA,
-            NETWORK_TYPE_HSUPA,
-            NETWORK_TYPE_HSPA,
-            NETWORK_TYPE_IDEN,
-            NETWORK_TYPE_EVDO_B,
-            NETWORK_TYPE_LTE,
-            NETWORK_TYPE_EHRPD,
-            NETWORK_TYPE_HSPAP,
-            NETWORK_TYPE_GSM,
-            NETWORK_TYPE_TD_SCDMA,
-            NETWORK_TYPE_IWLAN,
-            NETWORK_TYPE_LTE_CA,
-            NETWORK_TYPE_NR,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface NetworkType{}
-
     /**
      * Return the current data network type.
      *
@@ -4563,6 +4526,17 @@
     }
 
     /**
+     * Sim activation type: voice
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+    /**
+     * Sim activation type: data
+     * @hide
+     */
+    public static final int SIM_ACTIVATION_TYPE_DATA = 1;
+
+    /**
      * Initial SIM activation state, unknown. Not set by any carrier apps.
      * @hide
      */
@@ -4605,17 +4579,6 @@
     @SystemApi
     public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4;
 
-    /** @hide */
-    @IntDef({
-            SIM_ACTIVATION_STATE_UNKNOWN,
-            SIM_ACTIVATION_STATE_ACTIVATING,
-            SIM_ACTIVATION_STATE_ACTIVATED,
-            SIM_ACTIVATION_STATE_DEACTIVATED,
-            SIM_ACTIVATION_STATE_RESTRICTED
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SimActivationState{}
-
      /**
       * Sets the voice activation state
       *
@@ -5000,15 +4963,6 @@
      */
     public static final int CALL_STATE_OFFHOOK = 2;
 
-    /** @hide */
-    @IntDef(prefix = { "CALL_STATE_" }, value = {
-            CALL_STATE_IDLE,
-            CALL_STATE_RINGING,
-            CALL_STATE_OFFHOOK
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CallState{}
-
     /**
      * Returns the state of all calls on the device.
      * <p>
@@ -5089,6 +5043,17 @@
      */
     public static final int DATA_ACTIVITY_DORMANT = 0x00000004;
 
+    /** @hide */
+    @IntDef(prefix = {"DATA_"}, value = {
+        DATA_ACTIVITY_NONE,
+        DATA_ACTIVITY_IN,
+        DATA_ACTIVITY_OUT,
+        DATA_ACTIVITY_INOUT,
+        DATA_ACTIVITY_DORMANT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataActivityType{}
+
     /**
      * Returns a constant indicating the type of activity on a data connection
      * (cellular).
@@ -5524,19 +5489,20 @@
             telephony.requestCellInfoUpdate(
                     getSubId(),
                     new ICellInfoCallback.Stub() {
+                        @Override
                         public void onCellInfo(List<CellInfo> cellInfo) {
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onCellInfo(cellInfo)));
                         }
 
-                        public void onError(int errorCode, android.os.ParcelableException detail) {
+                        @Override
+                        public void onError(int errorCode, String exceptionName, String message) {
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onError(
                                             errorCode,
-                                            detail == null ? null : detail.getCause())));
+                                            createThrowableByClassName(exceptionName, message))));
                         }
                     }, getOpPackageName());
-
         } catch (RemoteException ex) {
         }
     }
@@ -5565,22 +5531,36 @@
             telephony.requestCellInfoUpdateWithWorkSource(
                     getSubId(),
                     new ICellInfoCallback.Stub() {
+                        @Override
                         public void onCellInfo(List<CellInfo> cellInfo) {
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onCellInfo(cellInfo)));
                         }
 
-                        public void onError(int errorCode, android.os.ParcelableException detail) {
+                        @Override
+                        public void onError(int errorCode, String exceptionName, String message) {
                             Binder.withCleanCallingIdentity(() ->
                                     executor.execute(() -> callback.onError(
                                             errorCode,
-                                            detail == null ? null : detail.getCause())));
+                                            createThrowableByClassName(exceptionName, message))));
                         }
                     }, getOpPackageName(), workSource);
         } catch (RemoteException ex) {
         }
     }
 
+    private static Throwable createThrowableByClassName(String className, String message) {
+        if (className == null) {
+            return null;
+        }
+        try {
+            Class<?> c = Class.forName(className);
+            return (Throwable) c.getConstructor(String.class).newInstance(message);
+        } catch (ReflectiveOperationException | ClassCastException e) {
+        }
+        return new RuntimeException(className + ": " + message);
+    }
+
     /**
      * Sets the minimum time in milli-seconds between {@link PhoneStateListener#onCellInfoChanged
      * PhoneStateListener.onCellInfoChanged} will be invoked.
@@ -8340,15 +8320,6 @@
         return false;
     }
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"RADIO_POWER_"},
-            value = {RADIO_POWER_OFF,
-                    RADIO_POWER_ON,
-                    RADIO_POWER_UNAVAILABLE,
-            })
-    public @interface RadioPowerState {}
-
     /**
      * Radio explicitly powered off (e.g, airplane mode).
      * @hide
@@ -9448,32 +9419,63 @@
         return returnValue;
     }
 
-    private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+    /**
+     * Returns the subscription ID for the given phone account handle.
+     *
+     * @param phoneAccountHandle the phone account handle for outgoing calls
+     * @return subscription ID for the given phone account handle; or
+     *         {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}
+     *         if not available; or throw a SecurityException if the caller doesn't have the
+     *         permission.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public int getSubIdForPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
         int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
-            ITelecomService service = getTelecomService();
+            ITelephony service = getITelephony();
             if (service != null) {
-                retval = getSubIdForPhoneAccount(service.getPhoneAccount(phoneAccountHandle));
+                retval = service.getSubIdForPhoneAccountHandle(
+                        phoneAccountHandle, mContext.getOpPackageName());
             }
-        } catch (RemoteException e) {
+        } catch (RemoteException ex) {
+            Log.e(TAG, "getSubIdForPhoneAccountHandle RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
-
         return retval;
     }
 
     /**
-     * Resets Telephony and IMS settings back to factory defaults.
+     * Resets telephony manager settings back to factory defaults.
      *
      * @hide
      */
-    @SystemApi
-    @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL)
     public void factoryReset(int subId) {
         try {
             Log.d(TAG, "factoryReset: subId=" + subId);
             ITelephony telephony = getITelephony();
-            if (telephony != null)
+            if (telephony != null) {
                 telephony.factoryReset(subId);
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
+
+    /**
+     * Resets Telephony and IMS settings back to factory defaults only for the subscription
+     * associated with this instance.
+     * @see #createForSubscriptionId(int)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL)
+    public void resetSettings() {
+        try {
+            Log.d(TAG, "resetSettings: subId=" + getSubId());
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.factoryReset(getSubId());
+            }
         } catch (RemoteException e) {
         }
     }
@@ -10826,6 +10828,16 @@
     }
 
     /**
+     * Broadcast intent action for Ota emergency number database installation complete.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED =
+            "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED";
+
+    /**
      * Returns whether {@link TelephonyManager#ACTION_EMERGENCY_ASSISTANCE emergency assistance} is
      * available on the device.
      * <p>
@@ -11466,11 +11478,14 @@
      *  3) APN type is whitelisted. E.g. MMS is whitelisted if
      *  {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
      *
+     * @param apnType Value indicating the apn type. Apn types are defined in {@link ApnSetting}.
      * @return whether data is enabled for a apn type.
      *
      * @hide
      */
-    public boolean isDataEnabledForApn(@ApnSetting.ApnType int apnType) {
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean isDataEnabledForApn(@ApnType int apnType) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         try {
             ITelephony service = getITelephony();
@@ -11491,7 +11506,7 @@
      *
      * @hide
      */
-    public boolean isApnMetered(@ApnSetting.ApnType int apnType) {
+    public boolean isApnMetered(@ApnType int apnType) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl
new file mode 100644
index 0000000..a648a0e
--- /dev/null
+++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/** @hide */
+package android.telephony.cdma;
+
+parcelable CdmaSmsCbProgramData;
+
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index e65e032..60774e7 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -26,6 +26,8 @@
 import android.os.Parcelable;
 import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -109,23 +111,6 @@
     /** APN type for MCX (Mission Critical Service) where X can be PTT/Video/Data */
     public static final int TYPE_MCX = ApnTypes.MCX;
 
-    /** @hide */
-    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
-        TYPE_DEFAULT,
-        TYPE_MMS,
-        TYPE_SUPL,
-        TYPE_DUN,
-        TYPE_HIPRI,
-        TYPE_FOTA,
-        TYPE_IMS,
-        TYPE_CBS,
-        TYPE_IA,
-        TYPE_EMERGENCY,
-        TYPE_MCX
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ApnType {}
-
     // Possible values for authentication types.
     /** No authentication type. */
     public static final int AUTH_TYPE_NONE = 0;
@@ -1430,7 +1415,7 @@
      *
      * @hide
      */
-    public boolean canSupportNetworkType(@TelephonyManager.NetworkType int networkType) {
+    public boolean canSupportNetworkType(@NetworkType int networkType) {
         // Do a special checking for GSM. In reality, GSM is a voice only network type and can never
         // be used for data. We allow it here because in some DSDS corner cases, on the non-DDS
         // sub, modem reports data rat unknown. In that case if voice is GSM and this APN supports
@@ -1959,8 +1944,9 @@
          * {@link ApnSetting} built from this builder otherwise.
          */
         public ApnSetting build() {
-            if ((mApnTypeBitmask & TYPE_ALL) == 0 || TextUtils.isEmpty(mApnName)
-                || TextUtils.isEmpty(mEntryName)) {
+            if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI |
+                    TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX)) == 0
+                || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
                 return null;
             }
             return new ApnSetting(this);
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 9170e88..49625bb 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -24,8 +24,8 @@
 import android.net.LinkAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.DataFailureCause;
 import android.telephony.DataFailCause;
-import android.telephony.DataFailCause.FailCause;
 import android.telephony.data.ApnSetting.ProtocolType;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -67,7 +67,7 @@
     /** Indicates the data connection is active with physical link up. */
     public static final int LINK_STATUS_ACTIVE = 2;
 
-    private final @FailCause int mCause;
+    private final @DataFailureCause int mCause;
     private final int mSuggestedRetryTime;
     private final int mId;
     private final @LinkStatus int mLinkStatus;
@@ -103,7 +103,7 @@
      *
      * @removed Use the {@link Builder()} instead.
      */
-    public DataCallResponse(@FailCause int cause, int suggestedRetryTime, int id,
+    public DataCallResponse(@DataFailureCause int cause, int suggestedRetryTime, int id,
                             @LinkStatus int linkStatus,
                             @ProtocolType int protocolType, @Nullable String interfaceName,
                             @Nullable List<LinkAddress> addresses,
@@ -150,7 +150,7 @@
     /**
      * @return Data call fail cause. {@link DataFailCause#NONE} indicates no error.
      */
-    @FailCause
+    @DataFailureCause
     public int getCause() { return mCause; }
 
     /**
@@ -314,7 +314,7 @@
      * </code></pre>
      */
     public static final class Builder {
-        private @FailCause int mCause;
+        private @DataFailureCause int mCause;
 
         private int mSuggestedRetryTime;
 
@@ -348,7 +348,7 @@
          * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setCause(@FailCause int cause) {
+        public @NonNull Builder setCause(@DataFailureCause int cause) {
             mCause = cause;
             return this;
         }
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 0d79ec9..30c209b 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -25,8 +25,8 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.ApnType;
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
-import android.telephony.data.ApnSetting.ApnType;
 import android.telephony.data.ApnSetting.AuthType;
 import android.text.TextUtils;
 
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 0e1751d..e793979 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -27,8 +27,8 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.Annotation.ApnType;
 import android.telephony.Rlog;
-import android.telephony.data.ApnSetting.ApnType;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -133,7 +133,7 @@
          * service.
          *
          * @param apnTypes APN types of the qualified networks. This must be a bitmask combination
-         * of {@link ApnSetting.ApnType}.
+         * of {@link ApnType}.
          * @param qualifiedNetworkTypes List of network types which are qualified for data
          * connection setup for {@link @apnType} in the preferred order. Each element in the list
          * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index ed292be..9fc8e75 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,7 +25,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -34,11 +33,9 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
-import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IIntegerConsumer;
@@ -46,8 +43,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -63,7 +58,7 @@
  * @hide
  */
 @SystemApi
-public class ImsMmTelManager {
+public class ImsMmTelManager implements RegistrationManager {
 
     /**
      * @hide
@@ -96,94 +91,18 @@
      * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
      */
-    public static class RegistrationCallback {
-
-        private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
-
-            // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
-            // and WWAN are more accurate constants.
-            private static final Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
-                    new HashMap<Integer, Integer>() {{
-                        // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
-                        // case, since it is defined.
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
-                                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
-                                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
-                    }};
-
-            private final RegistrationCallback mLocalCallback;
-            private Executor mExecutor;
-
-            RegistrationBinder(RegistrationCallback localCallback) {
-                mLocalCallback = localCallback;
-            }
-
-            @Override
-            public void onRegistered(int imsRadioTech) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
-            }
-
-            @Override
-            public void onRegistering(int imsRadioTech) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
-            }
-
-            @Override
-            public void onDeregistered(ImsReasonInfo info) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
-            }
-
-            @Override
-            public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
-                                getAccessType(imsRadioTech), info)));
-            }
-
-            @Override
-            public void onSubscriberAssociatedUriChanged(Uri[] uris) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() ->
-                                mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
-            }
-
-            private void setExecutor(Executor executor) {
-                mExecutor = executor;
-            }
-
-            private static int getAccessType(int regType) {
-                if (!IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
-                    Log.w("ImsMmTelManager", "RegistrationBinder - invalid regType returned: "
-                            + regType);
-                    return -1;
-                }
-                return IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
-            }
-        }
-
-        private final RegistrationBinder mBinder = new RegistrationBinder(this);
+    // Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
+    @Deprecated
+    public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
 
         /**
          * Notifies the framework when the IMS Provider is registered to the IMS network.
          *
          * @param imsTransportType the radio access technology.
          */
+        @Override
         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
@@ -192,6 +111,7 @@
          *
          * @param imsTransportType the radio access technology.
          */
+        @Override
         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
@@ -200,6 +120,7 @@
          *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          */
+        @Override
         public void onUnregistered(@Nullable ImsReasonInfo info) {
         }
 
@@ -209,33 +130,11 @@
          * @param imsTransportType The transport type that has failed to handover registration to.
          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
          */
+        @Override
         public void onTechnologyChangeFailed(
                 @AccessNetworkConstants.TransportType int imsTransportType,
                 @Nullable ImsReasonInfo info) {
         }
-
-        /**
-         * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
-         * it changes. Per RFC3455, an associated URI is a URI that the service provider has
-         * allocated to a user for their own usage. A user's phone number is typically one of the
-         * associated URIs.
-         * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
-         *         subscription.
-         * @hide
-         */
-        public void onSubscriberAssociatedUriChanged(@Nullable Uri[] uris) {
-        }
-
-        /**@hide*/
-        public final IImsRegistrationCallback getBinder() {
-            return mBinder;
-        }
-
-        /**@hide*/
-        //Only exposed as public for compatibility with deprecated ImsManager APIs.
-        public void setExecutor(Executor executor) {
-            mBinder.setExecutor(executor);
-        }
     }
 
     /**
@@ -355,7 +254,10 @@
      * the {@link ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
+     * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
+     * RegistrationManager.RegistrationCallback)} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull RegistrationCallback c) throws ImsException {
@@ -380,6 +282,27 @@
         }
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        c.setExecutor(executor);
+        try {
+            getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
+        } catch (RemoteException | IllegalStateException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
     /**
      * Removes an existing {@link RegistrationCallback}.
      *
@@ -390,7 +313,10 @@
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @deprecated Use {@link #unregisterImsRegistrationCallback(
+     * RegistrationManager.RegistrationCallback)}.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
         if (c == null) {
@@ -403,6 +329,69 @@
         }
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void unregisterImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c) {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        try {
+            getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
+        if (stateCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null callback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        try {
+            getITelephony().getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
+                @Override
+                public void accept(int result) {
+                    executor.execute(() -> stateCallback.accept(result));
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType
+                    Consumer<Integer> transportTypeCallback) {
+        if (transportTypeCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null callback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        try {
+            getITelephony().getImsMmTelRegistrationTransportType(mSubId,
+                    new IIntegerConsumer.Stub() {
+                        @Override
+                        public void accept(int result) {
+                            executor.execute(() -> transportTypeCallback.accept(result));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     /**
      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
      * availability updates for the subscription specified in
@@ -411,7 +400,7 @@
      *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
+     * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current capabilities.
@@ -617,17 +606,17 @@
      * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
      * @param capability The capability that is being queried for support on the carrier network.
      * @param transportType The transport type of the capability to check support for.
+     * @param executor The executor that the callback will be called with.
      * @param callback A consumer containing a Boolean result specifying whether or not the
      *                 capability is supported on this carrier network for the transport specified.
-     * @param executor The executor that the callback will be called with.
      * @throws ImsException if the subscription is no longer valid or the IMS service is not
      * available.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
             @AccessNetworkConstants.TransportType int transportType,
-            @NonNull Consumer<Boolean> callback,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> callback) throws ImsException {
         if (callback == null) {
             throw new IllegalArgumentException("Must include a non-null Consumer.");
         }
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3c343dd..21707b0 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -22,21 +22,28 @@
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.os.Binder;
-import android.telephony.SubscriptionManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRcsController;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
 
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Manager for interfacing with the framework RCS services, including the User Capability Exchange
  * (UCE) service, as well as managing user settings.
  *
- * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager.
+ * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this manager.
  * @hide
  */
-public class ImsRcsManager {
+public class ImsRcsManager implements RegistrationManager {
+    private static final String TAG = "ImsRcsManager";
 
     /**
      * Receives RCS availability status updates from the ImsService.
@@ -110,32 +117,83 @@
     private final int mSubId;
     private final Context mContext;
 
-
     /**
-     * Create an instance of ImsRcsManager for the subscription id specified.
-     *
-     * @param context The context to create this ImsRcsManager instance within.
-     * @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
-     * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
-     * @throws IllegalArgumentException if the subscription is invalid.
+     * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
      * @hide
      */
-    public static ImsRcsManager createForSubscriptionId(Context context, int subscriptionId) {
-        if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
-            throw new IllegalArgumentException("Invalid subscription ID");
-        }
-
-        return new ImsRcsManager(context, subscriptionId);
+    public ImsRcsManager(Context context, int subId) {
+        mSubId = subId;
+        mContext = context;
     }
 
     /**
-     * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this class.
+     * @return A {@link RcsUceAdapter} used for User Capability Exchange (UCE) operations for
+     * this subscription.
+     * @hide
      */
-    private ImsRcsManager(Context context, int subId) {
-        mContext = context;
-        mSubId = subId;
+    @NonNull
+    public RcsUceAdapter getUceAdapter() {
+        return new RcsUceAdapter(mSubId);
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    public void registerImsRegistrationCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationCallback c)
+            throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        c.setExecutor(executor);
+        throw new UnsupportedOperationException("registerImsRegistrationCallback is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void unregisterImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c) {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        throw new UnsupportedOperationException("unregisterImsRegistrationCallback is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
+        if (stateCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null stateCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        throw new UnsupportedOperationException("getRegistrationState is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType
+                    Consumer<Integer> transportTypeCallback) {
+        if (transportTypeCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null transportTypeCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        throw new UnsupportedOperationException("getRegistrationTransportType is not"
+                + "supported.");
+    }
+
+
     /**
      * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
      * availability updates for the subscription specified.
@@ -165,9 +223,22 @@
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
+
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "Register availability callback: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
         c.setExecutor(executor);
-        throw new UnsupportedOperationException("registerRcsAvailabilityCallback is not"
-                + "supported.");
+        try {
+            imsRcsController.registerRcsAvailabilityCallback(c.getBinder());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
     /**
@@ -178,14 +249,31 @@
      * inactive subscription, it will result in a no-op.
      * @param c The RCS {@link AvailabilityCallback} to be removed.
      * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+     * @throws ImsException if the IMS service is not available when calling this method
+     * {@link ImsRcsController#unregisterRcsAvailabilityCallback()}.
+     * See {@link ImsException#getCode()} for more information on the error codes.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c) {
+    public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c)
+            throws ImsException {
         if (c == null) {
             throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
         }
-        throw new UnsupportedOperationException("unregisterRcsAvailabilityCallback is not"
-                + "supported.");
+
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "Unregister availability callback: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            imsRcsController.unregisterRcsAvailabilityCallback(c.getBinder());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
     /**
@@ -200,10 +288,27 @@
      * rather the subscription is capable of this service over IMS.
      * @see #isAvailable(int)
      * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
+     * @throws ImsException if the IMS service is not available when calling this method
+     * {@link ImsRcsController#isCapable(int, int)}.
+     * See {@link ImsException#getCode()} for more information on the error codes.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
-        throw new UnsupportedOperationException("isCapable is not supported.");
+    public boolean isCapable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability)
+            throws ImsException {
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "isCapable: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            return imsRcsController.isCapable(mSubId, capability);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#isCapable", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
     /**
@@ -217,18 +322,31 @@
      * false otherwise. If the capability is available, IMS is registered and the service is
      * currently available over IMS.
      * @see #isCapable(int)
+     * @throws ImsException if the IMS service is not available when calling this method
+     * {@link ImsRcsController#isAvailable(int, int)}.
+     * See {@link ImsException#getCode()} for more information on the error codes.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
-        throw new UnsupportedOperationException("isAvailable is not supported.");
+    public boolean isAvailable(@RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability)
+            throws ImsException {
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "isAvailable: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            return imsRcsController.isAvailable(mSubId, capability);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#isAvailable", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
-    /**
-     * @return A new {@link RcsUceAdapter} used for User Capability Exchange (UCE) operations for
-     * this subscription.
-     */
-    @NonNull
-    public RcsUceAdapter getUceAdapter() {
-        return new RcsUceAdapter(mSubId);
+    private IImsRcsController getIImsRcsController() {
+        IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+        return IImsRcsController.Stub.asInterface(binder);
     }
 }
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index be34f9d..0510a00 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -336,4 +336,31 @@
     public @ClirInterrogationStatus int getClirInterrogationStatus() {
         return mClirInterrogationStatus;
     }
+
+    /**
+     * Parts of telephony still use the old {m,n} 3GPP definition, so convert to that format.
+     * @hide
+     */
+    public int[] getCompatArray(@ImsSsData.ServiceType int type) {
+        int[] result = new int[2];
+        // Convert ImsSsInfo into a form that telephony can read (as per 3GPP 27.007)
+        // CLIR (section 7.7)
+        if (type == ImsSsData.SS_CLIR) {
+            // Assume there will only be one ImsSsInfo.
+            // contains {"n","m"} parameters
+            result[0] = getClirOutgoingState();
+            result[1] = getClirInterrogationStatus();
+            return result;
+        }
+        // COLR 7.31
+        if (type == ImsSsData.SS_COLR) {
+            result[0] = getProvisionStatus();
+        }
+        // Facility Lock CLCK 7.4 (for call barring), CLIP 7.6, COLP 7.8, as well as any
+        // other result, just return the status for the "n" parameter and provisioning status for
+        // "m" as the default.
+        result[0] = getStatus();
+        result[1] = getProvisionStatus();
+        return result;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index d50a0f7..1a21d0a 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -16,22 +16,53 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.telephony.ims.stub.ImsUtImplBase;
 import android.util.Log;
 
 import com.android.ims.internal.IImsUtListener;
 
 /**
- * Base implementation of the IMS UT listener interface, which implements stubs.
- * Override these methods to implement functionality.
+ * Listener interface used to receive network responses back from UT supplementary service queries
+ * made by the framework.
  * @hide
  */
 // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
 // will break other implementations of ImsUt maintained by other ImsServices.
 @SystemApi
 public class ImsUtListener {
+
+    /**
+     * The {@link Bundle} key for a Calling Line Identification Restriction (CLIR) response. The
+     * value will be an int[] with two values:
+     * int[0] contains the 'n' parameter from TS 27.007 7.7, which is the
+     * outgoing CLIR state. See {@link ImsSsInfo#CLIR_OUTGOING_DEFAULT},
+     * {@link ImsSsInfo#CLIR_OUTGOING_INVOCATION}, and {@link ImsSsInfo#CLIR_OUTGOING_SUPPRESSION};
+     * int[1] contains the 'm' parameter from TS 27.007 7.7, which is the CLIR interrogation status.
+     * See {@link ImsSsInfo#CLIR_STATUS_NOT_PROVISIONED},
+     * {@link ImsSsInfo#CLIR_STATUS_PROVISIONED_PERMANENT}, {@link ImsSsInfo#CLIR_STATUS_UNKNOWN},
+     * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_RESTRICTED}, and
+     * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_ALLOWED}.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public static final String BUNDLE_KEY_CLIR = "queryClir";
+
+    /**
+     * The {@link Bundle} key for a Calling Line Identification Presentation (CLIP), Connected Line
+     * Identification Presentation (COLP), or Connected Line Identification Restriction (COLR)
+     * response. The value will be an instance of {@link ImsSsInfo}, which contains the response to
+     * the query.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
+
     private IImsUtListener mServiceInterface;
     private static final String LOG_TAG = "ImsUtListener";
 
@@ -51,14 +82,54 @@
         }
     }
 
-    public void onUtConfigurationQueried(int id, Bundle ssInfo) {
+    /**
+     * Notify the framework of a UT configuration response to a {@link ImsUtImplBase#queryClir()},
+     * {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     * {@link ImsUtImplBase#queryColr()} query for the transaction ID specified. If the query fails,
+     * {@link #onUtConfigurationQueryFailed(int, ImsReasonInfo)} should be called.
+     * @param id The ID associated with this UT configuration transaction from the framework.
+     * @param configuration A {@link Bundle} containing the result of querying the UT configuration.
+     *                      Must contain {@link #BUNDLE_KEY_CLIR} if it is a response to
+     *                      {@link ImsUtImplBase#queryClir()} or
+     *                      {@link #BUNDLE_KEY_SSINFO} if it is a response to
+     *                      {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     *                      {@link ImsUtImplBase#queryColr()}.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public void onUtConfigurationQueried(int id, Bundle configuration) {
         try {
-            mServiceInterface.utConfigurationQueried(null, id, ssInfo);
+            mServiceInterface.utConfigurationQueried(null, id, configuration);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "utConfigurationQueried: remote exception");
         }
     }
 
+    /**
+     * Notify the framework of a UT configuration response to a {@link ImsUtImplBase#queryClir()},
+     * {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     * {@link ImsUtImplBase#queryColr()} query for the transaction ID specified. If the query fails,
+     * the framework should be notified via
+     * {@link #onUtConfigurationQueryFailed(int, ImsReasonInfo)}.
+     * @param id The ID associated with this UT configuration transaction from the framework.
+     * @param configuration An {@link ImsSsInfo} instance containing the configuration for the
+     *                      line identification supplementary service queried.
+     */
+    public void onLineIdentificationSupplementaryServiceResponse(int id,
+            @NonNull ImsSsInfo configuration) {
+        try {
+            mServiceInterface.lineIdentificationSupplementaryServiceResponse(id, configuration);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "onLineIdentificationSupplementaryServicesResponse: remote exception");
+        }
+    }
+
+    /**
+     * Notify the Framework of the line identification query failure.
+     * @param id The ID associated with the UT query transaction.
+     * @param error The query failure reason.
+     */
     public void onUtConfigurationQueryFailed(int id, ImsReasonInfo error) {
         try {
             mServiceInterface.utConfigurationQueryFailed(null, id, error);
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index a6a7a84..b47bcb9 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -23,6 +23,13 @@
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -36,6 +43,7 @@
  * @hide
  */
 public class RcsUceAdapter {
+    private static final String TAG = "RcsUceAdapter";
 
     /**
      * An unknown error has caused the request to fail.
@@ -188,7 +196,6 @@
 
     /**
      * Not to be instantiated directly, use
-     * {@link ImsRcsManager#createForSubscriptionId(Context, int)} and
      * {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
      */
     RcsUceAdapter(int subId) {
@@ -218,7 +225,45 @@
     public void requestCapabilities(@CallbackExecutor Executor executor,
             @NonNull List<Uri> contactNumbers,
             @NonNull CapabilitiesCallback c) throws ImsException {
-        throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        if (contactNumbers == null) {
+            throw new IllegalArgumentException("Must include non-null contact number list.");
+        }
+
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "requestCapabilities: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
+            @Override
+            public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
+                Binder.withCleanCallingIdentity(() ->
+                        executor.execute(() ->
+                                c.onCapabilitiesReceived(contactCapabilities)));
+            }
+            @Override
+            public void onError(int errorCode) {
+                Binder.withCleanCallingIdentity(() ->
+                        executor.execute(() ->
+                                c.onError(errorCode)));
+            }
+        };
+
+        try {
+            imsRcsController.requestCapabilities(mSubId, contactNumbers, internalCallback);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
     /**
@@ -233,7 +278,20 @@
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @PublishState int getUcePublishState() throws ImsException {
-        throw new UnsupportedOperationException("getPublishState is not supported.");
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "getUcePublishState: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            return imsRcsController.getUcePublishState(mSubId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#getUcePublishState", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
 
     /**
@@ -252,9 +310,22 @@
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public boolean isUceSettingEnabled() throws ImsException {
-        // TODO: add SubscriptionController column for this property.
-        throw new UnsupportedOperationException("isUceSettingEnabled is not supported.");
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "isUceSettingEnabled: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            return imsRcsController.isUceSettingEnabled(mSubId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#isUceSettingEnabled", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
     }
+
     /**
      * Change the user’s setting for whether or not UCE is enabled for the associated subscription.
      * @param isEnabled the user's setting for whether or not they wish for Presence and User
@@ -270,7 +341,24 @@
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setUceSettingEnabled(boolean isEnabled) throws ImsException {
-        // TODO: add SubscriptionController column for this property.
-        throw new UnsupportedOperationException("setUceSettingEnabled is not supported.");
+        IImsRcsController imsRcsController = getIImsRcsController();
+        if (imsRcsController == null) {
+            Log.e(TAG, "setUceSettingEnabled: IImsRcsController is null");
+            throw new ImsException("Can not find remote IMS service",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+
+        try {
+            imsRcsController.setUceSettingEnabled(mSubId, isEnabled);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling IImsRcsController#setUceSettingEnabled", e);
+            throw new ImsException("Remote IMS Service is not available",
+                    ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
+    private IImsRcsController getIImsRcsController() {
+        IBinder binder = ServiceManager.getService(Context.TELEPHONY_IMS_SERVICE);
+        return IImsRcsController.Stub.asInterface(binder);
     }
 }
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
new file mode 100644
index 0000000..23402b8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2019 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.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Binder;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Manages IMS Service registration state for associated {@link ImsFeature}s.
+ * @hide
+ */
+@SystemApi
+public interface RegistrationManager {
+
+    /**
+     * @hide
+     */
+    // Defines the underlying radio technology type that we have registered for IMS over.
+    @IntDef(prefix = "REGISTRATION_STATE_",
+            value = {
+                    REGISTRATION_STATE_NOT_REGISTERED,
+                    REGISTRATION_STATE_REGISTERING,
+                    REGISTRATION_STATE_REGISTERED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsRegistrationState {}
+
+    /**
+     * The IMS service is currently not registered to the carrier network.
+     */
+    int REGISTRATION_STATE_NOT_REGISTERED = 0;
+
+    /**
+     * The IMS service is currently in the process of registering to the carrier network.
+     */
+    int REGISTRATION_STATE_REGISTERING = 1;
+
+    /**
+     * The IMS service is currently registered to the carrier network.
+     */
+    int REGISTRATION_STATE_REGISTERED = 2;
+
+
+    /**@hide*/
+    // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
+    // and WWAN are more accurate constants.
+    Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
+            new HashMap<Integer, Integer>() {{
+                // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
+                // case, since it is defined.
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+            }};
+
+    /**
+     * Callback class for receiving IMS network Registration callback events.
+     * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     */
+    class RegistrationCallback {
+
+        private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
+
+            private final RegistrationCallback mLocalCallback;
+            private Executor mExecutor;
+
+            RegistrationBinder(RegistrationCallback localCallback) {
+                mLocalCallback = localCallback;
+            }
+
+            @Override
+            public void onRegistered(int imsRadioTech) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+                        mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
+            }
+
+            @Override
+            public void onRegistering(int imsRadioTech) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+                        mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
+            }
+
+            @Override
+            public void onDeregistered(ImsReasonInfo info) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
+            }
+
+            @Override
+            public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
+                                getAccessType(imsRadioTech), info)));
+            }
+
+            @Override
+            public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() ->
+                                mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
+            }
+
+            private void setExecutor(Executor executor) {
+                mExecutor = executor;
+            }
+
+            private static int getAccessType(int regType) {
+                if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
+                    Log.w("RegistrationManager", "RegistrationBinder - invalid regType returned: "
+                            + regType);
+                    return -1;
+                }
+                return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
+            }
+        }
+
+        private final RegistrationBinder mBinder = new RegistrationBinder(this);
+
+        /**
+         * Notifies the framework when the IMS Provider is registered to the IMS network.
+         *
+         * @param imsTransportType the radio access technology.
+         */
+        public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
+        }
+
+        /**
+         * Notifies the framework when the IMS Provider is trying to register the IMS network.
+         *
+         * @param imsTransportType the radio access technology.
+         */
+        public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
+        }
+
+        /**
+         * Notifies the framework when the IMS Provider is deregistered from the IMS network.
+         *
+         * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+         */
+        public void onUnregistered(@Nullable ImsReasonInfo info) {
+        }
+
+        /**
+         * A failure has occurred when trying to handover registration to another technology type.
+         *
+         * @param imsTransportType The transport type that has failed to handover registration to.
+         * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
+         */
+        public void onTechnologyChangeFailed(
+                @AccessNetworkConstants.TransportType int imsTransportType,
+                @Nullable ImsReasonInfo info) {
+        }
+
+        /**
+         * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
+         * it changes. Per RFC3455, an associated URI is a URI that the service provider has
+         * allocated to a user for their own usage. A user's phone number is typically one of the
+         * associated URIs.
+         * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
+         *         subscription.
+         * @hide
+         */
+        public void onSubscriberAssociatedUriChanged(@Nullable Uri[] uris) {
+        }
+
+        /**@hide*/
+        public final IImsRegistrationCallback getBinder() {
+            return mBinder;
+        }
+
+        /**@hide*/
+        //Only exposed as public for compatibility with deprecated ImsManager APIs.
+        public void setExecutor(Executor executor) {
+            mBinder.setExecutor(executor);
+        }
+    }
+
+    /**
+     * Registers a {@link RegistrationCallback} with the system. Use
+     * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
+     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
+     *
+     * When the callback is registered, it will initiate the callback c to be called with the
+     * current registration state.
+     *
+     * @param executor The executor the callback events should be run on.
+     * @param c The {@link RegistrationCallback} to be added.
+     * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @throws ImsException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+     * reason.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull RegistrationCallback c) throws ImsException;
+
+    /**
+     * Removes an existing {@link RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
+     * @param c The {@link RegistrationCallback} to be removed.
+     * @see SubscriptionManager.OnSubscriptionsChangedListener
+     * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c);
+
+    /**
+     * Gets the registration state of the IMS service.
+     * @param executor The {@link Executor} that will be used to call the IMS registration state
+     *                 callback.
+     * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+ *                      registration state of the IMS service, which will be one of the
+ *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
+ *                      {@link #REGISTRATION_STATE_REGISTERING}, or
+ *                      {@link #REGISTRATION_STATE_REGISTERED}.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsRegistrationState Consumer<Integer> stateCallback);
+
+    /**
+     * Gets the Transport Type associated with the current IMS registration.
+     * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+     * @param transportTypeCallback The transport type associated with the current IMS registration,
+ *                              which will be one of following:
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+ *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationTransportType(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
new file mode 100644
index 0000000..b379bd0
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.net.Uri;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+
+/**
+ * Interface used to interact with the Telephony IMS.
+ *
+ * {@hide}
+ */
+interface IImsRcsController {
+    void registerRcsAvailabilityCallback(IImsCapabilityCallback c);
+    void unregisterRcsAvailabilityCallback(IImsCapabilityCallback c);
+    boolean isCapable(int subId, int capability);
+    boolean isAvailable(int subId, int capability);
+
+    // ImsUceAdapter specific
+    void requestCapabilities(int subId, in List<Uri> contactNumbers, IRcsUceControllerCallback c);
+    int getUcePublishState(int subId);
+    boolean isUceSettingEnabled(int subId);
+    void setUceSettingEnabled(int subId, boolean isEnabled);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
new file mode 100644
index 0000000..5975930
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/IRcsUceControllerCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019 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.RcsContactUceCapability;
+
+/**
+ * Provides interface for RCS UCE when receive a change.
+ *
+ * {@hide}
+ */
+oneway interface IRcsUceControllerCallback {
+    void onCapabilitiesReceived(in List<RcsContactUceCapability> contactCapabilities);
+    void onError(int errorCode);
+}
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
index 976c2be..ae113f2 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
@@ -18,12 +18,11 @@
 
 import android.os.Bundle;
 import android.os.RemoteException;
-
-import android.annotation.UnsupportedAppUsage;
 import android.telephony.ims.ImsCallForwardInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsSsData;
 import android.telephony.ims.ImsSsInfo;
+
 import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsUtListener;
 
@@ -65,6 +64,13 @@
     }
 
     /**
+     * Notifies the result of a line identification supplementary service query.
+     */
+    @Override
+    public void lineIdentificationSupplementaryServiceResponse(int id, ImsSsInfo config) {
+    }
+
+    /**
      * Notifies the status of the call barring supplementary service.
      */
     @Override
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index a08e031..b455c2e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -22,6 +22,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.util.Log;
@@ -72,9 +73,6 @@
     // with NOT_REGISTERED in the case where the ImsService has not updated the registration state
     // yet.
     private static final int REGISTRATION_STATE_UNKNOWN = -1;
-    private static final int REGISTRATION_STATE_NOT_REGISTERED = 0;
-    private static final int REGISTRATION_STATE_REGISTERING = 1;
-    private static final int REGISTRATION_STATE_REGISTERED = 2;
 
     private final IImsRegistration mBinder = new IImsRegistration.Stub() {
 
@@ -128,7 +126,7 @@
      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
      */
     public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERED);
+        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         mCallbacks.broadcast((c) -> {
             try {
                 c.onRegistered(imsRadioTech);
@@ -146,7 +144,7 @@
      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
      */
     public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERING);
+        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         mCallbacks.broadcast((c) -> {
             try {
                 c.onRegistering(imsRadioTech);
@@ -230,7 +228,8 @@
 
     private void updateToDisconnectedState(ImsReasonInfo info) {
         synchronized (mLock) {
-            updateToState(REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED);
+            updateToState(REGISTRATION_TECH_NONE,
+                    RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
             if (info != null) {
                 mLastDisconnectCause = info;
             } else {
@@ -264,15 +263,15 @@
             disconnectInfo = mLastDisconnectCause;
         }
         switch (state) {
-            case REGISTRATION_STATE_NOT_REGISTERED: {
+            case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: {
                 c.onDeregistered(disconnectInfo);
                 break;
             }
-            case REGISTRATION_STATE_REGISTERING: {
+            case RegistrationManager.REGISTRATION_STATE_REGISTERING: {
                 c.onRegistering(getConnectionType());
                 break;
             }
-            case REGISTRATION_STATE_REGISTERED: {
+            case RegistrationManager.REGISTRATION_STATE_REGISTERED: {
                 c.onRegistered(getConnectionType());
                 break;
             }
diff --git a/telephony/java/com/android/ims/internal/IImsUtListener.aidl b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
index fcb9fb1..9a12cee 100644
--- a/telephony/java/com/android/ims/internal/IImsUtListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
@@ -44,6 +44,7 @@
     @UnsupportedAppUsage
     void utConfigurationQueryFailed(in IImsUt ut, int id, in ImsReasonInfo error);
 
+    void lineIdentificationSupplementaryServiceResponse(int id, in ImsSsInfo config);
     /**
      * Notifies the status of the call barring supplementary service.
      */
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 7441c26..c1d700a 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -586,4 +586,23 @@
      * @param destAddress the destination address to test for possible short code
      */
     int checkSmsShortCodeDestination(int subId, String callingApk, String destAddress, String countryIso);
+
+    /**
+     * Gets the SMSC address from (U)SIM.
+     *
+     * @param subId the subscription Id.
+     * @param callingPackage the package name of the calling app.
+     * @return the SMSC address string, null if failed.
+     */
+    String getSmscAddressFromIccEfForSubscriber(int subId, String callingPackage);
+
+    /**
+     * Sets the SMSC address on (U)SIM.
+     *
+     * @param smsc the SMSC address string.
+     * @param subId the subscription Id.
+     * @param callingPackage the package name of the calling app.
+     * @return true for success, false otherwise.
+     */
+    boolean setSmscAddressOnIccEfForSubscriber(String smsc, int subId, String callingPackage);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index aa1f94f..ff816f2 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -208,4 +208,15 @@
             int subid, String callingApk, String destAddress, String countryIso) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public String getSmscAddressFromIccEfForSubscriber(int subId, String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setSmscAddressOnIccEfForSubscriber(
+            String smsc, int subId, String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ab3861e..414693e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1309,6 +1309,12 @@
     int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
 
     /**
+     * Returns the subscription ID associated with the specified PhoneAccountHandle.
+     */
+    int getSubIdForPhoneAccountHandle(in PhoneAccountHandle phoneAccountHandle,
+            String callingPackage);
+
+    /**
      * Returns the PhoneAccountHandle associated with a subscription ID.
      */
     PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId);
@@ -1796,6 +1802,16 @@
     void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c);
 
     /**
+     * Get the IMS service registration state for the MmTelFeature associated with this sub id.
+     */
+    void getImsMmTelRegistrationState(int subId, IIntegerConsumer consumer);
+
+    /**
+     * Get the transport type for the IMS service registration state.
+     */
+    void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer);
+
+    /**
      * Adds an IMS MmTel capabilities callback for the subscription specified.
      */
     void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c);
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index a20c494..21b2f39 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -43,8 +43,8 @@
     void listenForSubscriber(in int subId, String pkg, IPhoneStateListener callback, int events,
             boolean notifyNow);
     @UnsupportedAppUsage
-    void notifyCallState(int state, String incomingNumber);
-    void notifyCallStateForPhoneId(in int phoneId, in int subId, int state, String incomingNumber);
+    void notifyCallStateForAllSubs(int state, String incomingNumber);
+    void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber);
     void notifyServiceStateForPhoneId(in int phoneId, in int subId, in ServiceState state);
     void notifySignalStrengthForPhoneId(in int phoneId, in int subId,
             in SignalStrength signalStrength);
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index f8621c9..5b2f688 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -74,10 +74,6 @@
     public static final int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
     public static final int PRESENTATION_PAYPHONE = 4;   // show pay phone info
 
-    // Sim activation type
-    public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
-    public static final int SIM_ACTIVATION_TYPE_DATA = 1;
-
     public static final String PHONE_NAME_KEY = "phoneName";
     public static final String DATA_NETWORK_TYPE_KEY = "networkType";
     public static final String DATA_FAILURE_CAUSE_KEY = "failCause";
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 2a16421..1523875 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -19,17 +19,17 @@
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
 
 import android.content.res.Resources;
-import android.os.Parcel;
 import android.os.SystemProperties;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
 import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.Rlog;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
 import com.android.internal.telephony.SmsAddress;
 import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsHeader;
@@ -43,7 +43,6 @@
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.BitwiseInputStream;
 import com.android.internal.util.HexDump;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
 
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -881,6 +880,20 @@
     }
 
     /**
+     * @return the bearer data byte array
+     */
+    public byte[] getEnvelopeBearerData() {
+        return mEnvelope.bearerData;
+    }
+
+    /**
+     * @return the 16-bit CDMA SCPT service category
+     */
+    public @CdmaSmsCbProgramData.Category int getEnvelopeServiceCategory() {
+        return mEnvelope.serviceCategory;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index 4a49fbf..49b5f7f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -58,17 +58,17 @@
 
     // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1
     public static final int SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT  =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT;  // = 4096
     public static final int SERVICE_CATEGORY_CMAS_EXTREME_THREAT            =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT;            // = 4097
     public static final int SERVICE_CATEGORY_CMAS_SEVERE_THREAT             =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT;             // = 4098
     public static final int SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY; // = 4099
     public static final int SERVICE_CATEGORY_CMAS_TEST_MESSAGE              =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE;              // = 4100
     public static final int SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE       =
-            CdmaSmsCbProgramData.CATEGORY_CMAS_LAST_RESERVED_VALUE;
+            CdmaSmsCbProgramData.CATEGORY_CMAS_LAST_RESERVED_VALUE;       // = 4351
 
     /**
      * Provides the type of a SMS message like point to point, broadcast or acknowledge
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 81b1e49..0b5d446 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -19,8 +19,14 @@
 java_sdk_library {
     name: "android.test.mock",
 
-    srcs: ["src/**/*.java"],
-    api_srcs: [":framework-all-sources"],
+    srcs: [
+        "src/**/*.java",
+        // Note: Below are NOT APIs of this library. We only take APIs under
+        // the android.test.mock package. They however provide private APIs that
+        // android.test.mock APIs references to.
+        ":framework-core-sources-for-test-mock",
+        ":framework_native_aidl",
+    ],
     libs: ["framework-all"],
 
     api_packages: [
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index a95b6f1..727684e 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -463,6 +463,13 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 81937e6..f8e338e 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -106,13 +106,18 @@
         // Test the profile contents contain common methods for core-oj that would normally be AOT
         // compiled.
         res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file="
-                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar");
+                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"
+                + " --apk=/system/framework/services.jar");
         boolean sawObjectInit = false;
+        boolean sawPmInit = false;
         for (String line : res.split("\n")) {
             if (line.contains("Ljava/lang/Object;-><init>()V")) {
                 sawObjectInit = true;
+            } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) {
+                sawPmInit = true;
             }
         }
         assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
+        assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit);
     }
 }
diff --git a/tests/Gating/Android.bp b/tests/Gating/Android.bp
new file mode 100644
index 0000000..b6c0094
--- /dev/null
+++ b/tests/Gating/Android.bp
@@ -0,0 +1,17 @@
+android_test {
+    name: "Gating",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    certificate: "platform",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "junit",
+        "android-support-test",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+        "platform_compat-test-rules"
+    ],
+}
diff --git a/tests/Gating/AndroidManifest.xml b/tests/Gating/AndroidManifest.xml
new file mode 100644
index 0000000..7f14b83
--- /dev/null
+++ b/tests/Gating/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.gating">
+    <application android:label="GatingTest">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.tests.gating"/>
+</manifest>
diff --git a/tests/Gating/AndroidTest.xml b/tests/Gating/AndroidTest.xml
new file mode 100644
index 0000000..730e74a
--- /dev/null
+++ b/tests/Gating/AndroidTest.xml
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Test compatibility change gating.">
+    <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="Gating.apk"/>
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-tag" value="Gating"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.tests.gating"/>
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/tests/Gating/src/com/android/compat/testing/DummyApi.java b/tests/Gating/src/com/android/compat/testing/DummyApi.java
new file mode 100644
index 0000000..25106f9
--- /dev/null
+++ b/tests/Gating/src/com/android/compat/testing/DummyApi.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compat.testing;
+
+import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * This is a dummy API to test gating
+ *
+ * @hide
+ */
+public class DummyApi {
+
+    public static final long CHANGE_ID = 666013;
+    public static final long CHANGE_ID_1 = 666014;
+    public static final long CHANGE_ID_2 = 666015;
+    public static final long CHANGE_SYSTEM_SERVER = 666016;
+
+    /**
+     * Dummy method
+     * @return "A" if change is enabled, "B" otherwise.
+     */
+    public static String dummyFunc() {
+        if (Compatibility.isChangeEnabled(CHANGE_ID)) {
+            return "A";
+        }
+        return "B";
+    }
+
+    /**
+     * Dummy combined method
+     * @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled,
+               "1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled,
+               "2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled,
+               "3" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is enabled.
+     */
+    public static String dummyCombinedFunc() {
+        if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "0";
+        } else if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "1";
+        } else if (Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "2";
+        }
+        return "3";
+    }
+
+    /**
+     * Dummy api using system server API.
+     */
+    public static String dummySystemServer(Context context) {
+        IPlatformCompat platformCompat = IPlatformCompat.Stub
+                .asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+        if (platformCompat == null) {
+            throw new RuntimeException("Could not obtain IPlatformCompat instance!");
+        }
+        String packageName = context.getPackageName();
+        try {
+            if (platformCompat.isChangeEnabledByPackageName(CHANGE_SYSTEM_SERVER, packageName,
+                                                            context.getUserId())) {
+                return "True";
+            } else {
+                return "False";
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Could not get change value!", e);
+        }
+    }
+}
diff --git a/tests/Gating/src/com/android/tests/gating/GatingTest.java b/tests/Gating/src/com/android/tests/gating/GatingTest.java
new file mode 100644
index 0000000..1e3f9ed
--- /dev/null
+++ b/tests/Gating/src/com/android/tests/gating/GatingTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.gating;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.compat.testing.CompatChangeRule;
+import android.compat.testing.CompatChangeRule.DisableCompatChanges;
+import android.compat.testing.CompatChangeRule.EnableCompatChanges;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compat.testing.DummyApi;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for platform compatibility change gating.
+ */
+@RunWith(AndroidJUnit4.class)
+public class GatingTest {
+
+    @Rule
+    public TestRule compatChangeRule = new CompatChangeRule();
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingPositive() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("A");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingNegative() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("B");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined0() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("0");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1})
+    @EnableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined1() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("1");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1})
+    @DisableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined2() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("2");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined3() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("3");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+    public void testDummyGatingPositiveSystemServer() {
+        assertThat(
+                DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isEqualTo(
+                "True");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_SYSTEM_SERVER})
+    public void testDummyGatingNegativeSystemServer() {
+        assertThat(
+                DummyApi.dummySystemServer(InstrumentationRegistry.getTargetContext())).isEqualTo(
+                "False");
+    }
+}
diff --git a/tools/apilint/apilint b/tools/apilint/apilint
deleted file mode 100755
index e42857f..0000000
--- a/tools/apilint/apilint
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2019 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.
-
-if [ "$1" == "--help" -o "$1" == "-h" ]; then
-echo "Usage: apilint [FILTERS...]"
-echo "  Shows lint from currently open files (as diffed from HEAD), i.e. errors"
-echo "  you will receive if you upload this CL."
-echo
-echo "Usage: apilint --all [FILTERS...]"
-echo "  Shows all lint errors present in the current working directory, regardless"
-echo "  of when they were added."
-echo
-echo "Usage: apilint --level API_LEVEL [FILTERS...]"
-echo "  Shows lint as it stands in API_LEVEL"
-echo
-echo "Usage: apilint --shal SHA [FILTERS...]"
-echo "  Shows lint from locally commited git change SHA."
-echo
-echo "Usage: apilint --unreleased [FILTERS...]"
-echo "  Shows all lint errors in the current working directory directory added since"
-echo "  the last released SDK version."
-echo
-echo "FILTERS"
-echo "  List of class or package names by which to filter the results."
-echo
-exit
-fi
-
-if [ \( -z "$ANDROID_BUILD_TOP" \) \
-           -a \( ! -f frameworks/base/api/current.txt \) \
-           -a \( ! -f frameworks/base/api/system-current.txt \) \
-        ]; then
-    echo "apilint must be run either with ANDROID_BUILD_TOP set or from the" 1>&2
-    echo "root of the android source tree" 1>&2
-    exit 1
-fi
-
-if [ ${ANDROID_BUILD_TOP:0:1} != "/" ]; then
-    echo "ANDROID_BUILD_TOP must be an absolute path, not: $ANDROID_BUILD_TOP" 1>&2
-    exit 1
-fi
-
-if [ -z "$ANDROID_BUILD_TOP" ]; then
-    ANDROID_BUILD_TOP=$(pwd)
-fi
-
-FW_BASE=$ANDROID_BUILD_TOP/frameworks/base
-
-MODE=open
-
-OPTIONS=$(getopt -n apilint -o "" -l "all,sha:,unreleased" -- "$@")
-
-[ $? -eq 0 ] || { 
-    exit 1
-}
-
-eval set -- "$OPTIONS"
-while true; do
-    case "$1" in
-    --all)
-        MODE=all
-        ;;
-    --sha)
-        shift; # The arg is next in position args
-        MODE=sha
-        SHA=$1
-        ;;
-    --unreleased)
-        MODE=unreleased
-        ;;
-    --)
-        shift
-        break
-        ;;
-    esac
-    shift
-done
-FILTERS=
-for var in "$@"
-do
-    FILTERS="$FILTERS --filter $var"
-done
-
-if [ $MODE = "all" ]; then
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SDK" \
-            $FILTERS \
-            $ANDROID_BUILD_TOP/frameworks/base/api/current.txt
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SystemApi" \
-            $FILTERS \
-            --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \
-            $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt
-elif [ $MODE = "open" ]; then
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SDK" \
-            $FILTERS \
-            $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \
-            <(cd $FW_BASE ; git show HEAD:api/current.txt)
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SystemApi" \
-            $FILTERS \
-            --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \
-            --base-previous <(cd $FW_BASE ; git show HEAD:api/current.txt) \
-            $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt \
-            <(cd $FW_BASE ; git show HEAD:api/system-current.txt)
-elif [ $MODE = "sha" ]; then
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SDK" \
-            $FILTERS \
-            <(cd $FW_BASE ; git show $SHA:api/current.txt) \
-            <(cd $FW_BASE ; git show $SHA^:api/current.txt)
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SystemApi" \
-            $FILTERS \
-            --base-current <(cd $FW_BASE ; git show $SHA:api/current.txt) \
-            --base-previous <(cd $FW_BASE ; git show $SHA^:api/current.txt) \
-            <(cd $FW_BASE ; git show $SHA:api/system-current.txt) \
-            <(cd $FW_BASE ; git show $SHA^:api/system-current.txt)
-elif [ $MODE = "unreleased" ]; then
-    LAST_SDK=$(ls $ANDROID_BUILD_TOP/prebuilts/sdk | grep "^[0-9][0-9]*$" | sort -n | tail -n 1)
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SDK" \
-            $FILTERS \
-            $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \
-            $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/public/api/android.txt
-    python2.7 -B $ANDROID_BUILD_TOP/frameworks/base/tools/apilint/apilint.py \
-            --title "SystemApi" \
-            $FILTERS \
-            --base-current $ANDROID_BUILD_TOP/frameworks/base/api/current.txt \
-            --base-previous $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/public/api/android.txt \
-            $ANDROID_BUILD_TOP/frameworks/base/api/system-current.txt \
-            $ANDROID_BUILD_TOP/prebuilts/sdk/$LAST_SDK/system/api/android.txt
-fi
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
deleted file mode 100644
index 912c1ad..0000000
--- a/tools/apilint/apilint.py
+++ /dev/null
@@ -1,2353 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2014 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.
-
-"""
-Enforces common Android public API design patterns.  It ignores lint messages from
-a previous API level, if provided.
-
-Usage: apilint.py current.txt
-Usage: apilint.py current.txt previous.txt
-
-You can also splice in blame details like this:
-$ git blame api/current.txt -t -e > /tmp/currentblame.txt
-$ apilint.py /tmp/currentblame.txt previous.txt --no-color
-"""
-
-import re, sys, collections, traceback, argparse, itertools
-
-
-BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
-
-ALLOW_GOOGLE = False
-USE_COLOR = True
-
-def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
-    # manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes
-    if not USE_COLOR: return ""
-    codes = []
-    if reset: codes.append("0")
-    else:
-        if not fg is None: codes.append("3%d" % (fg))
-        if not bg is None:
-            if not bright: codes.append("4%d" % (bg))
-            else: codes.append("10%d" % (bg))
-        if bold: codes.append("1")
-        elif dim: codes.append("2")
-        else: codes.append("22")
-    return "\033[%sm" % (";".join(codes))
-
-
-class Field():
-    def __init__(self, clazz, line, raw, blame, sig_format = 1):
-        self.clazz = clazz
-        self.line = line
-        self.raw = raw.strip(" {;")
-        self.blame = blame
-
-        if sig_format == 2:
-            V2LineParser(raw).parse_into_field(self)
-        elif sig_format == 1:
-            # drop generics for now; may need multiple passes
-            raw = re.sub("<[^<]+?>", "", raw)
-            raw = re.sub("<[^<]+?>", "", raw)
-
-            raw = raw.split()
-            self.split = list(raw)
-
-            for r in ["field", "volatile", "transient", "public", "protected", "static", "final", "deprecated"]:
-                while r in raw: raw.remove(r)
-
-            # ignore annotations for now
-            raw = [ r for r in raw if not r.startswith("@") ]
-
-            self.typ = raw[0]
-            self.name = raw[1].strip(";")
-            if len(raw) >= 4 and raw[2] == "=":
-                self.value = raw[3].strip(';"')
-            else:
-                self.value = None
-            self.annotations = []
-
-        self.ident = "-".join((self.typ, self.name, self.value or ""))
-
-    def __hash__(self):
-        return hash(self.raw)
-
-    def __repr__(self):
-        return self.raw
-
-
-class Argument(object):
-
-    __slots__ = ["type", "annotations", "name", "default"]
-
-    def __init__(self, type):
-        self.type = type
-        self.annotations = []
-        self.name = None
-        self.default = None
-
-
-class Method():
-    def __init__(self, clazz, line, raw, blame, sig_format = 1):
-        self.clazz = clazz
-        self.line = line
-        self.raw = raw.strip(" {;")
-        self.blame = blame
-
-        if sig_format == 2:
-            V2LineParser(raw).parse_into_method(self)
-        elif sig_format == 1:
-            # drop generics for now; may need multiple passes
-            raw = re.sub("<[^<]+?>", "", raw)
-            raw = re.sub("<[^<]+?>", "", raw)
-
-            # handle each clause differently
-            raw_prefix, raw_args, _, raw_throws = re.match(r"(.*?)\((.*?)\)( throws )?(.*?);$", raw).groups()
-
-            # parse prefixes
-            raw = re.split("[\s]+", raw_prefix)
-            for r in ["", ";"]:
-                while r in raw: raw.remove(r)
-            self.split = list(raw)
-
-            for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default", "operator", "synchronized"]:
-                while r in raw: raw.remove(r)
-
-            self.typ = raw[0]
-            self.name = raw[1]
-
-            # parse args
-            self.detailed_args = []
-            for arg in re.split(",\s*", raw_args):
-                arg = re.split("\s", arg)
-                # ignore annotations for now
-                arg = [ a for a in arg if not a.startswith("@") ]
-                if len(arg[0]) > 0:
-                    self.detailed_args.append(Argument(arg[0]))
-
-            # parse throws
-            self.throws = []
-            for throw in re.split(",\s*", raw_throws):
-                self.throws.append(throw)
-
-            self.annotations = []
-        else:
-            raise ValueError("Unknown signature format: " + sig_format)
-
-        self.args = map(lambda a: a.type, self.detailed_args)
-        self.ident = "-".join((self.typ, self.name, "-".join(self.args)))
-
-    def sig_matches(self, typ, name, args):
-        return typ == self.typ and name == self.name and args == self.args
-
-    def __hash__(self):
-        return hash(self.raw)
-
-    def __repr__(self):
-        return self.raw
-
-
-class Class():
-    def __init__(self, pkg, line, raw, blame, sig_format = 1):
-        self.pkg = pkg
-        self.line = line
-        self.raw = raw.strip(" {;")
-        self.blame = blame
-        self.ctors = []
-        self.fields = []
-        self.methods = []
-        self.annotations = []
-
-        if sig_format == 2:
-            V2LineParser(raw).parse_into_class(self)
-        elif sig_format == 1:
-            # drop generics for now; may need multiple passes
-            raw = re.sub("<[^<]+?>", "", raw)
-            raw = re.sub("<[^<]+?>", "", raw)
-
-            raw = raw.split()
-            self.split = list(raw)
-            if "class" in raw:
-                self.fullname = raw[raw.index("class")+1]
-            elif "interface" in raw:
-                self.fullname = raw[raw.index("interface")+1]
-            elif "@interface" in raw:
-                self.fullname = raw[raw.index("@interface")+1]
-            else:
-                raise ValueError("Funky class type %s" % (self.raw))
-
-            if "extends" in raw:
-                self.extends = raw[raw.index("extends")+1]
-            else:
-                self.extends = None
-
-            if "implements" in raw:
-                self.implements = raw[raw.index("implements")+1]
-                self.implements_all = [self.implements]
-            else:
-                self.implements = None
-                self.implements_all = []
-        else:
-            raise ValueError("Unknown signature format: " + sig_format)
-
-        self.fullname = self.pkg.name + "." + self.fullname
-        self.fullname_path = self.fullname.split(".")
-
-        if self.extends is not None:
-            self.extends_path = self.extends.split(".")
-        else:
-            self.extends_path = []
-
-        self.name = self.fullname[self.fullname.rindex(".")+1:]
-
-    def merge_from(self, other):
-        self.ctors.extend(other.ctors)
-        self.fields.extend(other.fields)
-        self.methods.extend(other.methods)
-
-    def __hash__(self):
-        return hash((self.raw, tuple(self.ctors), tuple(self.fields), tuple(self.methods)))
-
-    def __repr__(self):
-        return self.raw
-
-
-class Package():
-    NAME = re.compile("package(?: .*)? ([A-Za-z0-9.]+)")
-
-    def __init__(self, line, raw, blame):
-        self.line = line
-        self.raw = raw.strip(" {;")
-        self.blame = blame
-
-        self.name = Package.NAME.match(raw).group(1)
-        self.name_path = self.name.split(".")
-
-    def __repr__(self):
-        return self.raw
-
-class V2Tokenizer(object):
-    __slots__ = ["raw"]
-
-    SIGNATURE_PREFIX = "// Signature format: "
-    DELIMITER = re.compile(r'\s+|[()@<>;,={}/"!?]|\[\]|\.\.\.')
-    STRING_SPECIAL = re.compile(r'["\\]')
-
-    def __init__(self, raw):
-        self.raw = raw
-
-    def tokenize(self):
-        tokens = []
-        current = 0
-        raw = self.raw
-        length = len(raw)
-
-        while current < length:
-            while current < length:
-                start = current
-                match = V2Tokenizer.DELIMITER.search(raw, start)
-                if match is not None:
-                    match_start = match.start()
-                    if match_start == current:
-                        end = match.end()
-                    else:
-                        end = match_start
-                else:
-                    end = length
-
-                token = raw[start:end]
-                current = end
-
-                if token == "" or token[0] == " ":
-                    continue
-                else:
-                    break
-
-            if token == "@":
-                if raw[start:start+11] == "@interface ":
-                    current = start + 11
-                    tokens.append("@interface")
-                    continue
-            elif token == '/':
-                if raw[start:start+2] == "//":
-                    current = length
-                    continue
-            elif token == '"':
-                current, string_token = self.tokenize_string(raw, length, current)
-                tokens.append(token + string_token)
-                continue
-
-            tokens.append(token)
-
-        return tokens
-
-    def tokenize_string(self, raw, length, current):
-        start = current
-        end = length
-        while start < end:
-            match = V2Tokenizer.STRING_SPECIAL.search(raw, start)
-            if match:
-                if match.group() == '"':
-                    end = match.end()
-                    break
-                elif match.group() == '\\':
-                    # ignore whatever is after the slash
-                    start += 2
-                else:
-                    raise ValueError("Unexpected match: `%s`" % (match.group()))
-            else:
-                raise ValueError("Unexpected EOF tokenizing string: `%s`" % (raw[current - 1:],))
-
-        token = raw[current:end]
-        return end, token
-
-class V2LineParser(object):
-    __slots__ = ["tokenized", "current", "len"]
-
-    FIELD_KINDS = ("field", "property", "enum_constant")
-    MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized native operator sealed strictfp infix inline suspend vararg".split())
-    JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split())
-
-    def __init__(self, raw):
-        self.tokenized = V2Tokenizer(raw).tokenize()
-        self.current = 0
-        self.len = len(self.tokenized)
-
-    def parse_into_method(self, method):
-        method.split = []
-        kind = self.parse_one_of("ctor", "method")
-        method.split.append(kind)
-        method.annotations = self.parse_annotations()
-        method.split.extend(self.parse_modifiers())
-        self.parse_matching_paren("<", ">")
-        if "@Deprecated" in method.annotations:
-            method.split.append("deprecated")
-        if kind == "ctor":
-            method.typ = "ctor"
-        else:
-            method.typ = self.parse_type()
-            method.split.append(method.typ)
-        method.name = self.parse_name()
-        method.split.append(method.name)
-        self.parse_token("(")
-        method.detailed_args = self.parse_args()
-        self.parse_token(")")
-        method.throws = self.parse_throws()
-        if "@interface" in method.clazz.split:
-            self.parse_annotation_default()
-        self.parse_token(";")
-        self.parse_eof()
-
-    def parse_into_class(self, clazz):
-        clazz.split = []
-        clazz.annotations = self.parse_annotations()
-        if "@Deprecated" in clazz.annotations:
-            clazz.split.append("deprecated")
-        clazz.split.extend(self.parse_modifiers())
-        kind = self.parse_one_of("class", "interface", "@interface", "enum")
-        if kind == "enum":
-            # enums are implicitly final
-            clazz.split.append("final")
-        clazz.split.append(kind)
-        clazz.fullname = self.parse_name()
-        self.parse_matching_paren("<", ">")
-        extends = self.parse_extends()
-        clazz.extends = extends[0] if extends else None
-        clazz.implements_all = self.parse_implements()
-        # The checks assume that interfaces are always found in implements, which isn't true for
-        # subinterfaces.
-        if not clazz.implements_all and "interface" in clazz.split:
-            clazz.implements_all = [clazz.extends]
-        clazz.implements = clazz.implements_all[0] if clazz.implements_all else None
-        self.parse_token("{")
-        self.parse_eof()
-
-    def parse_into_field(self, field):
-        kind = self.parse_one_of(*V2LineParser.FIELD_KINDS)
-        field.split = [kind]
-        field.annotations = self.parse_annotations()
-        if "@Deprecated" in field.annotations:
-            field.split.append("deprecated")
-        field.split.extend(self.parse_modifiers())
-        field.typ = self.parse_type()
-        field.split.append(field.typ)
-        field.name = self.parse_name()
-        field.split.append(field.name)
-        if self.parse_if("="):
-            field.value = self.parse_value_stripped()
-        else:
-            field.value = None
-
-        self.parse_token(";")
-        self.parse_eof()
-
-    def lookahead(self):
-        return self.tokenized[self.current]
-
-    def parse_one_of(self, *options):
-        found = self.lookahead()
-        if found not in options:
-            raise ValueError("Parsing failed, expected one of `%s` but found `%s` in %s" % (options, found, repr(self.tokenized)))
-        return self.parse_token()
-
-    def parse_token(self, tok = None):
-        found = self.lookahead()
-        if tok is not None and found != tok:
-            raise ValueError("Parsing failed, expected `%s` but found `%s` in %s" % (tok, found, repr(self.tokenized)))
-        self.current += 1
-        return found
-
-    def eof(self):
-        return self.current == self.len
-
-    def parse_eof(self):
-        if not self.eof():
-            raise ValueError("Parsing failed, expected EOF, but %s has not been parsed in %s" % (self.tokenized[self.current:], self.tokenized))
-
-    def parse_if(self, tok):
-        if not self.eof() and self.lookahead() == tok:
-            self.parse_token()
-            return True
-        return False
-
-    def parse_annotations(self):
-        ret = []
-        while self.lookahead() == "@":
-            ret.append(self.parse_annotation())
-        return ret
-
-    def parse_annotation(self):
-        ret = self.parse_token("@") + self.parse_token()
-        self.parse_matching_paren("(", ")")
-        return ret
-
-    def parse_matching_paren(self, open, close):
-        start = self.current
-        if not self.parse_if(open):
-            return
-        length = len(self.tokenized)
-        count = 1
-        while count > 0:
-            if self.current == length:
-                raise ValueError("Unexpected EOF looking for closing paren: `%s`" % (self.tokenized[start:],))
-            t = self.parse_token()
-            if t == open:
-                count += 1
-            elif t == close:
-                count -= 1
-        return self.tokenized[start:self.current]
-
-    def parse_modifiers(self):
-        ret = []
-        while self.lookahead() in V2LineParser.MODIFIERS:
-            ret.append(self.parse_token())
-        return ret
-
-    def parse_kotlin_nullability(self):
-        t = self.lookahead()
-        if t == "?" or t == "!":
-            return self.parse_token()
-        return None
-
-    def parse_type(self):
-        self.parse_annotations()
-        type = self.parse_token()
-        if type[-1] == '.':
-            self.parse_annotations()
-            type += self.parse_token()
-        if type in V2LineParser.JAVA_LANG_TYPES:
-            type = "java.lang." + type
-        self.parse_matching_paren("<", ">")
-        while True:
-            t = self.lookahead()
-            if t == "@":
-                self.parse_annotation()
-            elif t == "[]":
-                type += self.parse_token()
-            elif self.parse_kotlin_nullability() is not None:
-                pass  # discard nullability for now
-            else:
-                break
-        return type
-
-    def parse_arg_type(self):
-        type = self.parse_type()
-        if self.parse_if("..."):
-            type += "..."
-        self.parse_kotlin_nullability() # discard nullability for now
-        return type
-
-    def parse_name(self):
-        return self.parse_token()
-
-    def parse_args(self):
-        args = []
-        if self.lookahead() == ")":
-            return args
-
-        while True:
-            args.append(self.parse_arg())
-            if self.lookahead() == ")":
-                return args
-            self.parse_token(",")
-
-    def parse_arg(self):
-        self.parse_if("vararg")  # kotlin vararg
-        annotations = self.parse_annotations()
-        arg = Argument(self.parse_arg_type())
-        arg.annotations = annotations
-        l = self.lookahead()
-        if l != "," and l != ")":
-            if self.lookahead() != '=':
-                arg.name = self.parse_token()  # kotlin argument name
-            if self.parse_if('='): # kotlin default value
-                arg.default = self.parse_expression()
-        return arg
-
-    def parse_expression(self):
-        while not self.lookahead() in [')', ',', ';']:
-            (self.parse_matching_paren('(', ')') or
-            self.parse_matching_paren('{', '}') or
-            self.parse_token())
-
-    def parse_throws(self):
-        ret = []
-        if self.parse_if("throws"):
-            ret.append(self.parse_type())
-            while self.parse_if(","):
-                ret.append(self.parse_type())
-        return ret
-
-    def parse_extends(self):
-        if self.parse_if("extends"):
-            return self.parse_space_delimited_type_list()
-        return []
-
-    def parse_implements(self):
-        if self.parse_if("implements"):
-            return self.parse_space_delimited_type_list()
-        return []
-
-    def parse_space_delimited_type_list(self, terminals = ["implements", "{"]):
-        types = []
-        while True:
-            types.append(self.parse_type())
-            if self.lookahead() in terminals:
-                return types
-
-    def parse_annotation_default(self):
-        if self.parse_if("default"):
-            self.parse_expression()
-
-    def parse_value(self):
-        if self.lookahead() == "{":
-            return " ".join(self.parse_matching_paren("{", "}"))
-        elif self.lookahead() == "(":
-            return " ".join(self.parse_matching_paren("(", ")"))
-        else:
-            return self.parse_token()
-
-    def parse_value_stripped(self):
-        value = self.parse_value()
-        if value[0] == '"':
-            return value[1:-1]
-        return value
-
-
-def _parse_stream(f, clazz_cb=None, base_f=None, out_classes_with_base=None,
-                  in_classes_with_base=[]):
-    api = {}
-    in_classes_with_base = _retry_iterator(in_classes_with_base)
-
-    if base_f:
-        base_classes = _retry_iterator(_parse_stream_to_generator(base_f))
-    else:
-        base_classes = []
-
-    def handle_class(clazz):
-        if clazz_cb:
-            clazz_cb(clazz)
-        else: # In callback mode, don't keep track of the full API
-            api[clazz.fullname] = clazz
-
-    def handle_missed_classes_with_base(clazz):
-        for c in _yield_until_matching_class(in_classes_with_base, clazz):
-            base_class = _skip_to_matching_class(base_classes, c)
-            if base_class:
-                handle_class(base_class)
-
-    for clazz in _parse_stream_to_generator(f):
-        # Before looking at clazz, let's see if there's some classes that were not present, but
-        # may have an entry in the base stream.
-        handle_missed_classes_with_base(clazz)
-
-        base_class = _skip_to_matching_class(base_classes, clazz)
-        if base_class:
-            clazz.merge_from(base_class)
-            if out_classes_with_base is not None:
-                out_classes_with_base.append(clazz)
-        handle_class(clazz)
-
-    handle_missed_classes_with_base(None)
-
-    return api
-
-def _parse_stream_to_generator(f):
-    line = 0
-    pkg = None
-    clazz = None
-    blame = None
-    sig_format = 1
-
-    re_blame = re.compile(r"^(\^?[a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
-
-    field_prefixes = map(lambda kind: "    %s" % (kind,), V2LineParser.FIELD_KINDS)
-    def startsWithFieldPrefix(raw):
-        for prefix in field_prefixes:
-            if raw.startswith(prefix):
-                return True
-        return False
-
-    for raw in f:
-        line += 1
-        raw = raw.rstrip()
-        match = re_blame.match(raw)
-        if match is not None:
-            blame = match.groups()[0:2]
-            if blame[0].startswith("^"):  # Outside of blame range
-              blame = None
-            raw = match.groups()[2]
-        else:
-            blame = None
-
-        if line == 1 and V2Tokenizer.SIGNATURE_PREFIX in raw:
-            sig_format_string = raw[len(V2Tokenizer.SIGNATURE_PREFIX):]
-            if sig_format_string in ["2.0", "3.0"]:
-                sig_format = 2
-            else:
-                raise ValueError("Unknown format: %s" % (sig_format_string,))
-        elif raw.startswith("package"):
-            pkg = Package(line, raw, blame)
-        elif raw.startswith("  ") and raw.endswith("{"):
-            clazz = Class(pkg, line, raw, blame, sig_format=sig_format)
-        elif raw.startswith("    ctor"):
-            clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format))
-        elif raw.startswith("    method"):
-            clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format))
-        elif startsWithFieldPrefix(raw):
-            clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format))
-        elif raw.startswith("  }") and clazz:
-            yield clazz
-
-def _retry_iterator(it):
-    """Wraps an iterator, such that calling send(True) on it will redeliver the same element"""
-    for e in it:
-        while True:
-            retry = yield e
-            if not retry:
-                break
-            # send() was called, asking us to redeliver clazz on next(). Still need to yield
-            # a dummy value to the send() first though.
-            if (yield "Returning clazz on next()"):
-                raise TypeError("send() must be followed by next(), not send()")
-
-def _skip_to_matching_class(classes, needle):
-    """Takes a classes iterator and consumes entries until it returns the class we're looking for
-
-    This relies on classes being sorted by package and class name."""
-
-    for clazz in classes:
-        if clazz.pkg.name < needle.pkg.name:
-            # We haven't reached the right package yet
-            continue
-        if clazz.pkg.name == needle.pkg.name and clazz.fullname < needle.fullname:
-            # We're in the right package, but not the right class yet
-            continue
-        if clazz.fullname == needle.fullname:
-            return clazz
-        # We ran past the right class. Send it back into the generator, then report failure.
-        classes.send(clazz)
-        return None
-
-def _yield_until_matching_class(classes, needle):
-    """Takes a class iterator and yields entries it until it reaches the class we're looking for.
-
-    This relies on classes being sorted by package and class name."""
-
-    for clazz in classes:
-        if needle is None:
-            yield clazz
-        elif clazz.pkg.name < needle.pkg.name:
-            # We haven't reached the right package yet
-            yield clazz
-        elif clazz.pkg.name == needle.pkg.name and clazz.fullname < needle.fullname:
-            # We're in the right package, but not the right class yet
-            yield clazz
-        elif clazz.fullname == needle.fullname:
-            # Class found, abort.
-            return
-        else:
-            # We ran past the right class. Send it back into the iterator, then abort.
-            classes.send(clazz)
-            return
-
-class Failure():
-    def __init__(self, sig, clazz, detail, error, rule, msg):
-        self.clazz = clazz
-        self.sig = sig
-        self.error = error
-        self.rule = rule
-        self.msg = msg
-
-        if error:
-            self.head = "Error %s" % (rule) if rule else "Error"
-            dump = "%s%s:%s %s" % (format(fg=RED, bg=BLACK, bold=True), self.head, format(reset=True), msg)
-        else:
-            self.head = "Warning %s" % (rule) if rule else "Warning"
-            dump = "%s%s:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), self.head, format(reset=True), msg)
-
-        self.line = clazz.line
-        blame = clazz.blame
-        if detail is not None:
-            dump += "\n    in " + repr(detail)
-            self.line = detail.line
-            blame = detail.blame
-        dump += "\n    in " + repr(clazz)
-        dump += "\n    in " + repr(clazz.pkg)
-        dump += "\n    at line " + repr(self.line)
-        if blame is not None:
-            dump += "\n    last modified by %s in %s" % (blame[1], blame[0])
-
-        self.dump = dump
-
-    def __repr__(self):
-        return self.dump
-
-
-failures = {}
-
-def _fail(clazz, detail, error, rule, msg):
-    """Records an API failure to be processed later."""
-    global failures
-
-    sig = "%s-%s-%s" % (clazz.fullname, detail.ident if detail else None, msg)
-    sig = sig.replace(" deprecated ", " ")
-
-    failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
-
-
-def warn(clazz, detail, rule, msg):
-    _fail(clazz, detail, False, rule, msg)
-
-def error(clazz, detail, rule, msg):
-    _fail(clazz, detail, True, rule, msg)
-
-
-noticed = {}
-
-def notice(clazz):
-    global noticed
-
-    noticed[clazz.fullname] = hash(clazz)
-
-
-verifiers = {}
-
-def verifier(f):
-    verifiers[f.__name__] = f
-    return f
-
-
-@verifier
-def verify_constants(clazz):
-    """All static final constants must be FOO_NAME style."""
-    if re.match("android\.R\.[a-z]+", clazz.fullname): return
-    if clazz.fullname.startswith("android.os.Build"): return
-    if clazz.fullname == "android.system.OsConstants": return
-
-    req = ["java.lang.String","byte","short","int","long","float","double","boolean","char"]
-    for f in clazz.fields:
-        if "static" in f.split and "final" in f.split:
-            if re.match("[A-Z0-9_]+", f.name) is None:
-                error(clazz, f, "C2", "Constant field names must be FOO_NAME")
-            if f.typ != "java.lang.String":
-                if f.name.startswith("MIN_") or f.name.startswith("MAX_"):
-                    warn(clazz, f, "C8", "If min/max could change in future, make them dynamic methods")
-            if f.typ in req and f.value is None:
-                error(clazz, f, None, "All constants must be defined at compile time")
-
-@verifier
-def verify_enums(clazz):
-    """Enums are bad, mmkay?"""
-    if clazz.extends == "java.lang.Enum" or "enum" in clazz.split:
-        error(clazz, None, "F5", "Enums are not allowed")
-
-@verifier
-def verify_class_names(clazz):
-    """Try catching malformed class names like myMtp or MTPUser."""
-    if clazz.fullname.startswith("android.opengl"): return
-    if clazz.fullname.startswith("android.renderscript"): return
-    if re.match("android\.R\.[a-z]+", clazz.fullname): return
-
-    if re.search("[A-Z]{2,}", clazz.name) is not None:
-        warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
-    if re.match("[^A-Z]", clazz.name):
-        error(clazz, None, "S1", "Class must start with uppercase char")
-    if clazz.name.endswith("Impl"):
-        error(clazz, None, None, "Don't expose your implementation details")
-
-
-@verifier
-def verify_method_names(clazz):
-    """Try catching malformed method names, like Foo() or getMTU()."""
-    if clazz.fullname.startswith("android.opengl"): return
-    if clazz.fullname.startswith("android.renderscript"): return
-    if clazz.fullname == "android.system.OsConstants": return
-
-    for m in clazz.methods:
-        if re.search("[A-Z]{2,}", m.name) is not None:
-            warn(clazz, m, "S1", "Method names with acronyms should be getMtu() instead of getMTU()")
-        if re.match("[^a-z]", m.name):
-            error(clazz, m, "S1", "Method name must start with lowercase char")
-
-
-@verifier
-def verify_callbacks(clazz):
-    """Verify Callback classes.
-    All methods must follow onFoo() naming style."""
-    if clazz.fullname == "android.speech.tts.SynthesisCallback": return
-
-    if clazz.name.endswith("Callbacks"):
-        error(clazz, None, "L1", "Callback class names should be singular")
-    if clazz.name.endswith("Observer"):
-        warn(clazz, None, "L1", "Class should be named FooCallback")
-
-    if clazz.name.endswith("Callback"):
-        for m in clazz.methods:
-            if not re.match("on[A-Z][a-z]*", m.name):
-                error(clazz, m, "L1", "Callback method names must be onFoo() style")
-
-
-@verifier
-def verify_listeners(clazz):
-    """Verify Listener classes.
-    All Listener classes must be interface.
-    All methods must follow onFoo() naming style.
-    If only a single method, it must match class name:
-        interface OnFooListener { void onFoo() }"""
-
-    if clazz.name.endswith("Listener"):
-        if "abstract" in clazz.split and "class" in clazz.split:
-            error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
-
-        for m in clazz.methods:
-            if not re.match("on[A-Z][a-z]*", m.name):
-                error(clazz, m, "L1", "Listener method names must be onFoo() style")
-
-        if len(clazz.methods) == 1 and clazz.name.startswith("On"):
-            m = clazz.methods[0]
-            if (m.name + "Listener").lower() != clazz.name.lower():
-                error(clazz, m, "L1", "Single listener method name must match class name")
-
-
-@verifier
-def verify_actions(clazz):
-    """Verify intent actions.
-    All action names must be named ACTION_FOO.
-    All action values must be scoped by package and match name:
-        package android.foo {
-            String ACTION_BAR = "android.foo.action.BAR";
-        }"""
-    for f in clazz.fields:
-        if f.value is None: continue
-        if f.name.startswith("EXTRA_"): continue
-        if f.name == "SERVICE_INTERFACE" or f.name == "PROVIDER_INTERFACE": continue
-        if "INTERACTION" in f.name: continue
-
-        if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
-            if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower():
-                if not f.name.startswith("ACTION_"):
-                    error(clazz, f, "C3", "Intent action constant name must be ACTION_FOO")
-                else:
-                    if clazz.fullname == "android.content.Intent":
-                        prefix = "android.intent.action"
-                    elif clazz.fullname == "android.provider.Settings":
-                        prefix = "android.settings"
-                    elif clazz.fullname == "android.app.admin.DevicePolicyManager" or clazz.fullname == "android.app.admin.DeviceAdminReceiver":
-                        prefix = "android.app.action"
-                    else:
-                        prefix = clazz.pkg.name + ".action"
-                    expected = prefix + "." + f.name[7:]
-                    if f.value != expected:
-                        error(clazz, f, "C4", "Inconsistent action value; expected '%s'" % (expected))
-
-
-@verifier
-def verify_extras(clazz):
-    """Verify intent extras.
-    All extra names must be named EXTRA_FOO.
-    All extra values must be scoped by package and match name:
-        package android.foo {
-            String EXTRA_BAR = "android.foo.extra.BAR";
-        }"""
-    if clazz.fullname == "android.app.Notification": return
-    if clazz.fullname == "android.appwidget.AppWidgetManager": return
-
-    for f in clazz.fields:
-        if f.value is None: continue
-        if f.name.startswith("ACTION_"): continue
-
-        if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
-            if "_EXTRA" in f.name or "EXTRA_" in f.name or ".extra" in f.value.lower():
-                if not f.name.startswith("EXTRA_"):
-                    error(clazz, f, "C3", "Intent extra must be EXTRA_FOO")
-                else:
-                    if clazz.pkg.name == "android.content" and clazz.name == "Intent":
-                        prefix = "android.intent.extra"
-                    elif clazz.pkg.name == "android.app.admin":
-                        prefix = "android.app.extra"
-                    else:
-                        prefix = clazz.pkg.name + ".extra"
-                    expected = prefix + "." + f.name[6:]
-                    if f.value != expected:
-                        error(clazz, f, "C4", "Inconsistent extra value; expected '%s'" % (expected))
-
-
-@verifier
-def verify_equals(clazz):
-    """Verify that equals() and hashCode() must be overridden together."""
-    eq = False
-    hc = False
-    for m in clazz.methods:
-        if "static" in m.split: continue
-        if m.sig_matches("boolean", "equals", ["java.lang.Object"]): eq = True
-        if m.sig_matches("int", "hashCode", []): hc = True
-    if eq != hc:
-        error(clazz, None, "M8", "Must override both equals and hashCode; missing one")
-
-
-@verifier
-def verify_parcelable(clazz):
-    """Verify that Parcelable objects aren't hiding required bits."""
-    if clazz.implements == "android.os.Parcelable":
-        creator = [ i for i in clazz.fields if i.name == "CREATOR" ]
-        write = [ i for i in clazz.methods if i.name == "writeToParcel" ]
-        describe = [ i for i in clazz.methods if i.name == "describeContents" ]
-
-        if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
-            error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
-
-        if "final" not in clazz.split:
-            error(clazz, None, "FW8", "Parcelable classes must be final")
-
-        for c in clazz.ctors:
-            if c.args == ["android.os.Parcel"]:
-                error(clazz, c, "FW3", "Parcelable inflation is exposed through CREATOR, not raw constructors")
-
-
-@verifier
-def verify_protected(clazz):
-    """Verify that no protected methods or fields are allowed."""
-    for m in clazz.methods:
-        if m.name == "finalize": continue
-        if "protected" in m.split:
-            error(clazz, m, "M7", "Protected methods not allowed; must be public")
-    for f in clazz.fields:
-        if "protected" in f.split:
-            error(clazz, f, "M7", "Protected fields not allowed; must be public")
-
-
-@verifier
-def verify_fields(clazz):
-    """Verify that all exposed fields are final.
-    Exposed fields must follow myName style.
-    Catch internal mFoo objects being exposed."""
-
-    IGNORE_BARE_FIELDS = [
-        "android.app.ActivityManager.RecentTaskInfo",
-        "android.app.Notification",
-        "android.content.pm.ActivityInfo",
-        "android.content.pm.ApplicationInfo",
-        "android.content.pm.ComponentInfo",
-        "android.content.pm.ResolveInfo",
-        "android.content.pm.FeatureGroupInfo",
-        "android.content.pm.InstrumentationInfo",
-        "android.content.pm.PackageInfo",
-        "android.content.pm.PackageItemInfo",
-        "android.content.res.Configuration",
-        "android.graphics.BitmapFactory.Options",
-        "android.os.Message",
-        "android.system.StructPollfd",
-    ]
-
-    for f in clazz.fields:
-        if not "final" in f.split:
-            if clazz.fullname in IGNORE_BARE_FIELDS:
-                pass
-            elif clazz.fullname.endswith("LayoutParams"):
-                pass
-            elif clazz.fullname.startswith("android.util.Mutable"):
-                pass
-            else:
-                error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
-
-        if "static" not in f.split and "property" not in f.split:
-            if not re.match("[a-z]([a-zA-Z]+)?", f.name):
-                error(clazz, f, "S1", "Non-static fields must be named using myField style")
-
-        if re.match("[ms][A-Z]", f.name):
-            error(clazz, f, "F1", "Internal objects must not be exposed")
-
-        if re.match("[A-Z_]+", f.name):
-            if "static" not in f.split or "final" not in f.split:
-                error(clazz, f, "C2", "Constants must be marked static final")
-
-
-@verifier
-def verify_register(clazz):
-    """Verify parity of registration methods.
-    Callback objects use register/unregister methods.
-    Listener objects use add/remove methods."""
-    methods = [ m.name for m in clazz.methods ]
-    for m in clazz.methods:
-        if "Callback" in m.raw:
-            if m.name.startswith("register"):
-                other = "unregister" + m.name[8:]
-                if other not in methods:
-                    error(clazz, m, "L2", "Missing unregister method")
-            if m.name.startswith("unregister"):
-                other = "register" + m.name[10:]
-                if other not in methods:
-                    error(clazz, m, "L2", "Missing register method")
-
-            if m.name.startswith("add") or m.name.startswith("remove"):
-                error(clazz, m, "L3", "Callback methods should be named register/unregister")
-
-        if "Listener" in m.raw:
-            if m.name.startswith("add"):
-                other = "remove" + m.name[3:]
-                if other not in methods:
-                    error(clazz, m, "L2", "Missing remove method")
-            if m.name.startswith("remove") and not m.name.startswith("removeAll"):
-                other = "add" + m.name[6:]
-                if other not in methods:
-                    error(clazz, m, "L2", "Missing add method")
-
-            if m.name.startswith("register") or m.name.startswith("unregister"):
-                error(clazz, m, "L3", "Listener methods should be named add/remove")
-
-
-@verifier
-def verify_sync(clazz):
-    """Verify synchronized methods aren't exposed."""
-    for m in clazz.methods:
-        if "synchronized" in m.split:
-            error(clazz, m, "M5", "Internal locks must not be exposed")
-
-
-@verifier
-def verify_intent_builder(clazz):
-    """Verify that Intent builders are createFooIntent() style."""
-    if clazz.name == "Intent": return
-
-    for m in clazz.methods:
-        if m.typ == "android.content.Intent":
-            if m.name.startswith("create") and m.name.endswith("Intent"):
-                pass
-            else:
-                warn(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")
-
-
-@verifier
-def verify_helper_classes(clazz):
-    """Verify that helper classes are named consistently with what they extend.
-    All developer extendable methods should be named onFoo()."""
-    test_methods = False
-    if clazz.extends == "android.app.Service":
-        test_methods = True
-        if not clazz.name.endswith("Service"):
-            error(clazz, None, "CL4", "Inconsistent class name; should be FooService")
-
-        found = False
-        for f in clazz.fields:
-            if f.name == "SERVICE_INTERFACE":
-                found = True
-                if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
-
-    if clazz.extends == "android.content.ContentProvider":
-        test_methods = True
-        if not clazz.name.endswith("Provider"):
-            error(clazz, None, "CL4", "Inconsistent class name; should be FooProvider")
-
-        found = False
-        for f in clazz.fields:
-            if f.name == "PROVIDER_INTERFACE":
-                found = True
-                if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface constant; expected '%s'" % (clazz.fullname))
-
-    if clazz.extends == "android.content.BroadcastReceiver":
-        test_methods = True
-        if not clazz.name.endswith("Receiver"):
-            error(clazz, None, "CL4", "Inconsistent class name; should be FooReceiver")
-
-    if clazz.extends == "android.app.Activity":
-        test_methods = True
-        if not clazz.name.endswith("Activity"):
-            error(clazz, None, "CL4", "Inconsistent class name; should be FooActivity")
-
-    if test_methods:
-        for m in clazz.methods:
-            if "final" in m.split: continue
-            if not re.match("on[A-Z]", m.name):
-                if "abstract" in m.split:
-                    warn(clazz, m, None, "Methods implemented by developers should be named onFoo()")
-                else:
-                    warn(clazz, m, None, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
-
-
-@verifier
-def verify_builder(clazz):
-    """Verify builder classes.
-    Methods should return the builder to enable chaining."""
-    if clazz.extends: return
-    if not clazz.name.endswith("Builder"): return
-
-    if clazz.name != "Builder":
-        warn(clazz, None, None, "Builder should be defined as inner class")
-
-    has_build = False
-    for m in clazz.methods:
-        if m.name == "build":
-            has_build = True
-            continue
-
-        if m.name.startswith("get"): continue
-        if m.name.startswith("clear"): continue
-
-        if m.name.startswith("with"):
-            warn(clazz, m, None, "Builder methods names should use setFoo() style")
-
-        if m.name.startswith("set"):
-            if not m.typ.endswith(clazz.fullname):
-                warn(clazz, m, "M4", "Methods must return the builder object")
-
-    if not has_build:
-        warn(clazz, None, None, "Missing build() method")
-
-    if "final" not in clazz.split:
-        error(clazz, None, None, "Builder should be final")
-
-
-@verifier
-def verify_aidl(clazz):
-    """Catch people exposing raw AIDL."""
-    if clazz.extends == "android.os.Binder" or clazz.implements == "android.os.IInterface":
-        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
-
-
-@verifier
-def verify_internal(clazz):
-    """Catch people exposing internal classes."""
-    if clazz.pkg.name.startswith("com.android"):
-        error(clazz, None, None, "Internal classes must not be exposed")
-
-def layering_build_ranking(ranking_list):
-    r = {}
-    for rank, ps in enumerate(ranking_list):
-        if not isinstance(ps, list):
-            ps = [ps]
-        for p in ps:
-            rs = r
-            for n in p.split('.'):
-                if n not in rs:
-                    rs[n] = {}
-                rs = rs[n]
-            rs['-rank'] = rank
-    return r
-
-LAYERING_PACKAGE_RANKING = layering_build_ranking([
-    ["android.service","android.accessibilityservice","android.inputmethodservice","android.printservice","android.appwidget","android.webkit","android.preference","android.gesture","android.print"],
-    "android.app",
-    "android.widget",
-    "android.view",
-    "android.animation",
-    "android.provider",
-    ["android.content","android.graphics.drawable"],
-    "android.database",
-    "android.text",
-    "android.graphics",
-    "android.os",
-    "android.util"
-])
-
-@verifier
-def verify_layering(clazz):
-    """Catch package layering violations.
-    For example, something in android.os depending on android.app."""
-
-    def rank(p):
-        r = None
-        l = LAYERING_PACKAGE_RANKING
-        for n in p.split('.'):
-            if n in l:
-                l = l[n]
-                if '-rank' in l:
-                    r = l['-rank']
-            else:
-                break
-        return r
-
-    cr = rank(clazz.pkg.name)
-    if cr is None: return
-
-    for f in clazz.fields:
-        ir = rank(f.typ)
-        if ir is not None and ir < cr:
-            warn(clazz, f, "FW6", "Field type violates package layering")
-
-    for m in itertools.chain(clazz.methods, clazz.ctors):
-        ir = rank(m.typ)
-        if ir is not None and ir < cr:
-            warn(clazz, m, "FW6", "Method return type violates package layering")
-        for arg in m.args:
-            ir = rank(arg)
-            if ir is not None and ir < cr:
-                warn(clazz, m, "FW6", "Method argument type violates package layering")
-
-
-@verifier
-def verify_boolean(clazz):
-    """Verifies that boolean accessors are named correctly.
-    For example, hasFoo() and setHasFoo()."""
-
-    def is_get(m): return len(m.args) == 0 and m.typ == "boolean"
-    def is_set(m): return len(m.args) == 1 and m.args[0] == "boolean"
-
-    gets = [ m for m in clazz.methods if is_get(m) ]
-    sets = [ m for m in clazz.methods if is_set(m) ]
-
-    def error_if_exists(methods, trigger, expected, actual):
-        for m in methods:
-            if m.name == actual:
-                error(clazz, m, "M6", "Symmetric method for %s must be named %s" % (trigger, expected))
-
-    for m in clazz.methods:
-        if is_get(m):
-            if re.match("is[A-Z]", m.name):
-                target = m.name[2:]
-                expected = "setIs" + target
-                error_if_exists(sets, m.name, expected, "setHas" + target)
-            elif re.match("has[A-Z]", m.name):
-                target = m.name[3:]
-                expected = "setHas" + target
-                error_if_exists(sets, m.name, expected, "setIs" + target)
-                error_if_exists(sets, m.name, expected, "set" + target)
-            elif re.match("get[A-Z]", m.name):
-                target = m.name[3:]
-                expected = "set" + target
-                error_if_exists(sets, m.name, expected, "setIs" + target)
-                error_if_exists(sets, m.name, expected, "setHas" + target)
-
-        if is_set(m):
-            if re.match("set[A-Z]", m.name):
-                target = m.name[3:]
-                expected = "get" + target
-                error_if_exists(sets, m.name, expected, "is" + target)
-                error_if_exists(sets, m.name, expected, "has" + target)
-
-
-@verifier
-def verify_collections(clazz):
-    """Verifies that collection types are interfaces."""
-    if clazz.fullname == "android.os.Bundle": return
-    if clazz.fullname == "android.os.Parcel": return
-
-    bad = ["java.util.Vector", "java.util.LinkedList", "java.util.ArrayList", "java.util.Stack",
-           "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
-    for m in clazz.methods:
-        if m.typ in bad:
-            error(clazz, m, "CL2", "Return type is concrete collection; must be higher-level interface")
-        for arg in m.args:
-            if arg in bad:
-                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
-
-
-@verifier
-def verify_uris(clazz):
-    bad = ["java.net.URL", "java.net.URI", "android.net.URL"]
-
-    for f in clazz.fields:
-        if f.typ in bad:
-            error(clazz, f, None, "Field must be android.net.Uri instead of " + f.typ)
-
-    for m in clazz.methods + clazz.ctors:
-        if m.typ in bad:
-            error(clazz, m, None, "Must return android.net.Uri instead of " + m.typ)
-        for arg in m.args:
-            if arg in bad:
-                error(clazz, m, None, "Argument must take android.net.Uri instead of " + arg)
-
-
-@verifier
-def verify_flags(clazz):
-    """Verifies that flags are non-overlapping."""
-    known = collections.defaultdict(int)
-    for f in clazz.fields:
-        if "FLAG_" in f.name:
-            try:
-                val = int(f.value)
-            except:
-                continue
-
-            scope = f.name[0:f.name.index("FLAG_")]
-            if val & known[scope]:
-                warn(clazz, f, "C1", "Found overlapping flag constant value")
-            known[scope] |= val
-
-
-@verifier
-def verify_exception(clazz):
-    """Verifies that methods don't throw generic exceptions."""
-    for m in clazz.methods:
-        for t in m.throws:
-            if t in ["java.lang.Exception", "java.lang.Throwable", "java.lang.Error"]:
-                error(clazz, m, "S1", "Methods must not throw generic exceptions")
-
-            if t in ["android.os.RemoteException"]:
-                if clazz.fullname == "android.content.ContentProviderClient": continue
-                if clazz.fullname == "android.os.Binder": continue
-                if clazz.fullname == "android.os.IBinder": continue
-
-                error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException")
-
-            if len(m.args) == 0 and t in ["java.lang.IllegalArgumentException", "java.lang.NullPointerException"]:
-                warn(clazz, m, "S1", "Methods taking no arguments should throw IllegalStateException")
-
-
-GOOGLE_IGNORECASE = re.compile("google", re.IGNORECASE)
-
-# Not marked as @verifier, because it is only conditionally applied.
-def verify_google(clazz):
-    """Verifies that APIs never reference Google."""
-
-    if GOOGLE_IGNORECASE.search(clazz.raw) is not None:
-        error(clazz, None, None, "Must never reference Google")
-
-    for test in clazz.ctors, clazz.fields, clazz.methods:
-        for t in test:
-            if GOOGLE_IGNORECASE.search(t.raw) is not None:
-                error(clazz, t, None, "Must never reference Google")
-
-
-@verifier
-def verify_bitset(clazz):
-    """Verifies that we avoid using heavy BitSet."""
-
-    for f in clazz.fields:
-        if f.typ == "java.util.BitSet":
-            error(clazz, f, None, "Field type must not be heavy BitSet")
-
-    for m in clazz.methods:
-        if m.typ == "java.util.BitSet":
-            error(clazz, m, None, "Return type must not be heavy BitSet")
-        for arg in m.args:
-            if arg == "java.util.BitSet":
-                error(clazz, m, None, "Argument type must not be heavy BitSet")
-
-
-@verifier
-def verify_manager(clazz):
-    """Verifies that FooManager is only obtained from Context."""
-
-    if not clazz.name.endswith("Manager"): return
-
-    for c in clazz.ctors:
-        error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
-
-    for m in clazz.methods:
-        if m.typ == clazz.fullname:
-            error(clazz, m, None, "Managers must always be obtained from Context")
-
-
-@verifier
-def verify_boxed(clazz):
-    """Verifies that methods avoid boxed primitives."""
-
-    boxed = ["java.lang.Number","java.lang.Byte","java.lang.Double","java.lang.Float","java.lang.Integer","java.lang.Long","java.lang.Short"]
-
-    for c in clazz.ctors:
-        for arg in c.args:
-            if arg in boxed:
-                error(clazz, c, "M11", "Must avoid boxed primitives")
-
-    for f in clazz.fields:
-        if f.typ in boxed:
-            error(clazz, f, "M11", "Must avoid boxed primitives")
-
-    for m in clazz.methods:
-        if m.typ in boxed:
-            error(clazz, m, "M11", "Must avoid boxed primitives")
-        for arg in m.args:
-            if arg in boxed:
-                error(clazz, m, "M11", "Must avoid boxed primitives")
-
-
-@verifier
-def verify_static_utils(clazz):
-    """Verifies that helper classes can't be constructed."""
-    if clazz.fullname.startswith("android.opengl"): return
-    if clazz.fullname.startswith("android.R"): return
-
-    # Only care about classes with default constructors
-    if len(clazz.ctors) == 1 and len(clazz.ctors[0].args) == 0:
-        test = []
-        test.extend(clazz.fields)
-        test.extend(clazz.methods)
-
-        if len(test) == 0: return
-        for t in test:
-            if "static" not in t.split:
-                return
-
-        error(clazz, None, None, "Fully-static utility classes must not have constructor")
-
-
-# @verifier  # Disabled for now
-def verify_overload_args(clazz):
-    """Verifies that method overloads add new arguments at the end."""
-    if clazz.fullname.startswith("android.opengl"): return
-
-    overloads = collections.defaultdict(list)
-    for m in clazz.methods:
-        if "deprecated" in m.split: continue
-        overloads[m.name].append(m)
-
-    for name, methods in overloads.items():
-        if len(methods) <= 1: continue
-
-        # Look for arguments common across all overloads
-        def cluster(args):
-            count = collections.defaultdict(int)
-            res = set()
-            for i in range(len(args)):
-                a = args[i]
-                res.add("%s#%d" % (a, count[a]))
-                count[a] += 1
-            return res
-
-        common_args = cluster(methods[0].args)
-        for m in methods:
-            common_args = common_args & cluster(m.args)
-
-        if len(common_args) == 0: continue
-
-        # Require that all common arguments are present at start of signature
-        locked_sig = None
-        for m in methods:
-            sig = m.args[0:len(common_args)]
-            if not common_args.issubset(cluster(sig)):
-                warn(clazz, m, "M2", "Expected common arguments [%s] at beginning of overloaded method" % (", ".join(common_args)))
-            elif not locked_sig:
-                locked_sig = sig
-            elif locked_sig != sig:
-                error(clazz, m, "M2", "Expected consistent argument ordering between overloads: %s..." % (", ".join(locked_sig)))
-
-
-@verifier
-def verify_callback_handlers(clazz):
-    """Verifies that methods adding listener/callback have overload
-    for specifying delivery thread."""
-
-    # Ignore UI packages which assume main thread
-    skip = [
-        "animation",
-        "view",
-        "graphics",
-        "transition",
-        "widget",
-        "webkit",
-    ]
-    for s in skip:
-        if s in clazz.pkg.name_path: return
-        if s in clazz.extends_path: return
-
-    # Ignore UI classes which assume main thread
-    if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
-        for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
-            if s in clazz.fullname: return
-    if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
-        for s in ["Loader"]:
-            if s in clazz.fullname: return
-
-    found = {}
-    by_name = collections.defaultdict(list)
-    examine = clazz.ctors + clazz.methods
-    for m in examine:
-        if m.name.startswith("unregister"): continue
-        if m.name.startswith("remove"): continue
-        if re.match("on[A-Z]+", m.name): continue
-
-        by_name[m.name].append(m)
-
-        for a in m.args:
-            if a.endswith("Listener") or a.endswith("Callback") or a.endswith("Callbacks"):
-                found[m.name] = m
-
-    for f in found.values():
-        takes_handler = False
-        takes_exec = False
-        for m in by_name[f.name]:
-            if "android.os.Handler" in m.args:
-                takes_handler = True
-            if "java.util.concurrent.Executor" in m.args:
-                takes_exec = True
-        if not takes_exec:
-            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Executor")
-
-
-@verifier
-def verify_context_first(clazz):
-    """Verifies that methods accepting a Context keep it the first argument."""
-    examine = clazz.ctors + clazz.methods
-    for m in examine:
-        if len(m.args) > 1 and m.args[0] != "android.content.Context":
-            if "android.content.Context" in m.args[1:]:
-                error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
-        if len(m.args) > 1 and m.args[0] != "android.content.ContentResolver":
-            if "android.content.ContentResolver" in m.args[1:]:
-                error(clazz, m, "M3", "ContentResolver is distinct, so it must be the first argument")
-
-
-@verifier
-def verify_listener_last(clazz):
-    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
-    examine = clazz.ctors + clazz.methods
-    for m in examine:
-        if "Listener" in m.name or "Callback" in m.name: continue
-        found = False
-        for a in m.args:
-            if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
-                found = True
-            elif found:
-                warn(clazz, m, "M3", "Listeners should always be at end of argument list")
-
-
-@verifier
-def verify_resource_names(clazz):
-    """Verifies that resource names have consistent case."""
-    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
-
-    # Resources defined by files are foo_bar_baz
-    if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
-        for f in clazz.fields:
-            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
-            if f.name.startswith("config_"):
-                error(clazz, f, None, "Expected config name to be config_fooBarBaz style")
-
-            if re.match("[a-z1-9_]+$", f.name): continue
-            error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
-
-    # Resources defined inside files are fooBarBaz
-    if clazz.name in ["array","attr","id","bool","fraction","integer"]:
-        for f in clazz.fields:
-            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
-            if re.match("layout_[a-z][a-zA-Z1-9]*$", f.name): continue
-            if re.match("state_[a-z_]*$", f.name): continue
-
-            if re.match("[a-z][a-zA-Z1-9]*$", f.name): continue
-            error(clazz, f, "C7", "Expected resource name in this class to be fooBarBaz style")
-
-    # Styles are FooBar_Baz
-    if clazz.name in ["style"]:
-        for f in clazz.fields:
-            if re.match("[A-Z][A-Za-z1-9]+(_[A-Z][A-Za-z1-9]+?)*$", f.name): continue
-            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
-
-
-@verifier
-def verify_files(clazz):
-    """Verifies that methods accepting File also accept streams."""
-
-    has_file = set()
-    has_stream = set()
-
-    test = []
-    test.extend(clazz.ctors)
-    test.extend(clazz.methods)
-
-    for m in test:
-        if "java.io.File" in m.args:
-            has_file.add(m)
-        if "java.io.FileDescriptor" in m.args or "android.os.ParcelFileDescriptor" in m.args or "java.io.InputStream" in m.args or "java.io.OutputStream" in m.args:
-            has_stream.add(m.name)
-
-    for m in has_file:
-        if m.name not in has_stream:
-            warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
-
-
-@verifier
-def verify_manager_list(clazz):
-    """Verifies that managers return List<? extends Parcelable> instead of arrays."""
-
-    if not clazz.name.endswith("Manager"): return
-
-    for m in clazz.methods:
-        if m.typ.startswith("android.") and m.typ.endswith("[]"):
-            warn(clazz, m, None, "Methods should return List<? extends Parcelable> instead of Parcelable[] to support ParceledListSlice under the hood")
-
-
-@verifier
-def verify_abstract_inner(clazz):
-    """Verifies that abstract inner classes are static."""
-
-    if re.match(".+?\.[A-Z][^\.]+\.[A-Z]", clazz.fullname):
-        if "abstract" in clazz.split and "static" not in clazz.split:
-            warn(clazz, None, None, "Abstract inner classes should be static to improve testability")
-
-
-@verifier
-def verify_runtime_exceptions(clazz):
-    """Verifies that runtime exceptions aren't listed in throws."""
-
-    banned = [
-        "java.lang.NullPointerException",
-        "java.lang.ClassCastException",
-        "java.lang.IndexOutOfBoundsException",
-        "java.lang.reflect.UndeclaredThrowableException",
-        "java.lang.reflect.MalformedParametersException",
-        "java.lang.reflect.MalformedParameterizedTypeException",
-        "java.lang.invoke.WrongMethodTypeException",
-        "java.lang.EnumConstantNotPresentException",
-        "java.lang.IllegalMonitorStateException",
-        "java.lang.SecurityException",
-        "java.lang.UnsupportedOperationException",
-        "java.lang.annotation.AnnotationTypeMismatchException",
-        "java.lang.annotation.IncompleteAnnotationException",
-        "java.lang.TypeNotPresentException",
-        "java.lang.IllegalStateException",
-        "java.lang.ArithmeticException",
-        "java.lang.IllegalArgumentException",
-        "java.lang.ArrayStoreException",
-        "java.lang.NegativeArraySizeException",
-        "java.util.MissingResourceException",
-        "java.util.EmptyStackException",
-        "java.util.concurrent.CompletionException",
-        "java.util.concurrent.RejectedExecutionException",
-        "java.util.IllformedLocaleException",
-        "java.util.ConcurrentModificationException",
-        "java.util.NoSuchElementException",
-        "java.io.UncheckedIOException",
-        "java.time.DateTimeException",
-        "java.security.ProviderException",
-        "java.nio.BufferUnderflowException",
-        "java.nio.BufferOverflowException",
-    ]
-
-    examine = clazz.ctors + clazz.methods
-    for m in examine:
-        for t in m.throws:
-            if t in banned:
-                error(clazz, m, None, "Methods must not mention RuntimeException subclasses in throws clauses")
-
-
-@verifier
-def verify_error(clazz):
-    """Verifies that we always use Exception instead of Error."""
-    if not clazz.extends: return
-    if clazz.extends.endswith("Error"):
-        error(clazz, None, None, "Trouble must be reported through an Exception, not Error")
-    if clazz.extends.endswith("Exception") and not clazz.name.endswith("Exception"):
-        error(clazz, None, None, "Exceptions must be named FooException")
-
-
-@verifier
-def verify_units(clazz):
-    """Verifies that we use consistent naming for units."""
-
-    # If we find K, recommend replacing with V
-    bad = {
-        "Ns": "Nanos",
-        "Ms": "Millis or Micros",
-        "Sec": "Seconds", "Secs": "Seconds",
-        "Hr": "Hours", "Hrs": "Hours",
-        "Mo": "Months", "Mos": "Months",
-        "Yr": "Years", "Yrs": "Years",
-        "Byte": "Bytes", "Space": "Bytes",
-    }
-
-    for m in clazz.methods:
-        if m.typ not in ["short","int","long"]: continue
-        for k, v in bad.iteritems():
-            if m.name.endswith(k):
-                error(clazz, m, None, "Expected method name units to be " + v)
-        if m.name.endswith("Nanos") or m.name.endswith("Micros"):
-            warn(clazz, m, None, "Returned time values are strongly encouraged to be in milliseconds unless you need the extra precision")
-        if m.name.endswith("Seconds"):
-            error(clazz, m, None, "Returned time values must be in milliseconds")
-
-    for m in clazz.methods:
-        typ = m.typ
-        if typ == "void":
-            if len(m.args) != 1: continue
-            typ = m.args[0]
-
-        if m.name.endswith("Fraction") and typ != "float":
-            error(clazz, m, None, "Fractions must use floats")
-        if m.name.endswith("Percentage") and typ != "int":
-            error(clazz, m, None, "Percentage must use ints")
-
-
-@verifier
-def verify_closable(clazz):
-    """Verifies that classes are AutoClosable."""
-    if "java.lang.AutoCloseable" in clazz.implements_all: return
-    if "java.io.Closeable" in clazz.implements_all: return
-
-    for m in clazz.methods:
-        if len(m.args) > 0: continue
-        if m.name in ["close","release","destroy","finish","finalize","disconnect","shutdown","stop","free","quit"]:
-            warn(clazz, m, None, "Classes that release resources should implement AutoClosable and CloseGuard")
-            return
-
-
-@verifier
-def verify_member_name_not_kotlin_keyword(clazz):
-    """Prevent method names which are keywords in Kotlin."""
-
-    # https://kotlinlang.org/docs/reference/keyword-reference.html#hard-keywords
-    # This list does not include Java keywords as those are already impossible to use.
-    keywords = [
-        'as',
-        'fun',
-        'in',
-        'is',
-        'object',
-        'typealias',
-        'val',
-        'var',
-        'when',
-    ]
-
-    for m in clazz.methods:
-        if m.name in keywords:
-            error(clazz, m, None, "Method name must not be a Kotlin keyword")
-    for f in clazz.fields:
-        if f.name in keywords:
-            error(clazz, f, None, "Field name must not be a Kotlin keyword")
-
-
-@verifier
-def verify_method_name_not_kotlin_operator(clazz):
-    """Warn about method names which become operators in Kotlin."""
-
-    binary = set()
-
-    def unique_binary_op(m, op):
-        if op in binary:
-            error(clazz, m, None, "Only one of '{0}' and '{0}Assign' methods should be present for Kotlin".format(op))
-        binary.add(op)
-
-    for m in clazz.methods:
-        if 'static' in m.split or 'operator' in m.split:
-            continue
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#unary-prefix-operators
-        if m.name in ['unaryPlus', 'unaryMinus', 'not'] and len(m.args) == 0:
-            warn(clazz, m, None, "Method can be invoked as a unary operator from Kotlin")
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#increments-and-decrements
-        if m.name in ['inc', 'dec'] and len(m.args) == 0 and m.typ != 'void':
-            # This only applies if the return type is the same or a subtype of the enclosing class, but we have no
-            # practical way of checking that relationship here.
-            warn(clazz, m, None, "Method can be invoked as a pre/postfix inc/decrement operator from Kotlin")
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#arithmetic
-        if m.name in ['plus', 'minus', 'times', 'div', 'rem', 'mod', 'rangeTo'] and len(m.args) == 1:
-            warn(clazz, m, None, "Method can be invoked as a binary operator from Kotlin")
-            unique_binary_op(m, m.name)
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#in
-        if m.name == 'contains' and len(m.args) == 1 and m.typ == 'boolean':
-            warn(clazz, m, None, "Method can be invoked as a 'in' operator from Kotlin")
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#indexed
-        if (m.name == 'get' and len(m.args) > 0) or (m.name == 'set' and len(m.args) > 1):
-            warn(clazz, m, None, "Method can be invoked with an indexing operator from Kotlin")
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#invoke
-        if m.name == 'invoke':
-            warn(clazz, m, None, "Method can be invoked with function call syntax from Kotlin")
-
-        # https://kotlinlang.org/docs/reference/operator-overloading.html#assignments
-        if m.name in ['plusAssign', 'minusAssign', 'timesAssign', 'divAssign', 'remAssign', 'modAssign'] \
-                and len(m.args) == 1 \
-                and m.typ == 'void':
-            warn(clazz, m, None, "Method can be invoked as a compound assignment operator from Kotlin")
-            unique_binary_op(m, m.name[:-6])  # Remove 'Assign' suffix
-
-
-@verifier
-def verify_collections_over_arrays(clazz):
-    """Warn that [] should be Collections."""
-
-    if "@interface" in clazz.split:
-        return
-
-    safe = ["java.lang.String[]","byte[]","short[]","int[]","long[]","float[]","double[]","boolean[]","char[]"]
-    for m in clazz.methods:
-        if m.typ.endswith("[]") and m.typ not in safe:
-            warn(clazz, m, None, "Method should return Collection<> (or subclass) instead of raw array")
-        for arg in m.args:
-            if arg.endswith("[]") and arg not in safe:
-                warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array")
-
-
-@verifier
-def verify_user_handle(clazz):
-    """Methods taking UserHandle should be ForUser or AsUser."""
-    if clazz.name.endswith("Listener") or clazz.name.endswith("Callback") or clazz.name.endswith("Callbacks"): return
-    if clazz.fullname == "android.app.admin.DeviceAdminReceiver": return
-    if clazz.fullname == "android.content.pm.LauncherApps": return
-    if clazz.fullname == "android.os.UserHandle": return
-    if clazz.fullname == "android.os.UserManager": return
-
-    for m in clazz.methods:
-        if re.match("on[A-Z]+", m.name): continue
-
-        has_arg = "android.os.UserHandle" in m.args
-        has_name = m.name.endswith("AsUser") or m.name.endswith("ForUser")
-
-        if clazz.fullname.endswith("Manager") and has_arg:
-            warn(clazz, m, None, "When a method overload is needed to target a specific "
-                 "UserHandle, callers should be directed to use "
-                 "Context.createPackageContextAsUser() and re-obtain the relevant "
-                 "Manager, and no new API should be added")
-        elif has_arg and not has_name:
-            warn(clazz, m, None, "Method taking UserHandle should be named 'doFooAsUser' "
-                 "or 'queryFooForUser'")
-
-
-@verifier
-def verify_params(clazz):
-    """Parameter classes should be 'Params'."""
-    if clazz.name.endswith("Params"): return
-    if clazz.fullname == "android.app.ActivityOptions": return
-    if clazz.fullname == "android.app.BroadcastOptions": return
-    if clazz.fullname == "android.os.Bundle": return
-    if clazz.fullname == "android.os.BaseBundle": return
-    if clazz.fullname == "android.os.PersistableBundle": return
-
-    bad = ["Param","Parameter","Parameters","Args","Arg","Argument","Arguments","Options","Bundle"]
-    for b in bad:
-        if clazz.name.endswith(b):
-            error(clazz, None, None, "Classes holding a set of parameters should be called 'FooParams'")
-
-
-@verifier
-def verify_services(clazz):
-    """Service name should be FOO_BAR_SERVICE = 'foo_bar'."""
-    if clazz.fullname != "android.content.Context": return
-
-    for f in clazz.fields:
-        if f.typ != "java.lang.String": continue
-        found = re.match(r"([A-Z_]+)_SERVICE", f.name)
-        if found:
-            expected = found.group(1).lower()
-            if f.value != expected:
-                error(clazz, f, "C4", "Inconsistent service value; expected '%s'" % (expected))
-
-
-@verifier
-def verify_tense(clazz):
-    """Verify tenses of method names."""
-    if clazz.fullname.startswith("android.opengl"): return
-
-    for m in clazz.methods:
-        if m.name.endswith("Enable"):
-            warn(clazz, m, None, "Unexpected tense; probably meant 'enabled'")
-
-
-@verifier
-def verify_icu(clazz):
-    """Verifies that richer ICU replacements are used."""
-    better = {
-        "java.util.TimeZone": "android.icu.util.TimeZone",
-        "java.util.Calendar": "android.icu.util.Calendar",
-        "java.util.Locale": "android.icu.util.ULocale",
-        "java.util.ResourceBundle": "android.icu.util.UResourceBundle",
-        "java.util.SimpleTimeZone": "android.icu.util.SimpleTimeZone",
-        "java.util.StringTokenizer": "android.icu.util.StringTokenizer",
-        "java.util.GregorianCalendar": "android.icu.util.GregorianCalendar",
-        "java.lang.Character": "android.icu.lang.UCharacter",
-        "java.text.BreakIterator": "android.icu.text.BreakIterator",
-        "java.text.Collator": "android.icu.text.Collator",
-        "java.text.DecimalFormatSymbols": "android.icu.text.DecimalFormatSymbols",
-        "java.text.NumberFormat": "android.icu.text.NumberFormat",
-        "java.text.DateFormatSymbols": "android.icu.text.DateFormatSymbols",
-        "java.text.DateFormat": "android.icu.text.DateFormat",
-        "java.text.SimpleDateFormat": "android.icu.text.SimpleDateFormat",
-        "java.text.MessageFormat": "android.icu.text.MessageFormat",
-        "java.text.DecimalFormat": "android.icu.text.DecimalFormat",
-    }
-
-    for m in clazz.ctors + clazz.methods:
-        types = []
-        types.extend(m.typ)
-        types.extend(m.args)
-        for arg in types:
-            if arg in better:
-                warn(clazz, m, None, "Type %s should be replaced with richer ICU type %s" % (arg, better[arg]))
-
-
-@verifier
-def verify_clone(clazz):
-    """Verify that clone() isn't implemented; see EJ page 61."""
-    for m in clazz.methods:
-        if m.name == "clone":
-            error(clazz, m, None, "Provide an explicit copy constructor instead of implementing clone()")
-
-
-@verifier
-def verify_pfd(clazz):
-    """Verify that android APIs use PFD over FD."""
-    if clazz.fullname == "android.os.FileUtils" or clazz.fullname == "android.system.Os":
-        return
-
-    examine = clazz.ctors + clazz.methods
-    for m in examine:
-        if m.typ == "java.io.FileDescriptor":
-            error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
-        if m.typ == "int":
-            if "Fd" in m.name or "FD" in m.name or "FileDescriptor" in m.name:
-                error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
-        for arg in m.args:
-            if arg == "java.io.FileDescriptor":
-                error(clazz, m, "FW11", "Must use ParcelFileDescriptor")
-
-    for f in clazz.fields:
-        if f.typ == "java.io.FileDescriptor":
-            error(clazz, f, "FW11", "Must use ParcelFileDescriptor")
-
-
-@verifier
-def verify_numbers(clazz):
-    """Discourage small numbers types like short and byte."""
-
-    discouraged = ["short","byte"]
-
-    for c in clazz.ctors:
-        for arg in c.args:
-            if arg in discouraged:
-                warn(clazz, c, "FW12", "Should avoid odd sized primitives; use int instead")
-
-    for f in clazz.fields:
-        if f.typ in discouraged:
-            warn(clazz, f, "FW12", "Should avoid odd sized primitives; use int instead")
-
-    for m in clazz.methods:
-        if m.typ in discouraged:
-            warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")
-        for arg in m.args:
-            if arg in discouraged:
-                warn(clazz, m, "FW12", "Should avoid odd sized primitives; use int instead")
-
-
-PRIMITIVES = {"void", "int", "float", "boolean", "short", "char", "byte", "long", "double"}
-
-@verifier
-def verify_nullability(clazz):
-    """Catches missing nullability annotations"""
-
-    for f in clazz.fields:
-        if "enum_constant" in f.split:
-            continue  # Enum constants are never null
-        if f.value is not None and 'final' in f.split:
-            continue  # Nullability of constants can be inferred.
-        if f.typ not in PRIMITIVES and not has_nullability(f.annotations):
-            error(clazz, f, "M12", "Field must be marked either @NonNull or @Nullable")
-
-    for c in clazz.ctors:
-        verify_nullability_args(clazz, c)
-
-    for m in clazz.methods:
-        if m.name == "writeToParcel" or m.name == "onReceive" or m.name == "onBind":
-            continue  # Parcelable.writeToParcel(), BroadcastReceiver.onReceive(), and Service.onBind() are not yet annotated
-
-        if (m.name == "equals" and m.args == ["java.lang.Object"] or
-                m.name == "toString" and m.args == []):
-            continue  # Nullability of equals and toString is implicit.
-
-        if m.typ not in PRIMITIVES and not has_nullability(m.annotations):
-            error(clazz, m, "M12", "Return value must be marked either @NonNull or @Nullable")
-        verify_nullability_args(clazz, m)
-
-def verify_nullability_args(clazz, m):
-    for i, arg in enumerate(m.detailed_args):
-        if arg.type not in PRIMITIVES and not has_nullability(arg.annotations):
-            error(clazz, m, "M12", "Argument %d must be marked either @NonNull or @Nullable" % (i+1,))
-
-def has_nullability(annotations):
-    return "@NonNull" in annotations or "@Nullable" in annotations
-
-
-@verifier
-def verify_intdef(clazz):
-    """intdefs must be @hide, because the constant names cannot be stored in
-       the stubs (only the values are, which is not useful)"""
-    if "@interface" not in clazz.split:
-        return
-    if "@IntDef" in clazz.annotations or "@LongDef" in clazz.annotations:
-        error(clazz, None, None, "@IntDef and @LongDef annotations must be @hide")
-
-
-@verifier
-def verify_singleton(clazz):
-    """Catch singleton objects with constructors."""
-
-    singleton = False
-    for m in clazz.methods:
-        if m.name.startswith("get") and m.name.endswith("Instance") and " static " in m.raw:
-            singleton = True
-
-    if singleton:
-        for c in clazz.ctors:
-            error(clazz, c, None, "Singleton classes should use getInstance() methods")
-
-
-
-def is_interesting(clazz):
-    """Test if given class is interesting from an Android PoV."""
-
-    if clazz.pkg.name.startswith("java"): return False
-    if clazz.pkg.name.startswith("junit"): return False
-    if clazz.pkg.name.startswith("org.apache"): return False
-    if clazz.pkg.name.startswith("org.xml"): return False
-    if clazz.pkg.name.startswith("org.json"): return False
-    if clazz.pkg.name.startswith("org.w3c"): return False
-    if clazz.pkg.name.startswith("android.icu."): return False
-    return True
-
-
-def examine_clazz(clazz):
-    """Find all style issues in the given class."""
-
-    notice(clazz)
-
-    if not is_interesting(clazz): return
-
-    for v in verifiers.itervalues():
-        v(clazz)
-
-    if not ALLOW_GOOGLE: verify_google(clazz)
-
-
-def examine_stream(stream, base_stream=None, in_classes_with_base=[], out_classes_with_base=None):
-    """Find all style issues in the given API stream."""
-    global failures, noticed
-    failures = {}
-    noticed = {}
-    _parse_stream(stream, examine_clazz, base_f=base_stream,
-                  in_classes_with_base=in_classes_with_base,
-                  out_classes_with_base=out_classes_with_base)
-    return (failures, noticed)
-
-
-def examine_api(api):
-    """Find all style issues in the given parsed API."""
-    global failures
-    failures = {}
-    for key in sorted(api.keys()):
-        examine_clazz(api[key])
-    return failures
-
-
-def verify_compat(cur, prev):
-    """Find any incompatible API changes between two levels."""
-    global failures
-
-    def class_exists(api, test):
-        return test.fullname in api
-
-    def ctor_exists(api, clazz, test):
-        for m in clazz.ctors:
-            if m.ident == test.ident: return True
-        return False
-
-    def all_methods(api, clazz):
-        methods = list(clazz.methods)
-        if clazz.extends is not None:
-            methods.extend(all_methods(api, api[clazz.extends]))
-        return methods
-
-    def method_exists(api, clazz, test):
-        methods = all_methods(api, clazz)
-        for m in methods:
-            if m.ident == test.ident: return True
-        return False
-
-    def field_exists(api, clazz, test):
-        for f in clazz.fields:
-            if f.ident == test.ident: return True
-        return False
-
-    failures = {}
-    for key in sorted(prev.keys()):
-        prev_clazz = prev[key]
-
-        if not class_exists(cur, prev_clazz):
-            error(prev_clazz, None, None, "Class removed or incompatible change")
-            continue
-
-        cur_clazz = cur[key]
-
-        for test in prev_clazz.ctors:
-            if not ctor_exists(cur, cur_clazz, test):
-                error(prev_clazz, prev_ctor, None, "Constructor removed or incompatible change")
-
-        methods = all_methods(prev, prev_clazz)
-        for test in methods:
-            if not method_exists(cur, cur_clazz, test):
-                error(prev_clazz, test, None, "Method removed or incompatible change")
-
-        for test in prev_clazz.fields:
-            if not field_exists(cur, cur_clazz, test):
-                error(prev_clazz, test, None, "Field removed or incompatible change")
-
-    return failures
-
-
-def match_filter(filters, fullname):
-    for f in filters:
-        if fullname == f:
-            return True
-        if fullname.startswith(f + '.'):
-            return True
-    return False
-
-
-def show_deprecations_at_birth(cur, prev):
-    """Show API deprecations at birth."""
-    global failures
-
-    # Remove all existing things so we're left with new
-    for prev_clazz in prev.values():
-        if prev_clazz.fullname not in cur:
-            # The class was removed this release; we can safely ignore it.
-            continue
-
-        cur_clazz = cur[prev_clazz.fullname]
-        if not is_interesting(cur_clazz): continue
-
-        sigs = { i.ident: i for i in prev_clazz.ctors }
-        cur_clazz.ctors = [ i for i in cur_clazz.ctors if i.ident not in sigs ]
-        sigs = { i.ident: i for i in prev_clazz.methods }
-        cur_clazz.methods = [ i for i in cur_clazz.methods if i.ident not in sigs ]
-        sigs = { i.ident: i for i in prev_clazz.fields }
-        cur_clazz.fields = [ i for i in cur_clazz.fields if i.ident not in sigs ]
-
-        # Forget about class entirely when nothing new
-        if len(cur_clazz.ctors) == 0 and len(cur_clazz.methods) == 0 and len(cur_clazz.fields) == 0:
-            del cur[prev_clazz.fullname]
-
-    for clazz in cur.values():
-        if not is_interesting(clazz): continue
-
-        if "deprecated" in clazz.split and not clazz.fullname in prev:
-            error(clazz, None, None, "Found API deprecation at birth")
-
-        for i in clazz.ctors + clazz.methods + clazz.fields:
-            if "deprecated" in i.split:
-                error(clazz, i, None, "Found API deprecation at birth")
-
-    print "%s Deprecated at birth %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True),
-                                            format(reset=True)))
-    for f in sorted(failures):
-        print failures[f]
-        print
-
-
-def show_stats(cur, prev):
-    """Show API stats."""
-
-    stats = collections.defaultdict(int)
-    for cur_clazz in cur.values():
-        if not is_interesting(cur_clazz): continue
-
-        if cur_clazz.fullname not in prev:
-            stats['new_classes'] += 1
-            stats['new_ctors'] += len(cur_clazz.ctors)
-            stats['new_methods'] += len(cur_clazz.methods)
-            stats['new_fields'] += len(cur_clazz.fields)
-        else:
-            prev_clazz = prev[cur_clazz.fullname]
-
-            sigs = { i.ident: i for i in prev_clazz.ctors }
-            ctors = len([ i for i in cur_clazz.ctors if i.ident not in sigs ])
-            sigs = { i.ident: i for i in prev_clazz.methods }
-            methods = len([ i for i in cur_clazz.methods if i.ident not in sigs ])
-            sigs = { i.ident: i for i in prev_clazz.fields }
-            fields = len([ i for i in cur_clazz.fields if i.ident not in sigs ])
-
-            if ctors + methods + fields > 0:
-                stats['extend_classes'] += 1
-                stats['extend_ctors'] += ctors
-                stats['extend_methods'] += methods
-                stats['extend_fields'] += fields
-
-    print "#", "".join([ k.ljust(20) for k in sorted(stats.keys()) ])
-    print " ", "".join([ str(stats[k]).ljust(20) for k in sorted(stats.keys()) ])
-
-
-def main():
-    parser = argparse.ArgumentParser(description="Enforces common Android public API design \
-            patterns. It ignores lint messages from a previous API level, if provided.")
-    parser.add_argument("--base-current", nargs='?', type=argparse.FileType('r'), default=None,
-            help="The base current.txt to use when examining system-current.txt or"
-                 " test-current.txt")
-    parser.add_argument("--base-previous", nargs='?', type=argparse.FileType('r'), default=None,
-            help="The base previous.txt to use when examining system-previous.txt or"
-                 " test-previous.txt")
-    parser.add_argument("--no-color", action='store_const', const=True,
-            help="Disable terminal colors")
-    parser.add_argument("--color", action='store_const', const=True,
-            help="Use terminal colors")
-    parser.add_argument("--allow-google", action='store_const', const=True,
-            help="Allow references to Google")
-    parser.add_argument("--show-noticed", action='store_const', const=True,
-            help="Show API changes noticed")
-    parser.add_argument("--show-deprecations-at-birth", action='store_const', const=True,
-            help="Show API deprecations at birth")
-    parser.add_argument("--show-stats", action='store_const', const=True,
-            help="Show API stats")
-    parser.add_argument("--title", action='store', default=None,
-            help="Title to put in for display purposes")
-    parser.add_argument("--filter", action="append",
-            help="If provided, only show lint for the given packages or classes.")
-    parser.add_argument("current.txt", type=argparse.FileType('r'), help="current.txt")
-    parser.add_argument("previous.txt", nargs='?', type=argparse.FileType('r'), default=None,
-            help="previous.txt")
-    args = vars(parser.parse_args())
-
-    if args['no_color']:
-        USE_COLOR = False
-    elif args['color']:
-        USE_COLOR = True
-    else:
-        USE_COLOR = sys.stdout.isatty()
-
-    if args['allow_google']:
-        ALLOW_GOOGLE = True
-
-    current_file = args['current.txt']
-    base_current_file = args['base_current']
-    previous_file = args['previous.txt']
-    base_previous_file = args['base_previous']
-    filters = args['filter']
-    if not filters:
-        filters = []
-    title = args['title']
-    if not title:
-        title = current_file.name
-
-    if args['show_deprecations_at_birth']:
-        with current_file as f:
-            cur = _parse_stream(f)
-        with previous_file as f:
-            prev = _parse_stream(f)
-        show_deprecations_at_birth(cur, prev)
-        sys.exit()
-
-    if args['show_stats']:
-        with current_file as f:
-            cur = _parse_stream(f)
-        with previous_file as f:
-            prev = _parse_stream(f)
-        show_stats(cur, prev)
-        sys.exit()
-
-    classes_with_base = []
-
-    with current_file as f:
-        if base_current_file:
-            with base_current_file as base_f:
-                cur_fail, cur_noticed = examine_stream(f, base_f,
-                                                       out_classes_with_base=classes_with_base)
-        else:
-            cur_fail, cur_noticed = examine_stream(f, out_classes_with_base=classes_with_base)
-
-    if not previous_file is None:
-        with previous_file as f:
-            if base_previous_file:
-                with base_previous_file as base_f:
-                    prev_fail, prev_noticed = examine_stream(f, base_f,
-                                                             in_classes_with_base=classes_with_base)
-            else:
-                prev_fail, prev_noticed = examine_stream(f, in_classes_with_base=classes_with_base)
-
-        # ignore errors from previous API level
-        for p in prev_fail:
-            if p in cur_fail:
-                del cur_fail[p]
-
-        # ignore classes unchanged from previous API level
-        for k, v in prev_noticed.iteritems():
-            if k in cur_noticed and v == cur_noticed[k]:
-                del cur_noticed[k]
-
-        """
-        # NOTE: disabled because of memory pressure
-        # look for compatibility issues
-        compat_fail = verify_compat(cur, prev)
-
-        print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-        for f in sorted(compat_fail):
-            print compat_fail[f]
-            print
-        """
-
-    # ignore everything but the given filters, if provided
-    if filters:
-        cur_fail = dict([(key, failure) for key, failure in cur_fail.iteritems()
-                if match_filter(filters, failure.clazz.fullname)])
-
-    if args['show_noticed'] and len(cur_noticed) != 0:
-        print "%s API changes noticed %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
-        for f in sorted(cur_noticed.keys()):
-            print f
-        print
-
-    if len(cur_fail) != 0:
-        print "%s API style issues: %s %s" % ((format(fg=WHITE, bg=BLUE, bold=True),
-                    title, format(reset=True)))
-        for f in filters:
-            print "%s   filter: %s %s" % ((format(fg=WHITE, bg=BLUE, bold=True),
-                        f, format(reset=True)))
-        print
-        for f in sorted(cur_fail):
-            print cur_fail[f]
-            print
-        print "%d errors" % len(cur_fail)
-        sys.exit(77)
-
-if __name__ == "__main__":
-    try:
-        main()
-    except KeyboardInterrupt:
-        sys.exit(1)
diff --git a/tools/apilint/apilint_sha.sh b/tools/apilint/apilint_sha.sh
deleted file mode 100755
index 2a45b10..0000000
--- a/tools/apilint/apilint_sha.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-if git show --name-only --pretty=format: $1 | grep api/ > /dev/null; then
-    python tools/apilint/apilint.py <(git show $1:api/current.txt) <(git show $1^:api/current.txt)
-fi
diff --git a/tools/apilint/apilint_sha_system.sh b/tools/apilint/apilint_sha_system.sh
deleted file mode 100755
index 8538a3d..0000000
--- a/tools/apilint/apilint_sha_system.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2018 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.
-
-if git show --name-only --pretty=format: $1 | grep api/ > /dev/null; then
-  python tools/apilint/apilint.py \
-    --base-current <(git show $1:api/current.txt) \
-    --base-previous <(git show $1^:api/current.txt) \
-    <(git show $1:api/system-current.txt) \
-    <(git show $1^:api/system-current.txt)
-fi
diff --git a/tools/apilint/apilint_stats.sh b/tools/apilint/apilint_stats.sh
deleted file mode 100755
index 052d9a5..0000000
--- a/tools/apilint/apilint_stats.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-API=28
-while [ $API -gt 14 ]; do
-    echo "# Changes in API $((API))"
-    python tools/apilint/apilint.py --show-stats ../../prebuilts/sdk/$((API))/public/api/android.txt ../../prebuilts/sdk/$((API-1))/public/api/android.txt
-    let API=API-1
-done
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
deleted file mode 100644
index 811cb9a..0000000
--- a/tools/apilint/apilint_test.py
+++ /dev/null
@@ -1,414 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2018 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.
-
-import unittest
-
-import apilint
-
-def cls(pkg, name):
-    return apilint.Class(apilint.Package(999, "package %s {" % pkg, None), 999,
-                  "public final class %s {" % name, None)
-
-_ri = apilint._retry_iterator
-
-c1 = cls("android.app", "ActivityManager")
-c2 = cls("android.app", "Notification")
-c3 = cls("android.app", "Notification.Action")
-c4 = cls("android.graphics", "Bitmap")
-
-class UtilTests(unittest.TestCase):
-    def test_retry_iterator(self):
-        it = apilint._retry_iterator([1, 2, 3, 4])
-        self.assertEqual(it.next(), 1)
-        self.assertEqual(it.next(), 2)
-        self.assertEqual(it.next(), 3)
-        it.send("retry")
-        self.assertEqual(it.next(), 3)
-        self.assertEqual(it.next(), 4)
-        with self.assertRaises(StopIteration):
-            it.next()
-
-    def test_retry_iterator_one(self):
-        it = apilint._retry_iterator([1])
-        self.assertEqual(it.next(), 1)
-        it.send("retry")
-        self.assertEqual(it.next(), 1)
-        with self.assertRaises(StopIteration):
-            it.next()
-
-    def test_retry_iterator_one(self):
-        it = apilint._retry_iterator([1])
-        self.assertEqual(it.next(), 1)
-        it.send("retry")
-        self.assertEqual(it.next(), 1)
-        with self.assertRaises(StopIteration):
-            it.next()
-
-    def test_skip_to_matching_class_found(self):
-        it = _ri([c1, c2, c3, c4])
-        self.assertEquals(apilint._skip_to_matching_class(it, c3),
-                          c3)
-        self.assertEqual(it.next(), c4)
-
-    def test_skip_to_matching_class_not_found(self):
-        it = _ri([c1, c2, c3, c4])
-        self.assertEquals(apilint._skip_to_matching_class(it, cls("android.content", "ContentProvider")),
-                          None)
-        self.assertEqual(it.next(), c4)
-
-    def test_yield_until_matching_class_found(self):
-        it = _ri([c1, c2, c3, c4])
-        self.assertEquals(list(apilint._yield_until_matching_class(it, c3)),
-                          [c1, c2])
-        self.assertEqual(it.next(), c4)
-
-    def test_yield_until_matching_class_not_found(self):
-        it = _ri([c1, c2, c3, c4])
-        self.assertEquals(list(apilint._yield_until_matching_class(it, cls("android.content", "ContentProvider"))),
-                          [c1, c2, c3])
-        self.assertEqual(it.next(), c4)
-
-    def test_yield_until_matching_class_None(self):
-        it = _ri([c1, c2, c3, c4])
-        self.assertEquals(list(apilint._yield_until_matching_class(it, None)),
-                          [c1, c2, c3, c4])
-
-
-faulty_current_txt = """
-// Signature format: 2.0
-package android.app {
-  public final class Activity {
-  }
-
-  public final class WallpaperColors implements android.os.Parcelable {
-    ctor public WallpaperColors(@NonNull android.os.Parcel);
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
-  }
-}
-""".strip().split('\n')
-
-ok_current_txt = """
-// Signature format: 2.0
-package android.app {
-  public final class Activity {
-  }
-
-  public final class WallpaperColors implements android.os.Parcelable {
-    ctor public WallpaperColors();
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
-  }
-}
-""".strip().split('\n')
-
-system_current_txt = """
-// Signature format: 2.0
-package android.app {
-  public final class WallpaperColors implements android.os.Parcelable {
-    method public int getSomething();
-  }
-}
-""".strip().split('\n')
-
-
-
-class BaseFileTests(unittest.TestCase):
-    def test_base_file_avoids_errors(self):
-        failures, _ = apilint.examine_stream(system_current_txt, ok_current_txt)
-        self.assertEquals(failures, {})
-
-    def test_class_with_base_finds_same_errors(self):
-        failures_with_classes_with_base, _ = apilint.examine_stream("", faulty_current_txt,
-                                                                    in_classes_with_base=[cls("android.app", "WallpaperColors")])
-        failures_with_system_txt, _ = apilint.examine_stream(system_current_txt, faulty_current_txt)
-
-        self.assertEquals(failures_with_classes_with_base.keys(), failures_with_system_txt.keys())
-
-    def test_classes_with_base_is_emited(self):
-        classes_with_base = []
-        _, _ = apilint.examine_stream(system_current_txt, faulty_current_txt,
-                                      out_classes_with_base=classes_with_base)
-        self.assertEquals(map(lambda x: x.fullname, classes_with_base), ["android.app.WallpaperColors"])
-
-class ParseV2Stream(unittest.TestCase):
-    def test_field_kinds(self):
-        api = apilint._parse_stream("""
-// Signature format: 2.0
-package android {
-  public enum SomeEnum {
-    enum_constant public static final android.SomeEnum ENUM_CONST;
-    field public static final int FIELD_CONST;
-    property public final int someProperty;
-    ctor public SomeEnum();
-    method public Object? getObject();
-  }
-}
-        """.strip().split('\n'))
-
-        self.assertEquals(api['android.SomeEnum'].fields[0].split[0], 'enum_constant')
-        self.assertEquals(api['android.SomeEnum'].fields[1].split[0], 'field')
-        self.assertEquals(api['android.SomeEnum'].fields[2].split[0], 'property')
-        self.assertEquals(api['android.SomeEnum'].ctors[0].split[0], 'ctor')
-        self.assertEquals(api['android.SomeEnum'].methods[0].split[0], 'method')
-
-class ParseV3Stream(unittest.TestCase):
-    def test_field_kinds(self):
-        api = apilint._parse_stream("""
-// Signature format: 3.0
-package a {
-
-  public final class ContextKt {
-    method public static inline <reified T> T! getSystemService(android.content.Context);
-    method public static inline void withStyledAttributes(android.content.Context, android.util.AttributeSet? set = null, int[] attrs, @AttrRes int defStyleAttr = 0, @StyleRes int defStyleRes = 0, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
-  }
-}
-        """.strip().split('\n'))
-        self.assertEquals(api['a.ContextKt'].methods[0].name, 'getSystemService')
-        self.assertEquals(api['a.ContextKt'].methods[0].split[:4], ['method', 'public', 'static', 'inline'])
-        self.assertEquals(api['a.ContextKt'].methods[1].name, 'withStyledAttributes')
-        self.assertEquals(api['a.ContextKt'].methods[1].split[:4], ['method', 'public', 'static', 'inline'])
-
-class V2TokenizerTests(unittest.TestCase):
-    def _test(self, raw, expected):
-        self.assertEquals(apilint.V2Tokenizer(raw).tokenize(), expected)
-
-    def test_simple(self):
-        self._test("  method public some.Type someName(some.Argument arg, int arg);",
-                   ['method', 'public', 'some.Type', 'someName', '(', 'some.Argument',
-                    'arg', ',', 'int', 'arg', ')', ';'])
-        self._test("class Some.Class extends SomeOther {",
-                   ['class', 'Some.Class', 'extends', 'SomeOther', '{'])
-
-    def test_varargs(self):
-        self._test("name(String...)",
-                   ['name', '(', 'String', '...', ')'])
-
-    def test_kotlin(self):
-        self._test("String? name(String!...)",
-                   ['String', '?', 'name', '(', 'String', '!',  '...', ')'])
-
-    def test_annotation(self):
-        self._test("method @Nullable public void name();",
-                   ['method', '@', 'Nullable', 'public', 'void', 'name', '(', ')', ';'])
-
-    def test_annotation_args(self):
-        self._test("@Some(val=1, other=2) class Class {",
-                   ['@', 'Some', '(', 'val', '=', '1', ',', 'other', '=', '2', ')',
-                    'class', 'Class', '{'])
-    def test_comment(self):
-        self._test("some //comment", ['some'])
-
-    def test_strings(self):
-        self._test(r'"" "foo" "\"" "\\"', ['""', '"foo"', r'"\""', r'"\\"'])
-
-    def test_at_interface(self):
-        self._test("public @interface Annotation {",
-                   ['public', '@interface', 'Annotation', '{'])
-
-    def test_array_type(self):
-        self._test("int[][]", ['int', '[]', '[]'])
-
-    def test_generics(self):
-        self._test("<>foobar<A extends Object>",
-                   ['<', '>', 'foobar', '<', 'A', 'extends', 'Object', '>'])
-
-class V2ParserTests(unittest.TestCase):
-    def _cls(self, raw):
-        pkg = apilint.Package(999, "package pkg {", None)
-        return apilint.Class(pkg, 1, raw, '', sig_format=2)
-
-    def _method(self, raw, cls=None):
-        if not cls:
-            cls = self._cls("class Class {")
-        return apilint.Method(cls, 1, raw, '', sig_format=2)
-
-    def _field(self, raw):
-        cls = self._cls("class Class {")
-        return apilint.Field(cls, 1, raw, '', sig_format=2)
-
-    def test_parse_package(self):
-        pkg = apilint.Package(999, "package wifi.p2p {", None)
-        self.assertEquals("wifi.p2p", pkg.name)
-
-    def test_class(self):
-        cls = self._cls("@Deprecated @IntRange(from=1, to=2) public static abstract class Some.Name extends Super<Class> implements Interface<Class> {")
-        self.assertTrue('deprecated' in cls.split)
-        self.assertTrue('static' in cls.split)
-        self.assertTrue('abstract' in cls.split)
-        self.assertTrue('class' in cls.split)
-        self.assertEquals('Super', cls.extends)
-        self.assertEquals('Interface', cls.implements)
-        self.assertEquals('pkg.Some.Name', cls.fullname)
-
-    def test_enum(self):
-        cls = self._cls("public enum Some.Name {")
-        self._field("enum_constant public static final android.ValueType COLOR;")
-
-    def test_interface(self):
-        cls = self._cls("@Deprecated @IntRange(from=1, to=2) public interface Some.Name extends Interface<Class> {")
-        self.assertTrue('deprecated' in cls.split)
-        self.assertTrue('interface' in cls.split)
-        self.assertEquals('Interface', cls.extends)
-        self.assertEquals('Interface', cls.implements)
-        self.assertEquals('pkg.Some.Name', cls.fullname)
-
-    def test_at_interface(self):
-        cls = self._cls("@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {")
-        self.assertTrue('@interface' in cls.split)
-        self.assertEquals('pkg.SuppressLint', cls.fullname)
-
-    def test_parse_method(self):
-        m = self._method("method @Deprecated public static native <T> Class<T>[][] name("
-                         + "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;")
-        self.assertTrue('static' in m.split)
-        self.assertTrue('public' in m.split)
-        self.assertTrue('method' in m.split)
-        self.assertTrue('native' in m.split)
-        self.assertTrue('deprecated' in m.split)
-        self.assertEquals('java.lang.Class[][]', m.typ)
-        self.assertEquals('name', m.name)
-        self.assertEquals(['java.lang.Class[][]', 'java.lang.Class[][]...'], m.args)
-        self.assertEquals(['java.lang.Exception', 'T'], m.throws)
-
-    def test_ctor(self):
-        m = self._method("ctor @Deprecated <T> ClassName();")
-        self.assertTrue('ctor' in m.split)
-        self.assertTrue('deprecated' in m.split)
-        self.assertEquals('ctor', m.typ)
-        self.assertEquals('ClassName', m.name)
-
-    def test_parse_annotation_method(self):
-        cls = self._cls("@interface Annotation {")
-        self._method('method abstract String category() default "";', cls=cls)
-        self._method('method abstract boolean deepExport() default false;', cls=cls)
-        self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls)
-        self._method('method abstract ViewDebug.FlagToString[] flagMapping() default (double)java.lang.Float.NEGATIVE_INFINITY;', cls=cls)
-
-    def test_parse_string_field(self):
-        f = self._field('field @Deprecated public final String SOME_NAME = "value";')
-        self.assertTrue('field' in f.split)
-        self.assertTrue('deprecated' in f.split)
-        self.assertTrue('final' in f.split)
-        self.assertEquals('java.lang.String', f.typ)
-        self.assertEquals('SOME_NAME', f.name)
-        self.assertEquals('value', f.value)
-
-    def test_parse_field(self):
-        f = self._field('field public Object SOME_NAME;')
-        self.assertTrue('field' in f.split)
-        self.assertEquals('java.lang.Object', f.typ)
-        self.assertEquals('SOME_NAME', f.name)
-        self.assertEquals(None, f.value)
-
-    def test_parse_int_field(self):
-        f = self._field('field public int NAME = 123;')
-        self.assertTrue('field' in f.split)
-        self.assertEquals('int', f.typ)
-        self.assertEquals('NAME', f.name)
-        self.assertEquals('123', f.value)
-
-    def test_parse_quotient_field(self):
-        f = self._field('field public int NAME = (0.0/0.0);')
-        self.assertTrue('field' in f.split)
-        self.assertEquals('int', f.typ)
-        self.assertEquals('NAME', f.name)
-        self.assertEquals('( 0.0 / 0.0 )', f.value)
-
-    def test_kotlin_types(self):
-        self._field('field public List<Integer[]?[]!>?[]![]? NAME;')
-        self._method("method <T?> Class<T!>?[]![][]? name(Type!, Type argname,"
-                         + "Class<T?>[][]?[]!...!) throws Exception, T;")
-        self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, "
-                         + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""")
-
-    def test_kotlin_operator(self):
-        self._method('method public operator void unaryPlus(androidx.navigation.NavDestination);')
-        self._method('method public static operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);')
-        self._method('method public static operator <T> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);')
-
-    def test_kotlin_property(self):
-        self._field('property public VM value;')
-        self._field('property public final String? action;')
-
-    def test_kotlin_varargs(self):
-        self._method('method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);')
-
-    def test_kotlin_default_values(self):
-        self._method('method public void foo(String! = null, String! = "Hello World", int = 42);')
-        self._method('method void method(String, String firstArg = "hello", int secondArg = "42", String thirdArg = "world");')
-        self._method('method void method(String, String firstArg = "hello", int secondArg = "42");')
-        self._method('method void method(String, String firstArg = "hello");')
-        self._method('method void edit(android.Type, boolean commit = false, Function1<? super Editor,kotlin.Unit> action);')
-        self._method('method <K, V> LruCache<K,V> lruCache(int maxSize, Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, Function1<? extends V> create = { (V)null }, Function4<kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });')
-        self._method('method android.Bitmap? drawToBitmap(android.View, android.Config config = android.graphics.Bitmap.Config.ARGB_8888);')
-        self._method('method void emptyLambda(Function0<kotlin.Unit> sizeOf = {});')
-        self._method('method void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);')
-        self._method('method void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);')
-        self._method('method void method3(String str, int p, int int2 = double(int) + str.length);')
-        self._method('method void print(test.pkg.Foo foo = test.pkg.Foo());')
-
-    def test_type_use_annotation(self):
-        self._method('method public static int codePointAt(char @NonNull [], int);')
-        self._method('method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();')
-
-        m = self._method('method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();')
-        self.assertEquals('java.lang.annotation.Annotation[]', m.typ)
-
-        m = self._method('method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();')
-        self.assertEquals('java.lang.annotation.Annotation[][]', m.typ)
-
-        m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);')
-        self.assertEquals('java.lang.String[]', m.typ)
-
-class PackageTests(unittest.TestCase):
-    def _package(self, raw):
-        return apilint.Package(123, raw, "blame")
-
-    def test_regular_package(self):
-        p = self._package("package an.pref.int {")
-        self.assertEquals('an.pref.int', p.name)
-
-    def test_annotation_package(self):
-        p = self._package("package @RestrictTo(a.b.C) an.pref.int {")
-        self.assertEquals('an.pref.int', p.name)
-
-    def test_multi_annotation_package(self):
-        p = self._package("package @Rt(a.b.L_G_P) @RestrictTo(a.b.C) an.pref.int {")
-        self.assertEquals('an.pref.int', p.name)
-
-class FilterTests(unittest.TestCase):
-    def test_filter_match_prefix(self):
-        self.assertTrue(apilint.match_filter(["a"], "a.B"))
-        self.assertTrue(apilint.match_filter(["a.B"], "a.B.C"))
-
-    def test_filter_dont_match_prefix(self):
-        self.assertFalse(apilint.match_filter(["c"], "a.B"))
-        self.assertFalse(apilint.match_filter(["a."], "a.B"))
-        self.assertFalse(apilint.match_filter(["a.B."], "a.B.C"))
-
-    def test_filter_match_exact(self):
-        self.assertTrue(apilint.match_filter(["a.B"], "a.B"))
-
-    def test_filter_dont_match_exact(self):
-        self.assertFalse(apilint.match_filter([""], "a.B"))
-        self.assertFalse(apilint.match_filter(["a.C"], "a.B"))
-        self.assertFalse(apilint.match_filter(["a.C"], "a.B"))
-        
-if __name__ == "__main__":
-    unittest.main()
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 77e02df..0d2e816 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -38,6 +38,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.NetworkStack;
 import android.net.wifi.hotspot2.IProvisioningCallback;
 import android.net.wifi.hotspot2.OsuProvider;
 import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -532,19 +533,25 @@
     @SystemApi
     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     /**
-     * The interface used for the softap.
+     * The lookup key for a String extra that stores the interface name used for the Soft AP.
+     * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
+     * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
      *
      * @hide
      */
-    public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name";
+    @SystemApi
+    public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
+            "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
     /**
-     * The intended ip mode for this softap.
-     * @see #IFACE_IP_MODE_TETHERED
-     * @see #IFACE_IP_MODE_LOCAL_ONLY
+     * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
+     * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
+     * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
+     * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
      *
      * @hide
      */
-    public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode";
+    @SystemApi
+    public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
 
     /** @hide */
     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
@@ -634,40 +641,53 @@
      */
     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
+            IFACE_IP_MODE_UNSPECIFIED,
+            IFACE_IP_MODE_CONFIGURATION_ERROR,
+            IFACE_IP_MODE_TETHERED,
+            IFACE_IP_MODE_LOCAL_ONLY})
+    public @interface IfaceIpMode {}
+
     /**
      * Interface IP mode unspecified.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
+    @SystemApi
     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
 
     /**
      * Interface IP mode for configuration error.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
+    @SystemApi
     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
 
     /**
      * Interface IP mode for tethering.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
+    @SystemApi
     public static final int IFACE_IP_MODE_TETHERED = 1;
 
     /**
      * Interface IP mode for Local Only Hotspot.
      *
-     * @see updateInterfaceIpState(String, int)
+     * @see #updateInterfaceIpState(String, int)
      *
      * @hide
      */
+    @SystemApi
     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
 
     /**
@@ -2538,16 +2558,21 @@
     /**
      * Call allowing ConnectivityService to update WifiService with interface mode changes.
      *
-     * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
-     *                             {@link IFACE_IP_MODE_LOCAL_ONLY},
-     *                             {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
-     *
-     * @param ifaceName String name of the updated interface
-     * @param mode int representing the new mode
+     * @param ifaceName String name of the updated interface, or null to represent all interfaces
+     * @param mode int representing the new mode, one of:
+     *             {@link #IFACE_IP_MODE_TETHERED},
+     *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
+     *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
+     *             {@link #IFACE_IP_MODE_UNSPECIFIED}
      *
      * @hide
      */
-    public void updateInterfaceIpState(String ifaceName, int mode) {
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
+    public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
         try {
             mService.updateInterfaceIpState(ifaceName, mode);
         } catch (RemoteException e) {
@@ -2556,15 +2581,21 @@
     }
 
     /**
-     * Start SoftAp mode with the specified configuration.
-     * Note that starting in access point mode disables station
-     * mode operation
-     * @param wifiConfig SSID, security and channel details as
-     *        part of WifiConfiguration
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     * Start Soft AP (hotspot) mode with the specified configuration.
+     * Note that starting Soft AP mode may disable station mode operation if the device does not
+     * support concurrency.
+     * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
+     *                   use the persisted Soft AP configuration that was previously set using
+     *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
+     * @return {@code true} if the operation succeeded, {@code false} otherwise
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
         try {
             return mService.startSoftAp(wifiConfig);
@@ -2580,6 +2611,11 @@
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
     public boolean stopSoftAp() {
         try {
             return mService.stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index e595164..8f3635f 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,8 +20,8 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;