Merge "Add MAP_ANONYMOUS to OsConstants"
diff --git a/Android.bp b/Android.bp
index 90dca03..30dad50 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",
@@ -919,6 +962,7 @@
     "--hide-package com.android.org.conscrypt --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 +1445,6 @@
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
     srcs: [
-        ":non_openjdk_java_files",
-        ":openjdk_java_files",
         ":opt-telephony-common-srcs",
     ],
 
@@ -1493,6 +1535,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/api/current.txt b/api/current.txt
index ab310d6..98674f9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9769,6 +9769,7 @@
     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(@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);
@@ -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();
@@ -44296,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
@@ -44440,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;
@@ -44922,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
@@ -45022,6 +45028,7 @@
     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();
@@ -60892,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();
   }
 
@@ -71227,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 5c576e2..7ea45dc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1373,6 +1373,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";
@@ -4699,8 +4700,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
@@ -4715,10 +4719,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";
@@ -5640,6 +5650,14 @@
 
 }
 
+package android.os.telephony {
+
+  public class TelephonyRegistryManager {
+    method public void notifyCarrierNetworkChange(boolean);
+  }
+
+}
+
 package android.permission {
 
   public final class PermissionControllerManager {
@@ -6374,6 +6392,28 @@
     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);
+  }
+
 }
 
 package android.service.contentcapture {
@@ -7246,9 +7286,9 @@
 
   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 onGsmCellBroadcastSms(int, @NonNull byte[]);
     field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
   }
 
@@ -8181,6 +8221,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();
@@ -8201,6 +8242,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();
@@ -8236,6 +8278,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";
@@ -8812,9 +8855,11 @@
     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.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
     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();
@@ -8825,7 +8870,8 @@
     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 android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) 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);
@@ -8835,7 +8881,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
@@ -8847,12 +8894,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 {
@@ -9228,14 +9271,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 {
@@ -9284,6 +9330,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.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) 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 5cc9ae7..a82ec4e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2899,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..77647c5 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;
@@ -607,6 +608,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
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 51bb85a..cd6acba 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
@@ -4701,6 +4739,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/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/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/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/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/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/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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0460a80..461743e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9334,6 +9334,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/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..8ddb86b0 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,147 @@
 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;
+        V1_0::Status status = toHidlStatus(
+            mVib->perform(static_cast<aidl::Effect>(effect),
+                          static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs));
+        _hidl_cb(status, timeoutMs);
+        return android::hardware::Status::ok();
+    }
+  private:
+    sp<aidl::IVibrator> mVib;
+
+    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;
+        }
+        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 +218,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();
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/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..cb342c6 100644
--- a/telephony/java/android/telephony/CellBroadcastService.java
+++ b/telephony/java/android/telephony/CellBroadcastService.java
@@ -17,10 +17,13 @@
 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.IBinder;
+import android.telephony.cdma.CdmaSmsCbProgramData;
 
 /**
  * A service which exposes the cell broadcast handling module to the system.
@@ -64,14 +67,16 @@
      * @param slotIndex the index of the slot which received the message
      * @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 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);
 
     /**
      * If overriding this method, call through to the super method for any unknown actions.
@@ -79,7 +84,8 @@
      */
     @Override
     @CallSuper
-    public IBinder onBind(Intent intent) {
+    @NonNull
+    public IBinder onBind(@Nullable Intent intent) {
         return mStubWrapper;
     }
 
@@ -102,11 +108,14 @@
         /**
          * Handle a CDMA cell broadcast SMS.
          * @param slotIndex the index of the slot which received the broadcast
-         * @param message the SMS message PDU
+         * @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);
         }
     }
 }
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/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..bcd6cc5 100644
--- a/telephony/java/android/telephony/ICellBroadcastService.aidl
+++ b/telephony/java/android/telephony/ICellBroadcastService.aidl
@@ -28,5 +28,5 @@
     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);
 }
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/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 f661bba..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_"},
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..8dfc944 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,16 +9419,28 @@
         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;
     }
 
@@ -10826,6 +10809,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 +11459,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 +11487,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/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index e65e032..a5d6266 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
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..7cafa1e 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 #registerImsRegistrationCallback(
+     * RegistrationManager.RegistrationCallback, Executor)} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull RegistrationCallback c) throws ImsException {
@@ -380,6 +282,28 @@
         }
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void registerImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor) 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 +314,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 +330,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 @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        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 @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        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 +401,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.
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3c343dd..25bd1ca 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -22,12 +22,14 @@
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.os.Binder;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
 
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Manager for interfacing with the framework RCS services, including the User Capability Exchange
@@ -36,7 +38,7 @@
  * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager.
  * @hide
  */
-public class ImsRcsManager {
+public class ImsRcsManager implements RegistrationManager {
 
     /**
      * Receives RCS availability status updates from the ImsService.
@@ -136,6 +138,64 @@
         mSubId = subId;
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    public void registerImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor)
+            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 @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        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 @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        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.
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/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
new file mode 100644
index 0000000..b4c11e3
--- /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(RegistrationCallback, Executor)
+     * @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 c The {@link RegistrationCallback} to be added.
+     * @param executor The executor the callback events should be run on.
+     * @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 RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor) 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(RegistrationCallback, Executor)
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c);
+
+    /**
+     * Gets the registration state of the IMS service.
+     * @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}.
+     * @param executor The {@link Executor} that will be used to call the IMS registration state
+     *                 callback.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor);
+
+    /**
+     * Gets the Transport Type associated with the current IMS registration.
+     * @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}.
+     * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationTransportType(
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor);
+}
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/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/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;