[automerger] Fixed invalid pdu issue am: e8955271c5

Change-Id: I95999e8d622d5cbb4c471407ceba9c0a37659226
diff --git a/Android.mk b/Android.mk
index add14fa..70acfcd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,10 +26,12 @@
 	$(call all-proto-files-under, proto)
 
 LOCAL_JAVA_LIBRARIES := voip-common ims-common
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.0-java-static \
+    android.hardware.radio.deprecated-V1.0-java-static
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := telephony-common
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors,store_unknown_fields=true,enum_style=java
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := store_unknown_fields=true,enum_style=java
 
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/jarjar-rules.txt
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..f3db20e
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
index 50220b4..958e2bb 100644
--- a/jarjar-rules.txt
+++ b/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
+rule com.google.protobuf.nano.** com.android.internal.telephony.protobuf.nano.@1
 
diff --git a/proto/telephony.proto b/proto/telephony.proto
index 70d210b..1f1a2bb 100644
--- a/proto/telephony.proto
+++ b/proto/telephony.proto
@@ -95,13 +95,13 @@
 // Telephony related user settings
 message TelephonySettings {
 
-  // NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
+  // NETWORK_MODE_* See ril.h PREF_NET_TYPE_XXXX
   enum RilNetworkMode {
 
     // Mode is unknown.
     NETWORK_MODE_UNKNOWN = 0;
 
-    // GSM/WCDMA (WCDMA preferred)
+    // GSM/WCDMA (WCDMA preferred). Note the following values are all off by 1.
     NETWORK_MODE_WCDMA_PREF = 1;
 
     // GSM only
@@ -236,6 +236,9 @@
   // Roaming type
   enum RoamingType {
 
+    // Unknown. The default value. Different from ROAMING_TYPE_UNKNOWN.
+    UNKNOWN = -1;
+
     // In home network
     ROAMING_TYPE_NOT_ROAMING = 0;
 
@@ -257,21 +260,26 @@
   optional TelephonyOperator data_operator = 2;
 
   // Current voice network roaming type
-  optional RoamingType voice_roaming_type = 3;
+  optional RoamingType voice_roaming_type = 3 [default = UNKNOWN];
 
   // Current data network roaming type
-  optional RoamingType data_roaming_type = 4;
+  optional RoamingType data_roaming_type = 4 [default = UNKNOWN];
 
   // Current voice radio technology
-  optional RadioAccessTechnology voice_rat = 5;
+  optional RadioAccessTechnology voice_rat = 5 [default = UNKNOWN];
 
   // Current data radio technology
-  optional RadioAccessTechnology data_rat = 6;
+  optional RadioAccessTechnology data_rat = 6 [default = UNKNOWN];
 }
 
 // Radio access families
 enum RadioAccessTechnology {
 
+  // This is the default value. Different from RAT_UNKNOWN.
+  UNKNOWN = -1;
+
+  // Airplane mode, out of service, or when the modem cannot determine
+  // the RAT.
   RAT_UNKNOWN = 0;
 
   RAT_GPRS = 1;
@@ -377,6 +385,7 @@
   // type is unknown.
   RIL_E_UNKNOWN = 0;
 
+  // Note the following values are all off by 1.
   RIL_E_SUCCESS = 1;
 
   // If radio did not start or is resetting
@@ -458,8 +467,12 @@
   // SS request modified to different SS request
   RIL_E_SS_MODIFIED_TO_SS = 28;
 
-  // LCE service not supported(36 in RILConstants.java)
-  RIL_E_LCE_NOT_SUPPORTED = 36;
+  // LCE service not supported(36 in RILConstants.java. This is a mistake.
+  // The value should be off by 1 ideally.)
+  RIL_E_LCE_NOT_SUPPORTED = 36 [deprecated=true];
+
+  // LCE service not supported
+  RIL_E_LCE_NOT_SUPPORTED_NEW = 37;
 }
 
 // PDP_type values in TS 27.007 section 10.1.1.
@@ -561,7 +574,7 @@
     }
 
     // Radio technology to use
-    optional RadioAccessTechnology rat = 1;
+    optional RadioAccessTechnology rat = 1 [default = UNKNOWN];
 
     // optional RIL_DataProfile
     optional RilDataProfile data_profile = 2;
@@ -576,8 +589,7 @@
   // RIL response to RilSetupDataCall
   message RilSetupDataCallResponse {
 
-    // Copy of enum RIL_DataCallFailCause defined at
-    // https://cs.corp.google.com/android/hardware/ril/include/telephony/ril.h
+    // Copy of enum RIL_DataCallFailCause defined at ril.h
     enum RilDataCallFailCause {
 
       // Failure reason is unknown.
@@ -1097,10 +1109,10 @@
     optional ImsReasonInfo reason_info = 18;
 
     // Original access technology
-    optional RadioAccessTechnology src_access_tech = 19;
+    optional RadioAccessTechnology src_access_tech = 19 [default = UNKNOWN];
 
     // New access technology
-    optional RadioAccessTechnology target_access_tech = 20;
+    optional RadioAccessTechnology target_access_tech = 20 [default = UNKNOWN];
 
     // NITZ time in milliseconds
     optional int64 nitz_timestamp_millis = 21;
diff --git a/src/java/android/provider/Telephony.java b/src/java/android/provider/Telephony.java
deleted file mode 100644
index 943a6ca..0000000
--- a/src/java/android/provider/Telephony.java
+++ /dev/null
@@ -1,2975 +0,0 @@
-/*
- * Copyright (C) 2006 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.provider;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.TestApi;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.sqlite.SqliteWrapper;
-import android.net.Uri;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
-import android.telephony.Rlog;
-import android.util.Patterns;
-
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.SmsApplication;
-
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The Telephony provider contains data related to phone operation, specifically SMS and MMS
- * messages and access to the APN list, including the MMSC to use.
- *
- * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered
- * devices. If your app depends on telephony features such as for managing SMS messages, include
- * a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}
- * </a> element in your manifest that declares the {@code "android.hardware.telephony"} hardware
- * feature. Alternatively, you can check for telephony availability at runtime using either
- * {@link android.content.pm.PackageManager#hasSystemFeature
- * hasSystemFeature(PackageManager.FEATURE_TELEPHONY)} or {@link
- * android.telephony.TelephonyManager#getPhoneType}.</p>
- *
- * <h3>Creating an SMS app</h3>
- *
- * <p>Only the default SMS app (selected by the user in system settings) is able to write to the
- * SMS Provider (the tables defined within the {@code Telephony} class) and only the default SMS
- * app receives the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} broadcast
- * when the user receives an SMS or the {@link
- * android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION} broadcast when the user
- * receives an MMS.</p>
- *
- * <p>Any app that wants to behave as the user's default SMS app must handle the following intents:
- * <ul>
- * <li>In a broadcast receiver, include an intent filter for {@link Sms.Intents#SMS_DELIVER_ACTION}
- * (<code>"android.provider.Telephony.SMS_DELIVER"</code>). The broadcast receiver must also
- * require the {@link android.Manifest.permission#BROADCAST_SMS} permission.
- * <p>This allows your app to directly receive incoming SMS messages.</p></li>
- * <li>In a broadcast receiver, include an intent filter for {@link
- * Sms.Intents#WAP_PUSH_DELIVER_ACTION}} ({@code "android.provider.Telephony.WAP_PUSH_DELIVER"})
- * with the MIME type <code>"application/vnd.wap.mms-message"</code>.
- * The broadcast receiver must also require the {@link
- * android.Manifest.permission#BROADCAST_WAP_PUSH} permission.
- * <p>This allows your app to directly receive incoming MMS messages.</p></li>
- * <li>In your activity that delivers new messages, include an intent filter for
- * {@link android.content.Intent#ACTION_SENDTO} (<code>"android.intent.action.SENDTO"
- * </code>) with schemas, <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and
- * <code>mmsto:</code>.
- * <p>This allows your app to receive intents from other apps that want to deliver a
- * message.</p></li>
- * <li>In a service, include an intent filter for {@link
- * android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}
- * (<code>"android.intent.action.RESPOND_VIA_MESSAGE"</code>) with schemas,
- * <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and <code>mmsto:</code>.
- * This service must also require the {@link
- * android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.
- * <p>This allows users to respond to incoming phone calls with an immediate text message
- * using your app.</p></li>
- * </ul>
- *
- * <p>Other apps that are not selected as the default SMS app can only <em>read</em> the SMS
- * Provider, but may also be notified when a new SMS arrives by listening for the {@link
- * Sms.Intents#SMS_RECEIVED_ACTION}
- * broadcast, which is a non-abortable broadcast that may be delivered to multiple apps. This
- * broadcast is intended for apps that&mdash;while not selected as the default SMS app&mdash;need to
- * read special incoming messages such as to perform phone number verification.</p>
- *
- * <p>For more information about building SMS apps, read the blog post, <a
- * href="http://android-developers.blogspot.com/2013/10/getting-your-sms-apps-ready-for-kitkat.html"
- * >Getting Your SMS Apps Ready for KitKat</a>.</p>
- *
- */
-public final class Telephony {
-    private static final String TAG = "Telephony";
-
-    /**
-     * Not instantiable.
-     * @hide
-     */
-    private Telephony() {
-    }
-
-    /**
-     * Base columns for tables that contain text-based SMSs.
-     */
-    public interface TextBasedSmsColumns {
-
-        /** Message type: all messages. */
-        public static final int MESSAGE_TYPE_ALL    = 0;
-
-        /** Message type: inbox. */
-        public static final int MESSAGE_TYPE_INBOX  = 1;
-
-        /** Message type: sent messages. */
-        public static final int MESSAGE_TYPE_SENT   = 2;
-
-        /** Message type: drafts. */
-        public static final int MESSAGE_TYPE_DRAFT  = 3;
-
-        /** Message type: outbox. */
-        public static final int MESSAGE_TYPE_OUTBOX = 4;
-
-        /** Message type: failed outgoing message. */
-        public static final int MESSAGE_TYPE_FAILED = 5;
-
-        /** Message type: queued to send later. */
-        public static final int MESSAGE_TYPE_QUEUED = 6;
-
-        /**
-         * The type of message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * The thread ID of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String THREAD_ID = "thread_id";
-
-        /**
-         * The address of the other party.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ADDRESS = "address";
-
-        /**
-         * The date the message was received.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * The date the message was sent.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE_SENT = "date_sent";
-
-        /**
-         * Has the message been read?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * Has the message been seen by the user? The "seen" flag determines
-         * whether we need to show a notification.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String SEEN = "seen";
-
-        /**
-         * {@code TP-Status} value for the message, or -1 if no status has been received.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String STATUS = "status";
-
-        /** TP-Status: no status received. */
-        public static final int STATUS_NONE = -1;
-        /** TP-Status: complete. */
-        public static final int STATUS_COMPLETE = 0;
-        /** TP-Status: pending. */
-        public static final int STATUS_PENDING = 32;
-        /** TP-Status: failed. */
-        public static final int STATUS_FAILED = 64;
-
-        /**
-         * The subject of the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SUBJECT = "subject";
-
-        /**
-         * The body of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String BODY = "body";
-
-        /**
-         * The ID of the sender of the conversation, if present.
-         * <P>Type: INTEGER (reference to item in {@code content://contacts/people})</P>
-         */
-        public static final String PERSON = "person";
-
-        /**
-         * The protocol identifier code.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String PROTOCOL = "protocol";
-
-        /**
-         * Is the {@code TP-Reply-Path} flag set?
-         * <P>Type: BOOLEAN</P>
-         */
-        public static final String REPLY_PATH_PRESENT = "reply_path_present";
-
-        /**
-         * The service center (SC) through which to send the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SERVICE_CENTER = "service_center";
-
-        /**
-         * Is the message locked?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String LOCKED = "locked";
-
-        /**
-         * The subscription to which the message belongs to. Its value will be
-         * < 0 if the sub id cannot be determined.
-         * <p>Type: INTEGER (long) </p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The MTU size of the mobile interface to which the APN connected
-         * @hide
-         */
-        public static final String MTU = "mtu";
-
-        /**
-         * Error code associated with sending or receiving this message
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ERROR_CODE = "error_code";
-
-        /**
-         * The identity of the sender of a sent message. It is
-         * usually the package name of the app which sends the message.
-         * <p class="note"><strong>Note:</strong>
-         * This column is read-only. It is set by the provider and can not be changed by apps.
-         * <p>Type: TEXT</p>
-         */
-        public static final String CREATOR = "creator";
-    }
-
-    /**
-     * Contains all text-based SMS messages.
-     */
-    public static final class Sms implements BaseColumns, TextBasedSmsColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Sms() {
-        }
-
-        /**
-         * Used to determine the currently configured default SMS package.
-         * @param context context of the requesting application
-         * @return package name for the default SMS package or null
-         */
-        public static String getDefaultSmsPackage(Context context) {
-            ComponentName component = SmsApplication.getDefaultSmsApplication(context, false);
-            if (component != null) {
-                return component.getPackageName();
-            }
-            return null;
-        }
-
-        /**
-         * Return cursor for table query.
-         * @hide
-         */
-        public static Cursor query(ContentResolver cr, String[] projection) {
-            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
-        }
-
-        /**
-         * Return cursor for table query.
-         * @hide
-         */
-        public static Cursor query(ContentResolver cr, String[] projection,
-                String where, String orderBy) {
-            return cr.query(CONTENT_URI, projection, where,
-                    null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-        }
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://sms");
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-        /**
-         * Add an SMS to the given URI.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the pseudo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @return the URI for the new message
-         * @hide
-         */
-        public static Uri addMessageToUri(ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport) {
-            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                    resolver, uri, address, body, subject, date, read, deliveryReport, -1L);
-        }
-
-        /**
-         * Add an SMS to the given URI.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the psuedo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param subId the subscription which the message belongs to
-         * @return the URI for the new message
-         * @hide
-         */
-        public static Uri addMessageToUri(int subId, ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport) {
-            return addMessageToUri(subId, resolver, uri, address, body, subject,
-                    date, read, deliveryReport, -1L);
-        }
-
-        /**
-         * Add an SMS to the given URI with the specified thread ID.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the pseudo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param threadId the thread_id of the message
-         * @return the URI for the new message
-         * @hide
-         */
-        public static Uri addMessageToUri(ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport, long threadId) {
-            return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                    resolver, uri, address, body, subject,
-                    date, read, deliveryReport, threadId);
-        }
-
-        /**
-         * Add an SMS to the given URI with thread_id specified.
-         *
-         * @param resolver the content resolver to use
-         * @param uri the URI to add the message to
-         * @param address the address of the sender
-         * @param body the body of the message
-         * @param subject the psuedo-subject of the message
-         * @param date the timestamp for the message
-         * @param read true if the message has been read, false if not
-         * @param deliveryReport true if a delivery report was requested, false if not
-         * @param threadId the thread_id of the message
-         * @param subId the subscription which the message belongs to
-         * @return the URI for the new message
-         * @hide
-         */
-        public static Uri addMessageToUri(int subId, ContentResolver resolver,
-                Uri uri, String address, String body, String subject,
-                Long date, boolean read, boolean deliveryReport, long threadId) {
-            ContentValues values = new ContentValues(8);
-            Rlog.v(TAG,"Telephony addMessageToUri sub id: " + subId);
-
-            values.put(SUBSCRIPTION_ID, subId);
-            values.put(ADDRESS, address);
-            if (date != null) {
-                values.put(DATE, date);
-            }
-            values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
-            values.put(SUBJECT, subject);
-            values.put(BODY, body);
-            if (deliveryReport) {
-                values.put(STATUS, STATUS_PENDING);
-            }
-            if (threadId != -1L) {
-                values.put(THREAD_ID, threadId);
-            }
-            return resolver.insert(uri, values);
-        }
-
-        /**
-         * Move a message to the given folder.
-         *
-         * @param context the context to use
-         * @param uri the message to move
-         * @param folder the folder to move to
-         * @return true if the operation succeeded
-         * @hide
-         */
-        public static boolean moveMessageToFolder(Context context,
-                Uri uri, int folder, int error) {
-            if (uri == null) {
-                return false;
-            }
-
-            boolean markAsUnread = false;
-            boolean markAsRead = false;
-            switch(folder) {
-            case MESSAGE_TYPE_INBOX:
-            case MESSAGE_TYPE_DRAFT:
-                break;
-            case MESSAGE_TYPE_OUTBOX:
-            case MESSAGE_TYPE_SENT:
-                markAsRead = true;
-                break;
-            case MESSAGE_TYPE_FAILED:
-            case MESSAGE_TYPE_QUEUED:
-                markAsUnread = true;
-                break;
-            default:
-                return false;
-            }
-
-            ContentValues values = new ContentValues(3);
-
-            values.put(TYPE, folder);
-            if (markAsUnread) {
-                values.put(READ, 0);
-            } else if (markAsRead) {
-                values.put(READ, 1);
-            }
-            values.put(ERROR_CODE, error);
-
-            return 1 == SqliteWrapper.update(context, context.getContentResolver(),
-                            uri, values, null, null);
-        }
-
-        /**
-         * Returns true iff the folder (message type) identifies an
-         * outgoing message.
-         * @hide
-         */
-        public static boolean isOutgoingFolder(int messageType) {
-            return  (messageType == MESSAGE_TYPE_FAILED)
-                    || (messageType == MESSAGE_TYPE_OUTBOX)
-                    || (messageType == MESSAGE_TYPE_SENT)
-                    || (messageType == MESSAGE_TYPE_QUEUED);
-        }
-
-        /**
-         * Contains all text-based SMS messages in the SMS app inbox.
-         */
-        public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Inbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @param read true if the message has been read, false if not
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean read) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, read, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param read true if the message has been read, false if not
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date, boolean read) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, read, false);
-            }
-        }
-
-        /**
-         * Contains all sent text-based SMS messages in the SMS app.
-         */
-        public static final class Sent implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Sent() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/sent");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, true, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, false);
-            }
-        }
-
-        /**
-         * Contains all sent text-based SMS messages in the SMS app.
-         */
-        public static final class Draft implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Draft() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/draft");
-
-           /**
-            * @hide
-            */
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date, true, false);
-            }
-
-            /**
-             * Add an SMS to the Draft box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, false);
-            }
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all pending outgoing text-based SMS messages.
-         */
-        public static final class Outbox implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Outbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/outbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * Add an SMS to the outbox.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the pseudo-subject of the message
-             * @param date the timestamp for the message
-             * @param deliveryReport whether a delivery report was requested for the message
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean deliveryReport, long threadId) {
-                return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
-                        resolver, CONTENT_URI, address, body, subject, date,
-                        true, deliveryReport, threadId);
-            }
-
-            /**
-             * Add an SMS to the Out box.
-             *
-             * @param resolver the content resolver to use
-             * @param address the address of the sender
-             * @param body the body of the message
-             * @param subject the psuedo-subject of the message
-             * @param date the timestamp for the message
-             * @param deliveryReport whether a delivery report was requested for the message
-             * @param subId the subscription which the message belongs to
-             * @return the URI for the new message
-             * @hide
-             */
-            public static Uri addMessage(int subId, ContentResolver resolver,
-                    String address, String body, String subject, Long date,
-                    boolean deliveryReport, long threadId) {
-                return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
-                        subject, date, true, deliveryReport, threadId);
-            }
-        }
-
-        /**
-         * Contains all sent text-based SMS messages in the SMS app.
-         */
-        public static final class Conversations
-                implements BaseColumns, TextBasedSmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Conversations() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.parse("content://sms/conversations");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-            /**
-             * The first 45 characters of the body of the message.
-             * <P>Type: TEXT</P>
-             */
-            public static final String SNIPPET = "snippet";
-
-            /**
-             * The number of messages in the conversation.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MESSAGE_COUNT = "msg_count";
-        }
-
-        /**
-         * Contains constants for SMS related Intents that are broadcast.
-         */
-        public static final class Intents {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Intents() {
-            }
-
-            /**
-             * Set by BroadcastReceiver to indicate that the message was handled
-             * successfully.
-             */
-            public static final int RESULT_SMS_HANDLED = 1;
-
-            /**
-             * Set by BroadcastReceiver to indicate a generic error while
-             * processing the message.
-             */
-            public static final int RESULT_SMS_GENERIC_ERROR = 2;
-
-            /**
-             * Set by BroadcastReceiver to indicate insufficient memory to store
-             * the message.
-             */
-            public static final int RESULT_SMS_OUT_OF_MEMORY = 3;
-
-            /**
-             * Set by BroadcastReceiver to indicate that the message, while
-             * possibly valid, is of a format or encoding that is not
-             * supported.
-             */
-            public static final int RESULT_SMS_UNSUPPORTED = 4;
-
-            /**
-             * Set by BroadcastReceiver to indicate a duplicate incoming message.
-             */
-            public static final int RESULT_SMS_DUPLICATED = 5;
-
-            /**
-             * Activity action: Ask the user to change the default
-             * SMS application. This will show a dialog that asks the
-             * user whether they want to replace the current default
-             * SMS application with the one specified in
-             * {@link #EXTRA_PACKAGE_NAME}.
-             */
-            @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-            public static final String ACTION_CHANGE_DEFAULT =
-                    "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
-
-            /**
-             * The PackageName string passed in as an
-             * extra for {@link #ACTION_CHANGE_DEFAULT}
-             *
-             * @see #ACTION_CHANGE_DEFAULT
-             */
-            public static final String EXTRA_PACKAGE_NAME = "package";
-
-            /**
-             * Broadcast Action: A new text-based SMS message has been received
-             * by the device. This intent will only be delivered to the default
-             * sms app. That app is responsible for writing the message and notifying
-             * the user. The intent will have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             *   <li><em>"format"</em> - A String describing the format of the PDUs. It can
-             *   be either "3gpp" or "3gpp2".</li>
-             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
-             *   received the message.</li>
-             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
-             *   subscription.</li>
-             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
-             *   subscription.</li>
-             *   <li><em>"errorCode"</em> - An optional int error code associated with receiving
-             *   the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p class="note"><strong>Note:</strong>
-             * The broadcast receiver that filters for this intent must declare
-             * {@link android.Manifest.permission#BROADCAST_SMS} as a required permission in
-             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
-             * <receiver>}</a> tag.
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_DELIVER_ACTION =
-                    "android.provider.Telephony.SMS_DELIVER";
-
-            /**
-             * Broadcast Action: A new text-based SMS message has been received
-             * by the device. This intent will be delivered to all registered
-             * receivers as a notification. These apps are not expected to write the
-             * message or notify the user. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_RECEIVED";
-
-            /**
-             * Broadcast Action: A new data based SMS message has been received
-             * by the device. This intent will be delivered to all registered
-             * receivers as a notification. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
-             *   that make up the message.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String DATA_SMS_RECEIVED_ACTION =
-                    "android.intent.action.DATA_SMS_RECEIVED";
-
-            /**
-             * Broadcast Action: A new WAP PUSH message has been received by the
-             * device. This intent will only be delivered to the default
-             * sms app. That app is responsible for writing the message and notifying
-             * the user. The intent will have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
-             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
-             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
-             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
-             *   <li><em>"contentTypeParameters" </em>
-             *   -(HashMap&lt;String,String&gt;) Any parameters associated with the content type
-             *   (decoded from the WSP Content-Type header)</li>
-             *   <li><em>"subscription"</em> - An optional long value of the subscription id which
-             *   received the message.</li>
-             *   <li><em>"slot"</em> - An optional int value of the SIM slot containing the
-             *   subscription.</li>
-             *   <li><em>"phone"</em> - An optional int value of the phone id associated with the
-             *   subscription.</li>
-             * </ul>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>The contentTypeParameters extra value is map of content parameters keyed by
-             * their names.</p>
-             *
-             * <p>If any unassigned well-known parameters are encountered, the key of the map will
-             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
-             * a parameter has No-Value the value in the map will be null.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
-             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
-             * receive.</p>
-             *
-             * <p class="note"><strong>Note:</strong>
-             * The broadcast receiver that filters for this intent must declare
-             * {@link android.Manifest.permission#BROADCAST_WAP_PUSH} as a required permission in
-             * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
-             * <receiver>}</a> tag.
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String WAP_PUSH_DELIVER_ACTION =
-                    "android.provider.Telephony.WAP_PUSH_DELIVER";
-
-            /**
-             * Broadcast Action: A new WAP PUSH message has been received by the
-             * device. This intent will be delivered to all registered
-             * receivers as a notification. These apps are not expected to write the
-             * message or notify the user. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
-             *   <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
-             *   <li><em>"header"</em> - (byte[]) The header of the message</li>
-             *   <li><em>"data"</em> - (byte[]) The data payload of the message</li>
-             *   <li><em>"contentTypeParameters"</em>
-             *   - (HashMap&lt;String,String&gt;) Any parameters associated with the content type
-             *   (decoded from the WSP Content-Type header)</li>
-             * </ul>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>The contentTypeParameters extra value is map of content parameters keyed by
-             * their names.</p>
-             *
-             * <p>If any unassigned well-known parameters are encountered, the key of the map will
-             * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter.  If
-             * a parameter has No-Value the value in the map will be null.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
-             * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
-             * receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String WAP_PUSH_RECEIVED_ACTION =
-                    "android.provider.Telephony.WAP_PUSH_RECEIVED";
-
-            /**
-             * Broadcast Action: A new Cell Broadcast message has been received
-             * by the device. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
-             *   data. This is not an emergency alert, so ETWS and CMAS data will be null.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_CB_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_CB_RECEIVED";
-
-            /**
-             * Action: A SMS based carrier provision intent. Used to identify default
-             * carrier provisioning app on the device.
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            @TestApi
-            public static final String SMS_CARRIER_PROVISION_ACTION =
-                    "android.provider.Telephony.SMS_CARRIER_PROVISION";
-
-            /**
-             * Broadcast Action: A new Emergency Broadcast message has been received
-             * by the device. The intent will have the following extra
-             * values:</p>
-             *
-             * <ul>
-             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
-             *   data, including ETWS or CMAS warning notification info if present.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} to
-             * receive.</p>
-             * @removed
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
-
-            /**
-             * Broadcast Action: A new CDMA SMS has been received containing Service Category
-             * Program Data (updates the list of enabled broadcast channels). The intent will
-             * have the following extra values:</p>
-             *
-             * <ul>
-             *   <li><em>"operations"</em> - An array of CdmaSmsCbProgramData objects containing
-             *   the service category operations (add/delete/clear) to perform.</li>
-             * </ul>
-             *
-             * <p>The extra values can be extracted using
-             * {@link #getMessagesFromIntent(Intent)}.</p>
-             *
-             * <p>If a BroadcastReceiver encounters an error while processing
-             * this intent it should set the result code appropriately.</p>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
-
-            /**
-             * Broadcast Action: The SIM storage for SMS messages is full.  If
-             * space is not freed, messages targeted for the SIM (class 2) may
-             * not be saved.
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SIM_FULL_ACTION =
-                    "android.provider.Telephony.SIM_FULL";
-
-            /**
-             * Broadcast Action: An incoming SMS has been rejected by the
-             * telephony framework.  This intent is sent in lieu of any
-             * of the RECEIVED_ACTION intents.  The intent will have the
-             * following extra value:</p>
-             *
-             * <ul>
-             *   <li><em>"result"</em> - An int result code, e.g. {@link #RESULT_SMS_OUT_OF_MEMORY}
-             *   indicating the error returned to the network.</li>
-             * </ul>
-             *
-             * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_REJECTED_ACTION =
-                "android.provider.Telephony.SMS_REJECTED";
-
-            /**
-             * Broadcast Action: An incoming MMS has been downloaded. The intent is sent to all
-             * users, except for secondary users where SMS has been disabled and to managed
-             * profiles.
-             * @hide
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String MMS_DOWNLOADED_ACTION =
-                "android.provider.Telephony.MMS_DOWNLOADED";
-
-            /**
-             * Broadcast action: When the default SMS package changes,
-             * the previous default SMS package and the new default SMS
-             * package are sent this broadcast to notify them of the change.
-             * A boolean is specified in {@link #EXTRA_IS_DEFAULT_SMS_APP} to
-             * indicate whether the package is the new default SMS package.
-            */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED =
-                            "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
-
-            /**
-             * The IsDefaultSmsApp boolean passed as an
-             * extra for {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} to indicate whether the
-             * SMS app is becoming the default SMS app or is no longer the default.
-             *
-             * @see #ACTION_DEFAULT_SMS_PACKAGE_CHANGED
-             */
-            public static final String EXTRA_IS_DEFAULT_SMS_APP =
-                    "android.provider.extra.IS_DEFAULT_SMS_APP";
-
-            /**
-             * Broadcast action: When a change is made to the SmsProvider or
-             * MmsProvider by a process other than the default SMS application,
-             * this intent is broadcast to the default SMS application so it can
-             * re-sync or update the change. The uri that was used to call the provider
-             * can be retrieved from the intent with getData(). The actual affected uris
-             * (which would depend on the selection specified) are not included.
-            */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String ACTION_EXTERNAL_PROVIDER_CHANGE =
-                          "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
-
-            /**
-             * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
-             * {@link #DATA_SMS_RECEIVED_ACTION} intent.
-             *
-             * @param intent the intent to read from
-             * @return an array of SmsMessages for the PDUs
-             */
-            public static SmsMessage[] getMessagesFromIntent(Intent intent) {
-                Object[] messages;
-                try {
-                    messages = (Object[]) intent.getSerializableExtra("pdus");
-                }
-                catch (ClassCastException e) {
-                    Rlog.e(TAG, "getMessagesFromIntent: " + e);
-                    return null;
-                }
-
-                if (messages == null) {
-                    Rlog.e(TAG, "pdus does not exist in the intent");
-                    return null;
-                }
-
-                String format = intent.getStringExtra("format");
-                int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
-                        SubscriptionManager.getDefaultSmsSubscriptionId());
-
-                Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
-
-                int pduCount = messages.length;
-                SmsMessage[] msgs = new SmsMessage[pduCount];
-
-                for (int i = 0; i < pduCount; i++) {
-                    byte[] pdu = (byte[]) messages[i];
-                    msgs[i] = SmsMessage.createFromPdu(pdu, format);
-                    if (msgs[i] != null) msgs[i].setSubId(subId);
-                }
-                return msgs;
-            }
-        }
-    }
-
-    /**
-     * Base columns for tables that contain MMSs.
-     */
-    public interface BaseMmsColumns extends BaseColumns {
-
-        /** Message box: all messages. */
-        public static final int MESSAGE_BOX_ALL    = 0;
-        /** Message box: inbox. */
-        public static final int MESSAGE_BOX_INBOX  = 1;
-        /** Message box: sent messages. */
-        public static final int MESSAGE_BOX_SENT   = 2;
-        /** Message box: drafts. */
-        public static final int MESSAGE_BOX_DRAFTS = 3;
-        /** Message box: outbox. */
-        public static final int MESSAGE_BOX_OUTBOX = 4;
-        /** Message box: failed. */
-        public static final int MESSAGE_BOX_FAILED = 5;
-
-        /**
-         * The thread ID of the message.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String THREAD_ID = "thread_id";
-
-        /**
-         * The date the message was received.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * The date the message was sent.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE_SENT = "date_sent";
-
-        /**
-         * The box which the message belongs to, e.g. {@link #MESSAGE_BOX_INBOX}.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_BOX = "msg_box";
-
-        /**
-         * Has the message been read?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * Has the message been seen by the user? The "seen" flag determines
-         * whether we need to show a new message notification.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String SEEN = "seen";
-
-        /**
-         * Does the message have only a text part (can also have a subject) with
-         * no picture, slideshow, sound, etc. parts?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String TEXT_ONLY = "text_only";
-
-        /**
-         * The {@code Message-ID} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_ID = "m_id";
-
-        /**
-         * The subject of the message, if present.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SUBJECT = "sub";
-
-        /**
-         * The character set of the subject, if present.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SUBJECT_CHARSET = "sub_cs";
-
-        /**
-         * The {@code Content-Type} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String CONTENT_TYPE = "ct_t";
-
-        /**
-         * The {@code Content-Location} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String CONTENT_LOCATION = "ct_l";
-
-        /**
-         * The expiry time of the message.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String EXPIRY = "exp";
-
-        /**
-         * The class of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_CLASS = "m_cls";
-
-        /**
-         * The type of the message defined by MMS spec.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_TYPE = "m_type";
-
-        /**
-         * The version of the specification that this message conforms to.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MMS_VERSION = "v";
-
-        /**
-         * The size of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_SIZE = "m_size";
-
-        /**
-         * The priority of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String PRIORITY = "pri";
-
-        /**
-         * The {@code read-report} of the message.
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String READ_REPORT = "rr";
-
-        /**
-         * Is read report allowed?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String REPORT_ALLOWED = "rpt_a";
-
-        /**
-         * The {@code response-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RESPONSE_STATUS = "resp_st";
-
-        /**
-         * The {@code status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String STATUS = "st";
-
-        /**
-         * The {@code transaction-id} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String TRANSACTION_ID = "tr_id";
-
-        /**
-         * The {@code retrieve-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RETRIEVE_STATUS = "retr_st";
-
-        /**
-         * The {@code retrieve-text} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RETRIEVE_TEXT = "retr_txt";
-
-        /**
-         * The character set of the retrieve-text.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
-
-        /**
-         * The {@code read-status} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String READ_STATUS = "read_status";
-
-        /**
-         * The {@code content-class} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CONTENT_CLASS = "ct_cls";
-
-        /**
-         * The {@code delivery-report} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String DELIVERY_REPORT = "d_rpt";
-
-        /**
-         * The {@code delivery-time-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DELIVERY_TIME_TOKEN = "d_tm_tok";
-
-        /**
-         * The {@code delivery-time} of the message.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String DELIVERY_TIME = "d_tm";
-
-        /**
-         * The {@code response-text} of the message.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RESPONSE_TEXT = "resp_txt";
-
-        /**
-         * The {@code sender-visibility} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String SENDER_VISIBILITY = "s_vis";
-
-        /**
-         * The {@code reply-charging} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING = "r_chg";
-
-        /**
-         * The {@code reply-charging-deadline-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok";
-
-        /**
-         * The {@code reply-charging-deadline} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl";
-
-        /**
-         * The {@code reply-charging-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_ID = "r_chg_id";
-
-        /**
-         * The {@code reply-charging-size} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_CHARGING_SIZE = "r_chg_sz";
-
-        /**
-         * The {@code previously-sent-by} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String PREVIOUSLY_SENT_BY = "p_s_by";
-
-        /**
-         * The {@code previously-sent-date} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String PREVIOUSLY_SENT_DATE = "p_s_d";
-
-        /**
-         * The {@code store} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE = "store";
-
-        /**
-         * The {@code mm-state} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_STATE = "mm_st";
-
-        /**
-         * The {@code mm-flags-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_FLAGS_TOKEN = "mm_flg_tok";
-
-        /**
-         * The {@code mm-flags} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MM_FLAGS = "mm_flg";
-
-        /**
-         * The {@code store-status} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE_STATUS = "store_st";
-
-        /**
-         * The {@code store-status-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORE_STATUS_TEXT = "store_st_txt";
-
-        /**
-         * The {@code stored} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STORED = "stored";
-
-        /**
-         * The {@code totals} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String TOTALS = "totals";
-
-        /**
-         * The {@code mbox-totals} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_TOTALS = "mb_t";
-
-        /**
-         * The {@code mbox-totals-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_TOTALS_TOKEN = "mb_t_tok";
-
-        /**
-         * The {@code quotas} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String QUOTAS = "qt";
-
-        /**
-         * The {@code mbox-quotas} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_QUOTAS = "mb_qt";
-
-        /**
-         * The {@code mbox-quotas-token} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok";
-
-        /**
-         * The {@code message-count} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String MESSAGE_COUNT = "m_cnt";
-
-        /**
-         * The {@code start} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String START = "start";
-
-        /**
-         * The {@code distribution-indicator} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DISTRIBUTION_INDICATOR = "d_ind";
-
-        /**
-         * The {@code element-descriptor} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String ELEMENT_DESCRIPTOR = "e_des";
-
-        /**
-         * The {@code limit} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String LIMIT = "limit";
-
-        /**
-         * The {@code recommended-retrieval-mode} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod";
-
-        /**
-         * The {@code recommended-retrieval-mode-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt";
-
-        /**
-         * The {@code status-text} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String STATUS_TEXT = "st_txt";
-
-        /**
-         * The {@code applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String APPLIC_ID = "apl_id";
-
-        /**
-         * The {@code reply-applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLY_APPLIC_ID = "r_apl_id";
-
-        /**
-         * The {@code aux-applic-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String AUX_APPLIC_ID = "aux_apl_id";
-
-        /**
-         * The {@code drm-content} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String DRM_CONTENT = "drm_c";
-
-        /**
-         * The {@code adaptation-allowed} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String ADAPTATION_ALLOWED = "adp_a";
-
-        /**
-         * The {@code replace-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String REPLACE_ID = "repl_id";
-
-        /**
-         * The {@code cancel-id} of the message.
-         * <P>Type: TEXT</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String CANCEL_ID = "cl_id";
-
-        /**
-         * The {@code cancel-status} of the message.
-         * <P>Type: INTEGER</P>
-         * @deprecated this column is no longer supported.
-         * @hide
-         */
-        @Deprecated
-        public static final String CANCEL_STATUS = "cl_st";
-
-        /**
-         * Is the message locked?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String LOCKED = "locked";
-
-        /**
-         * The subscription to which the message belongs to. Its value will be
-         * < 0 if the sub id cannot be determined.
-         * <p>Type: INTEGER (long)</p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The identity of the sender of a sent message. It is
-         * usually the package name of the app which sends the message.
-         * <p class="note"><strong>Note:</strong>
-         * This column is read-only. It is set by the provider and can not be changed by apps.
-         * <p>Type: TEXT</p>
-         */
-        public static final String CREATOR = "creator";
-    }
-
-    /**
-     * Columns for the "canonical_addresses" table used by MMS and SMS.
-     */
-    public interface CanonicalAddressesColumns extends BaseColumns {
-        /**
-         * An address used in MMS or SMS.  Email addresses are
-         * converted to lower case and are compared by string
-         * equality.  Other addresses are compared using
-         * PHONE_NUMBERS_EQUAL.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ADDRESS = "address";
-    }
-
-    /**
-     * Columns for the "threads" table used by MMS and SMS.
-     */
-    public interface ThreadsColumns extends BaseColumns {
-
-        /**
-         * The date at which the thread was created.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DATE = "date";
-
-        /**
-         * A string encoding of the recipient IDs of the recipients of
-         * the message, in numerical order and separated by spaces.
-         * <P>Type: TEXT</P>
-         */
-        public static final String RECIPIENT_IDS = "recipient_ids";
-
-        /**
-         * The message count of the thread.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_COUNT = "message_count";
-
-        /**
-         * Indicates whether all messages of the thread have been read.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String READ = "read";
-
-        /**
-         * The snippet of the latest message in the thread.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SNIPPET = "snippet";
-
-        /**
-         * The charset of the snippet.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SNIPPET_CHARSET = "snippet_cs";
-
-        /**
-         * Type of the thread, either {@link Threads#COMMON_THREAD} or
-         * {@link Threads#BROADCAST_THREAD}.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * Indicates whether there is a transmission error in the thread.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ERROR = "error";
-
-        /**
-         * Indicates whether this thread contains any attachments.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String HAS_ATTACHMENT = "has_attachment";
-
-        /**
-         * If the thread is archived
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String ARCHIVED = "archived";
-    }
-
-    /**
-     * Helper functions for the "threads" table used by MMS and SMS.
-     */
-    public static final class Threads implements ThreadsColumns {
-
-        private static final String[] ID_PROJECTION = { BaseColumns._ID };
-
-        /**
-         * Private {@code content://} style URL for this table. Used by
-         * {@link #getOrCreateThreadId(android.content.Context, java.util.Set)}.
-         */
-        private static final Uri THREAD_ID_CONTENT_URI = Uri.parse(
-                "content://mms-sms/threadID");
-
-        /**
-         * The {@code content://} style URL for this table, by conversation.
-         */
-        public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                MmsSms.CONTENT_URI, "conversations");
-
-        /**
-         * The {@code content://} style URL for this table, for obsolete threads.
-         */
-        public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath(
-                CONTENT_URI, "obsolete");
-
-        /** Thread type: common thread. */
-        public static final int COMMON_THREAD    = 0;
-
-        /** Thread type: broadcast thread. */
-        public static final int BROADCAST_THREAD = 1;
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Threads() {
-        }
-
-        /**
-         * This is a single-recipient version of {@code getOrCreateThreadId}.
-         * It's convenient for use with SMS messages.
-         * @param context the context object to use.
-         * @param recipient the recipient to send to.
-         */
-        public static long getOrCreateThreadId(Context context, String recipient) {
-            Set<String> recipients = new HashSet<String>();
-
-            recipients.add(recipient);
-            return getOrCreateThreadId(context, recipients);
-        }
-
-        /**
-         * Given the recipients list and subject of an unsaved message,
-         * return its thread ID.  If the message starts a new thread,
-         * allocate a new thread ID.  Otherwise, use the appropriate
-         * existing thread ID.
-         *
-         * <p>Find the thread ID of the same set of recipients (in any order,
-         * without any additions). If one is found, return it. Otherwise,
-         * return a unique thread ID.</p>
-         */
-        public static long getOrCreateThreadId(
-                Context context, Set<String> recipients) {
-            Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
-
-            for (String recipient : recipients) {
-                if (Mms.isEmailAddress(recipient)) {
-                    recipient = Mms.extractAddrSpec(recipient);
-                }
-
-                uriBuilder.appendQueryParameter("recipient", recipient);
-            }
-
-            Uri uri = uriBuilder.build();
-            //if (DEBUG) Rlog.v(TAG, "getOrCreateThreadId uri: " + uri);
-
-            Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
-                    uri, ID_PROJECTION, null, null, null);
-            if (cursor != null) {
-                try {
-                    if (cursor.moveToFirst()) {
-                        return cursor.getLong(0);
-                    } else {
-                        Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
-                    }
-                } finally {
-                    cursor.close();
-                }
-            }
-
-            Rlog.e(TAG, "getOrCreateThreadId failed with " + recipients.size() + " recipients");
-            throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
-        }
-    }
-
-    /**
-     * Contains all MMS messages.
-     */
-    public static final class Mms implements BaseMmsColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Mms() {
-        }
-
-        /**
-         * The {@code content://} URI for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://mms");
-
-        /**
-         * Content URI for getting MMS report requests.
-         */
-        public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath(
-                                            CONTENT_URI, "report-request");
-
-        /**
-         * Content URI for getting MMS report status.
-         */
-        public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath(
-                                            CONTENT_URI, "report-status");
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "date DESC";
-
-        /**
-         * Regex pattern for names and email addresses.
-         * <ul>
-         *     <li><em>mailbox</em> = {@code name-addr}</li>
-         *     <li><em>name-addr</em> = {@code [display-name] angle-addr}</li>
-         *     <li><em>angle-addr</em> = {@code [CFWS] "<" addr-spec ">" [CFWS]}</li>
-         * </ul>
-         * @hide
-         */
-        public static final Pattern NAME_ADDR_EMAIL_PATTERN =
-                Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
-
-        /**
-         * Helper method to query this table.
-         * @hide
-         */
-        public static Cursor query(
-                ContentResolver cr, String[] projection) {
-            return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
-        }
-
-        /**
-         * Helper method to query this table.
-         * @hide
-         */
-        public static Cursor query(
-                ContentResolver cr, String[] projection,
-                String where, String orderBy) {
-            return cr.query(CONTENT_URI, projection,
-                    where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
-        }
-
-        /**
-         * Helper method to extract email address from address string.
-         * @hide
-         */
-        public static String extractAddrSpec(String address) {
-            Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address);
-
-            if (match.matches()) {
-                return match.group(2);
-            }
-            return address;
-        }
-
-        /**
-         * Is the specified address an email address?
-         *
-         * @param address the input address to test
-         * @return true if address is an email address; false otherwise.
-         * @hide
-         */
-        public static boolean isEmailAddress(String address) {
-            if (TextUtils.isEmpty(address)) {
-                return false;
-            }
-
-            String s = extractAddrSpec(address);
-            Matcher match = Patterns.EMAIL_ADDRESS.matcher(s);
-            return match.matches();
-        }
-
-        /**
-         * Is the specified number a phone number?
-         *
-         * @param number the input number to test
-         * @return true if number is a phone number; false otherwise.
-         * @hide
-         */
-        public static boolean isPhoneNumber(String number) {
-            if (TextUtils.isEmpty(number)) {
-                return false;
-            }
-
-            Matcher match = Patterns.PHONE.matcher(number);
-            return match.matches();
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app inbox.
-         */
-        public static final class Inbox implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Inbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/inbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app sent folder.
-         */
-        public static final class Sent implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Sent() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/sent");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app drafts folder.
-         */
-        public static final class Draft implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Draft() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/drafts");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains all MMS messages in the MMS app outbox.
-         */
-        public static final class Outbox implements BaseMmsColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Outbox() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri
-                    CONTENT_URI = Uri.parse("content://mms/outbox");
-
-            /**
-             * The default sort order for this table.
-             */
-            public static final String DEFAULT_SORT_ORDER = "date DESC";
-        }
-
-        /**
-         * Contains address information for an MMS message.
-         */
-        public static final class Addr implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Addr() {
-            }
-
-            /**
-             * The ID of MM which this address entry belongs to.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String MSG_ID = "msg_id";
-
-            /**
-             * The ID of contact entry in Phone Book.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String CONTACT_ID = "contact_id";
-
-            /**
-             * The address text.
-             * <P>Type: TEXT</P>
-             */
-            public static final String ADDRESS = "address";
-
-            /**
-             * Type of address: must be one of {@code PduHeaders.BCC},
-             * {@code PduHeaders.CC}, {@code PduHeaders.FROM}, {@code PduHeaders.TO}.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String TYPE = "type";
-
-            /**
-             * Character set of this entry (MMS charset value).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CHARSET = "charset";
-        }
-
-        /**
-         * Contains message parts.
-         */
-        public static final class Part implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Part() {
-            }
-
-            /**
-             * The identifier of the message which this part belongs to.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MSG_ID = "mid";
-
-            /**
-             * The order of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String SEQ = "seq";
-
-            /**
-             * The content type of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CONTENT_TYPE = "ct";
-
-            /**
-             * The name of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String NAME = "name";
-
-            /**
-             * The charset of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CHARSET = "chset";
-
-            /**
-             * The file name of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String FILENAME = "fn";
-
-            /**
-             * The content disposition of the part.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CONTENT_DISPOSITION = "cd";
-
-            /**
-             * The content ID of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CONTENT_ID = "cid";
-
-            /**
-             * The content location of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CONTENT_LOCATION = "cl";
-
-            /**
-             * The start of content-type of the message.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String CT_START = "ctt_s";
-
-            /**
-             * The type of content-type of the message.
-             * <P>Type: TEXT</P>
-             */
-            public static final String CT_TYPE = "ctt_t";
-
-            /**
-             * The location (on filesystem) of the binary data of the part.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String _DATA = "_data";
-
-            /**
-             * The message text.
-             * <P>Type: TEXT</P>
-             */
-            public static final String TEXT = "text";
-        }
-
-        /**
-         * Message send rate table.
-         */
-        public static final class Rate {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Rate() {
-            }
-
-            /**
-             * The {@code content://} style URL for this table.
-             */
-            public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                    Mms.CONTENT_URI, "rate");
-
-            /**
-             * When a message was successfully sent.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String SENT_TIME = "sent_time";
-        }
-
-        /**
-         * Intents class.
-         */
-        public static final class Intents {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private Intents() {
-            }
-
-            /**
-             * Indicates that the contents of specified URIs were changed.
-             * The application which is showing or caching these contents
-             * should be updated.
-             */
-            @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String CONTENT_CHANGED_ACTION
-                    = "android.intent.action.CONTENT_CHANGED";
-
-            /**
-             * An extra field which stores the URI of deleted contents.
-             */
-            public static final String DELETED_CONTENTS = "deleted_contents";
-        }
-    }
-
-    /**
-     * Contains all MMS and SMS messages.
-     */
-    public static final class MmsSms implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private MmsSms() {
-        }
-
-        /**
-         * The column to distinguish SMS and MMS messages in query results.
-         */
-        public static final String TYPE_DISCRIMINATOR_COLUMN =
-                "transport_type";
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/");
-
-        /**
-         * The {@code content://} style URL for this table, by conversation.
-         */
-        public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse(
-                "content://mms-sms/conversations");
-
-        /**
-         * The {@code content://} style URL for this table, by phone number.
-         */
-        public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse(
-                "content://mms-sms/messages/byphone");
-
-        /**
-         * The {@code content://} style URL for undelivered messages in this table.
-         */
-        public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse(
-                "content://mms-sms/undelivered");
-
-        /**
-         * The {@code content://} style URL for draft messages in this table.
-         */
-        public static final Uri CONTENT_DRAFT_URI = Uri.parse(
-                "content://mms-sms/draft");
-
-        /**
-         * The {@code content://} style URL for locked messages in this table.
-         */
-        public static final Uri CONTENT_LOCKED_URI = Uri.parse(
-                "content://mms-sms/locked");
-
-        /**
-         * Pass in a query parameter called "pattern" which is the text to search for.
-         * The sort order is fixed to be: {@code thread_id ASC, date DESC}.
-         */
-        public static final Uri SEARCH_URI = Uri.parse(
-                "content://mms-sms/search");
-
-        // Constants for message protocol types.
-
-        /** SMS protocol type. */
-        public static final int SMS_PROTO = 0;
-
-        /** MMS protocol type. */
-        public static final int MMS_PROTO = 1;
-
-        // Constants for error types of pending messages.
-
-        /** Error type: no error. */
-        public static final int NO_ERROR                      = 0;
-
-        /** Error type: generic transient error. */
-        public static final int ERR_TYPE_GENERIC              = 1;
-
-        /** Error type: SMS protocol transient error. */
-        public static final int ERR_TYPE_SMS_PROTO_TRANSIENT  = 2;
-
-        /** Error type: MMS protocol transient error. */
-        public static final int ERR_TYPE_MMS_PROTO_TRANSIENT  = 3;
-
-        /** Error type: transport failure. */
-        public static final int ERR_TYPE_TRANSPORT_FAILURE    = 4;
-
-        /** Error type: permanent error (along with all higher error values). */
-        public static final int ERR_TYPE_GENERIC_PERMANENT    = 10;
-
-        /** Error type: SMS protocol permanent error. */
-        public static final int ERR_TYPE_SMS_PROTO_PERMANENT  = 11;
-
-        /** Error type: MMS protocol permanent error. */
-        public static final int ERR_TYPE_MMS_PROTO_PERMANENT  = 12;
-
-        /**
-         * Contains pending messages info.
-         */
-        public static final class PendingMessages implements BaseColumns {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private PendingMessages() {
-            }
-
-            public static final Uri CONTENT_URI = Uri.withAppendedPath(
-                    MmsSms.CONTENT_URI, "pending");
-
-            /**
-             * The type of transport protocol (MMS or SMS).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String PROTO_TYPE = "proto_type";
-
-            /**
-             * The ID of the message to be sent or downloaded.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String MSG_ID = "msg_id";
-
-            /**
-             * The type of the message to be sent or downloaded.
-             * This field is only valid for MM. For SM, its value is always set to 0.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String MSG_TYPE = "msg_type";
-
-            /**
-             * The type of the error code.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String ERROR_TYPE = "err_type";
-
-            /**
-             * The error code of sending/retrieving process.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String ERROR_CODE = "err_code";
-
-            /**
-             * How many times we tried to send or download the message.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String RETRY_INDEX = "retry_index";
-
-            /**
-             * The time to do next retry.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String DUE_TIME = "due_time";
-
-            /**
-             * The time we last tried to send or download the message.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String LAST_TRY = "last_try";
-
-            /**
-             * The subscription to which the message belongs to. Its value will be
-             * < 0 if the sub id cannot be determined.
-             * <p>Type: INTEGER (long) </p>
-             */
-            public static final String SUBSCRIPTION_ID = "pending_sub_id";
-        }
-
-        /**
-         * Words table used by provider for full-text searches.
-         * @hide
-         */
-        public static final class WordsTable {
-
-            /**
-             * Not instantiable.
-             * @hide
-             */
-            private WordsTable() {}
-
-            /**
-             * Primary key.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String ID = "_id";
-
-            /**
-             * Source row ID.
-             * <P>Type: INTEGER (long)</P>
-             */
-            public static final String SOURCE_ROW_ID = "source_id";
-
-            /**
-             * Table ID (either 1 or 2).
-             * <P>Type: INTEGER</P>
-             */
-            public static final String TABLE_ID = "table_to_use";
-
-            /**
-             * The words to index.
-             * <P>Type: TEXT</P>
-             */
-            public static final String INDEXED_TEXT = "index_text";
-        }
-    }
-
-    /**
-     * Carriers class contains information about APNs, including MMSC information.
-     */
-    public static final class Carriers implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private Carriers() {}
-
-        /**
-         * The {@code content://} style URL for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
-
-        /**
-         * The default sort order for this table.
-         */
-        public static final String DEFAULT_SORT_ORDER = "name ASC";
-
-        /**
-         * Entry name.
-         * <P>Type: TEXT</P>
-         */
-        public static final String NAME = "name";
-
-        /**
-         * APN name.
-         * <P>Type: TEXT</P>
-         */
-        public static final String APN = "apn";
-
-        /**
-         * Proxy address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PROXY = "proxy";
-
-        /**
-         * Proxy port.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PORT = "port";
-
-        /**
-         * MMS proxy address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSPROXY = "mmsproxy";
-
-        /**
-         * MMS proxy port.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSPORT = "mmsport";
-
-        /**
-         * Server address.
-         * <P>Type: TEXT</P>
-         */
-        public static final String SERVER = "server";
-
-        /**
-         * APN username.
-         * <P>Type: TEXT</P>
-         */
-        public static final String USER = "user";
-
-        /**
-         * APN password.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PASSWORD = "password";
-
-        /**
-         * MMSC URL.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MMSC = "mmsc";
-
-        /**
-         * Mobile Country Code (MCC).
-         * <P>Type: TEXT</P>
-         */
-        public static final String MCC = "mcc";
-
-        /**
-         * Mobile Network Code (MNC).
-         * <P>Type: TEXT</P>
-         */
-        public static final String MNC = "mnc";
-
-        /**
-         * Numeric operator ID (as String). Usually {@code MCC + MNC}.
-         * <P>Type: TEXT</P>
-         */
-        public static final String NUMERIC = "numeric";
-
-        /**
-         * Authentication type.
-         * <P>Type:  INTEGER</P>
-         */
-        public static final String AUTH_TYPE = "authtype";
-
-        /**
-         * Comma-delimited list of APN types.
-         * <P>Type: TEXT</P>
-         */
-        public static final String TYPE = "type";
-
-        /**
-         * The protocol to use to connect to this APN.
-         *
-         * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
-         * For example: {@code IP}, {@code IPV6}, {@code IPV4V6}, or {@code PPP}.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PROTOCOL = "protocol";
-
-        /**
-         * The protocol to use to connect to this APN when roaming.
-         * The syntax is the same as protocol.
-         * <P>Type: TEXT</P>
-         */
-        public static final String ROAMING_PROTOCOL = "roaming_protocol";
-
-        /**
-         * Is this the current APN?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String CURRENT = "current";
-
-        /**
-         * Is this APN enabled?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String CARRIER_ENABLED = "carrier_enabled";
-
-        /**
-         * Radio Access Technology info.
-         * To check what values are allowed, refer to {@link android.telephony.ServiceState}.
-         * This should be spread to other technologies,
-         * but is currently only used for LTE (14) and eHRPD (13).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String BEARER = "bearer";
-
-        /**
-         * Radio Access Technology bitmask.
-         * To check what values can be contained, refer to {@link android.telephony.ServiceState}.
-         * 0 indicates all techs otherwise first bit refers to RAT/bearer 1, second bit refers to
-         * RAT/bearer 2 and so on.
-         * Bitmask for a radio tech R is (1 << (R - 1))
-         * <P>Type: INTEGER</P>
-         * @hide
-         */
-        public static final String BEARER_BITMASK = "bearer_bitmask";
-
-        /**
-         * MVNO type:
-         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MVNO_TYPE = "mvno_type";
-
-        /**
-         * MVNO data.
-         * Use the following examples.
-         * <ul>
-         *     <li>SPN: A MOBILE, BEN NL, ...</li>
-         *     <li>IMSI: 302720x94, 2060188, ...</li>
-         *     <li>GID: 4E, 33, ...</li>
-         * </ul>
-         * <P>Type: TEXT</P>
-         */
-        public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
-        /**
-         * The subscription to which the APN belongs to
-         * <p>Type: INTEGER (long) </p>
-         */
-        public static final String SUBSCRIPTION_ID = "sub_id";
-
-        /**
-         * The profile_id to which the APN saved in modem
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        public static final String PROFILE_ID = "profile_id";
-
-        /**
-         * Is the apn setting to be set in modem
-         * <P>Type: INTEGER (boolean)</P>
-         *@hide
-         */
-        public static final String MODEM_COGNITIVE = "modem_cognitive";
-
-        /**
-         * The max connections of this apn
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        public static final String MAX_CONNS = "max_conns";
-
-        /**
-         * The wait time for retry of the apn
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        public static final String WAIT_TIME = "wait_time";
-
-        /**
-         * The time to limit max connection for the apn
-         * <p>Type: INTEGER</p>
-         *@hide
-         */
-        public static final String MAX_CONNS_TIME = "max_conns_time";
-
-        /**
-         * The MTU size of the mobile interface to  which the APN connected
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        public static final String MTU = "mtu";
-
-        /**
-         * Is this APN added/edited/deleted by a user or carrier?
-         * <p>Type: INTEGER </p>
-         * @hide
-         */
-        public static final String EDITED = "edited";
-
-        /**
-         * Is this APN visible to the user?
-         * <p>Type: INTEGER (boolean) </p>
-         * @hide
-         */
-        public static final String USER_VISIBLE = "user_visible";
-
-        /**
-         * Following are possible values for the EDITED field
-         * @hide
-         */
-        public static final int UNEDITED = 0;
-        /**
-         *  @hide
-         */
-        public static final int USER_EDITED = 1;
-        /**
-         *  @hide
-         */
-        public static final int USER_DELETED = 2;
-        /**
-         * DELETED_BUT_PRESENT is an intermediate value used to indicate that an entry deleted
-         * by the user is still present in the new APN database and therefore must remain tagged
-         * as user deleted rather than completely removed from the database
-         * @hide
-         */
-        public static final int USER_DELETED_BUT_PRESENT_IN_XML = 3;
-        /**
-         *  @hide
-         */
-        public static final int CARRIER_EDITED = 4;
-        /**
-         * CARRIER_DELETED values are currently not used as there is no usecase. If they are used,
-         * delete() will have to change accordingly. Currently it is hardcoded to USER_DELETED.
-         * @hide
-         */
-        public static final int CARRIER_DELETED = 5;
-        /**
-         *  @hide
-         */
-        public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
-    }
-
-    /**
-     * Contains received SMS cell broadcast messages.
-     * @hide
-     */
-    public static final class CellBroadcasts implements BaseColumns {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private CellBroadcasts() {}
-
-        /**
-         * The {@code content://} URI for this table.
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
-
-        /**
-         * Message geographical scope.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
-
-        /**
-         * Message serial number.
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SERIAL_NUMBER = "serial_number";
-
-        /**
-         * PLMN of broadcast sender. {@code SERIAL_NUMBER + PLMN + LAC + CID} uniquely identifies
-         * a broadcast for duplicate detection purposes.
-         * <P>Type: TEXT</P>
-         */
-        public static final String PLMN = "plmn";
-
-        /**
-         * Location Area (GSM) or Service Area (UMTS) of broadcast sender. Unused for CDMA.
-         * Only included if Geographical Scope of message is not PLMN wide (01).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String LAC = "lac";
-
-        /**
-         * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the
-         * Geographical Scope of message is cell wide (00 or 11).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CID = "cid";
-
-        /**
-         * Message code. <em>OBSOLETE: merged into SERIAL_NUMBER.</em>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String V1_MESSAGE_CODE = "message_code";
-
-        /**
-         * Message identifier. <em>OBSOLETE: renamed to SERVICE_CATEGORY.</em>
-         * <P>Type: INTEGER</P>
-         */
-        public static final String V1_MESSAGE_IDENTIFIER = "message_id";
-
-        /**
-         * Service category (GSM/UMTS: message identifier; CDMA: service category).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String SERVICE_CATEGORY = "service_category";
-
-        /**
-         * Message language code.
-         * <P>Type: TEXT</P>
-         */
-        public static final String LANGUAGE_CODE = "language";
-
-        /**
-         * Message body.
-         * <P>Type: TEXT</P>
-         */
-        public static final String MESSAGE_BODY = "body";
-
-        /**
-         * Message delivery time.
-         * <P>Type: INTEGER (long)</P>
-         */
-        public static final String DELIVERY_TIME = "date";
-
-        /**
-         * Has the message been viewed?
-         * <P>Type: INTEGER (boolean)</P>
-         */
-        public static final String MESSAGE_READ = "read";
-
-        /**
-         * Message format (3GPP or 3GPP2).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_FORMAT = "format";
-
-        /**
-         * Message priority (including emergency).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String MESSAGE_PRIORITY = "priority";
-
-        /**
-         * ETWS warning type (ETWS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String ETWS_WARNING_TYPE = "etws_warning_type";
-
-        /**
-         * CMAS message class (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
-
-        /**
-         * CMAS category (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_CATEGORY = "cmas_category";
-
-        /**
-         * CMAS response type (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
-
-        /**
-         * CMAS severity (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_SEVERITY = "cmas_severity";
-
-        /**
-         * CMAS urgency (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_URGENCY = "cmas_urgency";
-
-        /**
-         * CMAS certainty (CMAS alerts only).
-         * <P>Type: INTEGER</P>
-         */
-        public static final String CMAS_CERTAINTY = "cmas_certainty";
-
-        /** The default sort order for this table. */
-        public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC";
-
-        /**
-         * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects.
-         */
-        public static final String[] QUERY_COLUMNS = {
-                _ID,
-                GEOGRAPHICAL_SCOPE,
-                PLMN,
-                LAC,
-                CID,
-                SERIAL_NUMBER,
-                SERVICE_CATEGORY,
-                LANGUAGE_CODE,
-                MESSAGE_BODY,
-                DELIVERY_TIME,
-                MESSAGE_READ,
-                MESSAGE_FORMAT,
-                MESSAGE_PRIORITY,
-                ETWS_WARNING_TYPE,
-                CMAS_MESSAGE_CLASS,
-                CMAS_CATEGORY,
-                CMAS_RESPONSE_TYPE,
-                CMAS_SEVERITY,
-                CMAS_URGENCY,
-                CMAS_CERTAINTY
-        };
-    }
-}
diff --git a/src/java/android/telephony/SmsCbCmasInfo.java b/src/java/android/telephony/SmsCbCmasInfo.java
deleted file mode 100644
index c912924..0000000
--- a/src/java/android/telephony/SmsCbCmasInfo.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * 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 android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Contains CMAS warning notification Type 1 elements for a {@link SmsCbMessage}.
- * Supported values for each element are defined in TIA-1149-0-1 (CMAS over CDMA) and
- * 3GPP TS 23.041 (for GSM/UMTS).
- *
- * {@hide}
- */
-public class SmsCbCmasInfo implements Parcelable {
-
-    // CMAS message class (in GSM/UMTS message identifier or CDMA service category).
-
-    /** Presidential-level alert (Korean Public Alert System Class 0 message). */
-    public static final int CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT = 0x00;
-
-    /** Extreme threat to life and property (Korean Public Alert System Class 1 message). */
-    public static final int CMAS_CLASS_EXTREME_THREAT = 0x01;
-
-    /** Severe threat to life and property (Korean Public Alert System Class 1 message). */
-    public static final int CMAS_CLASS_SEVERE_THREAT = 0x02;
-
-    /** Child abduction emergency (AMBER Alert). */
-    public static final int CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY = 0x03;
-
-    /** CMAS test message. */
-    public static final int CMAS_CLASS_REQUIRED_MONTHLY_TEST = 0x04;
-
-    /** CMAS exercise. */
-    public static final int CMAS_CLASS_CMAS_EXERCISE = 0x05;
-
-    /** CMAS category for operator defined use. */
-    public static final int CMAS_CLASS_OPERATOR_DEFINED_USE = 0x06;
-
-    /** CMAS category for warning types that are reserved for future extension. */
-    public static final int CMAS_CLASS_UNKNOWN = -1;
-
-    // CMAS alert category (in CDMA type 1 elements record).
-
-    /** CMAS alert category: Geophysical including landslide. */
-    public static final int CMAS_CATEGORY_GEO = 0x00;
-
-    /** CMAS alert category: Meteorological including flood. */
-    public static final int CMAS_CATEGORY_MET = 0x01;
-
-    /** CMAS alert category: General emergency and public safety. */
-    public static final int CMAS_CATEGORY_SAFETY = 0x02;
-
-    /** CMAS alert category: Law enforcement, military, homeland/local/private security. */
-    public static final int CMAS_CATEGORY_SECURITY = 0x03;
-
-    /** CMAS alert category: Rescue and recovery. */
-    public static final int CMAS_CATEGORY_RESCUE = 0x04;
-
-    /** CMAS alert category: Fire suppression and rescue. */
-    public static final int CMAS_CATEGORY_FIRE = 0x05;
-
-    /** CMAS alert category: Medical and public health. */
-    public static final int CMAS_CATEGORY_HEALTH = 0x06;
-
-    /** CMAS alert category: Pollution and other environmental. */
-    public static final int CMAS_CATEGORY_ENV = 0x07;
-
-    /** CMAS alert category: Public and private transportation. */
-    public static final int CMAS_CATEGORY_TRANSPORT = 0x08;
-
-    /** CMAS alert category: Utility, telecom, other non-transport infrastructure. */
-    public static final int CMAS_CATEGORY_INFRA = 0x09;
-
-    /** CMAS alert category: Chem, bio, radiological, nuclear, high explosive threat or attack. */
-    public static final int CMAS_CATEGORY_CBRNE = 0x0a;
-
-    /** CMAS alert category: Other events. */
-    public static final int CMAS_CATEGORY_OTHER = 0x0b;
-
-    /**
-     * CMAS alert category is unknown. The category is only available for CDMA broadcasts
-     * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown.
-     */
-    public static final int CMAS_CATEGORY_UNKNOWN = -1;
-
-    // CMAS response type (in CDMA type 1 elements record).
-
-    /** CMAS response type: Take shelter in place. */
-    public static final int CMAS_RESPONSE_TYPE_SHELTER = 0x00;
-
-    /** CMAS response type: Evacuate (Relocate). */
-    public static final int CMAS_RESPONSE_TYPE_EVACUATE = 0x01;
-
-    /** CMAS response type: Make preparations. */
-    public static final int CMAS_RESPONSE_TYPE_PREPARE = 0x02;
-
-    /** CMAS response type: Execute a pre-planned activity. */
-    public static final int CMAS_RESPONSE_TYPE_EXECUTE = 0x03;
-
-    /** CMAS response type: Attend to information sources. */
-    public static final int CMAS_RESPONSE_TYPE_MONITOR = 0x04;
-
-    /** CMAS response type: Avoid hazard. */
-    public static final int CMAS_RESPONSE_TYPE_AVOID = 0x05;
-
-    /** CMAS response type: Evaluate the information in this message (not for public warnings). */
-    public static final int CMAS_RESPONSE_TYPE_ASSESS = 0x06;
-
-    /** CMAS response type: No action recommended. */
-    public static final int CMAS_RESPONSE_TYPE_NONE = 0x07;
-
-    /**
-     * CMAS response type is unknown. The response type is only available for CDMA broadcasts
-     * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown.
-     */
-    public static final int CMAS_RESPONSE_TYPE_UNKNOWN = -1;
-
-    // 4-bit CMAS severity (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
-    /** CMAS severity type: Extraordinary threat to life or property. */
-    public static final int CMAS_SEVERITY_EXTREME = 0x0;
-
-    /** CMAS severity type: Significant threat to life or property. */
-    public static final int CMAS_SEVERITY_SEVERE = 0x1;
-
-    /**
-     * CMAS alert severity is unknown. The severity is available for CDMA warning alerts
-     * containing a type 1 elements record and for all GSM and UMTS alerts except for the
-     * Presidential-level alert class (Korean Public Alert System Class 0).
-     */
-    public static final int CMAS_SEVERITY_UNKNOWN = -1;
-
-    // CMAS urgency (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
-    /** CMAS urgency type: Responsive action should be taken immediately. */
-    public static final int CMAS_URGENCY_IMMEDIATE = 0x0;
-
-    /** CMAS urgency type: Responsive action should be taken within the next hour. */
-    public static final int CMAS_URGENCY_EXPECTED = 0x1;
-
-    /**
-     * CMAS alert urgency is unknown. The urgency is available for CDMA warning alerts
-     * containing a type 1 elements record and for all GSM and UMTS alerts except for the
-     * Presidential-level alert class (Korean Public Alert System Class 0).
-     */
-    public static final int CMAS_URGENCY_UNKNOWN = -1;
-
-    // CMAS certainty (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
-    /** CMAS certainty type: Determined to have occurred or to be ongoing. */
-    public static final int CMAS_CERTAINTY_OBSERVED = 0x0;
-
-    /** CMAS certainty type: Likely (probability > ~50%). */
-    public static final int CMAS_CERTAINTY_LIKELY = 0x1;
-
-    /**
-     * CMAS alert certainty is unknown. The certainty is available for CDMA warning alerts
-     * containing a type 1 elements record and for all GSM and UMTS alerts except for the
-     * Presidential-level alert class (Korean Public Alert System Class 0).
-     */
-    public static final int CMAS_CERTAINTY_UNKNOWN = -1;
-
-    /** CMAS message class. */
-    private final int mMessageClass;
-
-    /** CMAS category. */
-    private final int mCategory;
-
-    /** CMAS response type. */
-    private final int mResponseType;
-
-    /** CMAS severity. */
-    private final int mSeverity;
-
-    /** CMAS urgency. */
-    private final int mUrgency;
-
-    /** CMAS certainty. */
-    private final int mCertainty;
-
-    /** Create a new SmsCbCmasInfo object with the specified values. */
-    public SmsCbCmasInfo(int messageClass, int category, int responseType, int severity,
-            int urgency, int certainty) {
-        mMessageClass = messageClass;
-        mCategory = category;
-        mResponseType = responseType;
-        mSeverity = severity;
-        mUrgency = urgency;
-        mCertainty = certainty;
-    }
-
-    /** Create a new SmsCbCmasInfo object from a Parcel. */
-    SmsCbCmasInfo(Parcel in) {
-        mMessageClass = in.readInt();
-        mCategory = in.readInt();
-        mResponseType = in.readInt();
-        mSeverity = in.readInt();
-        mUrgency = in.readInt();
-        mCertainty = in.readInt();
-    }
-
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest  The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written (ignored).
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mMessageClass);
-        dest.writeInt(mCategory);
-        dest.writeInt(mResponseType);
-        dest.writeInt(mSeverity);
-        dest.writeInt(mUrgency);
-        dest.writeInt(mCertainty);
-    }
-
-    /**
-     * Returns the CMAS message class, e.g. {@link #CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT}.
-     * @return one of the {@code CMAS_CLASS} values
-     */
-    public int getMessageClass() {
-        return mMessageClass;
-    }
-
-    /**
-     * Returns the CMAS category, e.g. {@link #CMAS_CATEGORY_GEO}.
-     * @return one of the {@code CMAS_CATEGORY} values
-     */
-    public int getCategory() {
-        return mCategory;
-    }
-
-    /**
-     * Returns the CMAS response type, e.g. {@link #CMAS_RESPONSE_TYPE_SHELTER}.
-     * @return one of the {@code CMAS_RESPONSE_TYPE} values
-     */
-    public int getResponseType() {
-        return mResponseType;
-    }
-
-    /**
-     * Returns the CMAS severity, e.g. {@link #CMAS_SEVERITY_EXTREME}.
-     * @return one of the {@code CMAS_SEVERITY} values
-     */
-    public int getSeverity() {
-        return mSeverity;
-    }
-
-    /**
-     * Returns the CMAS urgency, e.g. {@link #CMAS_URGENCY_IMMEDIATE}.
-     * @return one of the {@code CMAS_URGENCY} values
-     */
-    public int getUrgency() {
-        return mUrgency;
-    }
-
-    /**
-     * Returns the CMAS certainty, e.g. {@link #CMAS_CERTAINTY_OBSERVED}.
-     * @return one of the {@code CMAS_CERTAINTY} values
-     */
-    public int getCertainty() {
-        return mCertainty;
-    }
-
-    @Override
-    public String toString() {
-        return "SmsCbCmasInfo{messageClass=" + mMessageClass + ", category=" + mCategory
-                + ", responseType=" + mResponseType + ", severity=" + mSeverity
-                + ", urgency=" + mUrgency + ", certainty=" + mCertainty + '}';
-    }
-
-    /**
-     * Describe the kinds of special objects contained in the marshalled representation.
-     * @return a bitmask indicating this Parcelable contains no special objects
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Creator for unparcelling objects. */
-    public static final Parcelable.Creator<SmsCbCmasInfo>
-            CREATOR = new Parcelable.Creator<SmsCbCmasInfo>() {
-        @Override
-        public SmsCbCmasInfo createFromParcel(Parcel in) {
-            return new SmsCbCmasInfo(in);
-        }
-
-        @Override
-        public SmsCbCmasInfo[] newArray(int size) {
-            return new SmsCbCmasInfo[size];
-        }
-    };
-}
diff --git a/src/java/android/telephony/SmsCbEtwsInfo.java b/src/java/android/telephony/SmsCbEtwsInfo.java
deleted file mode 100644
index 14e02de..0000000
--- a/src/java/android/telephony/SmsCbEtwsInfo.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * 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 android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.format.Time;
-
-import com.android.internal.telephony.uicc.IccUtils;
-
-import java.util.Arrays;
-
-/**
- * Contains information elements for a GSM or UMTS ETWS warning notification.
- * Supported values for each element are defined in 3GPP TS 23.041.
- *
- * {@hide}
- */
-public class SmsCbEtwsInfo implements Parcelable {
-
-    /** ETWS warning type for earthquake. */
-    public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00;
-
-    /** ETWS warning type for tsunami. */
-    public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01;
-
-    /** ETWS warning type for earthquake and tsunami. */
-    public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02;
-
-    /** ETWS warning type for test messages. */
-    public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 0x03;
-
-    /** ETWS warning type for other emergency types. */
-    public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 0x04;
-
-    /** Unknown ETWS warning type. */
-    public static final int ETWS_WARNING_TYPE_UNKNOWN = -1;
-
-    /** One of the ETWS warning type constants defined in this class. */
-    private final int mWarningType;
-
-    /** Whether or not to activate the emergency user alert tone and vibration. */
-    private final boolean mEmergencyUserAlert;
-
-    /** Whether or not to activate a popup alert. */
-    private final boolean mActivatePopup;
-
-    /** Whether ETWS primary message or not/ */
-    private final boolean mPrimary;
-
-    /**
-     * 50-byte security information (ETWS primary notification for GSM only). As of Release 10,
-     * 3GPP TS 23.041 states that the UE shall ignore the ETWS primary notification timestamp
-     * and digital signature if received. Therefore it is treated as a raw byte array and
-     * parceled with the broadcast intent if present, but the timestamp is only computed if an
-     * application asks for the individual components.
-     */
-    private final byte[] mWarningSecurityInformation;
-
-    /** Create a new SmsCbEtwsInfo object with the specified values. */
-    public SmsCbEtwsInfo(int warningType, boolean emergencyUserAlert, boolean activatePopup,
-                boolean primary, byte[] warningSecurityInformation) {
-        mWarningType = warningType;
-        mEmergencyUserAlert = emergencyUserAlert;
-        mActivatePopup = activatePopup;
-        mPrimary = primary;
-        mWarningSecurityInformation = warningSecurityInformation;
-    }
-
-    /** Create a new SmsCbEtwsInfo object from a Parcel. */
-    SmsCbEtwsInfo(Parcel in) {
-        mWarningType = in.readInt();
-        mEmergencyUserAlert = (in.readInt() != 0);
-        mActivatePopup = (in.readInt() != 0);
-        mPrimary = (in.readInt() != 0);
-        mWarningSecurityInformation = in.createByteArray();
-    }
-
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest  The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written (ignored).
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mWarningType);
-        dest.writeInt(mEmergencyUserAlert ? 1 : 0);
-        dest.writeInt(mActivatePopup ? 1 : 0);
-        dest.writeInt(mPrimary ? 1 : 0);
-        dest.writeByteArray(mWarningSecurityInformation);
-    }
-
-    /**
-     * Returns the ETWS warning type.
-     * @return a warning type such as {@link #ETWS_WARNING_TYPE_EARTHQUAKE}
-     */
-    public int getWarningType() {
-        return mWarningType;
-    }
-
-    /**
-     * Returns the ETWS emergency user alert flag.
-     * @return true to notify terminal to activate emergency user alert; false otherwise
-     */
-    public boolean isEmergencyUserAlert() {
-        return mEmergencyUserAlert;
-    }
-
-    /**
-     * Returns the ETWS activate popup flag.
-     * @return true to notify terminal to activate display popup; false otherwise
-     */
-    public boolean isPopupAlert() {
-        return mActivatePopup;
-    }
-
-    /**
-     * Returns the ETWS format flag.
-     * @return true if the message is primary message, otherwise secondary message
-     */
-    public boolean isPrimary() {
-        return mPrimary;
-    }
-
-    /**
-     * Returns the Warning-Security-Information timestamp (GSM primary notifications only).
-     * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received.
-     * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present
-     */
-    public long getPrimaryNotificationTimestamp() {
-        if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) {
-            return 0;
-        }
-
-        int year = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[0]);
-        int month = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[1]);
-        int day = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[2]);
-        int hour = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[3]);
-        int minute = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[4]);
-        int second = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[5]);
-
-        // For the timezone, the most significant bit of the
-        // least significant nibble is the sign byte
-        // (meaning the max range of this field is 79 quarter-hours,
-        // which is more than enough)
-
-        byte tzByte = mWarningSecurityInformation[6];
-
-        // Mask out sign bit.
-        int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
-
-        timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
-
-        Time time = new Time(Time.TIMEZONE_UTC);
-
-        // We only need to support years above 2000.
-        time.year = year + 2000;
-        time.month = month - 1;
-        time.monthDay = day;
-        time.hour = hour;
-        time.minute = minute;
-        time.second = second;
-
-        // Timezone offset is in quarter hours.
-        return time.toMillis(true) - timezoneOffset * 15 * 60 * 1000;
-    }
-
-    /**
-     * Returns the digital signature (GSM primary notifications only). As of Release 10,
-     * 3GPP TS 23.041 states that the UE shall ignore this value if received.
-     * @return a byte array containing a copy of the primary notification digital signature
-     */
-    public byte[] getPrimaryNotificationSignature() {
-        if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 50) {
-            return null;
-        }
-        return Arrays.copyOfRange(mWarningSecurityInformation, 7, 50);
-    }
-
-    @Override
-    public String toString() {
-        return "SmsCbEtwsInfo{warningType=" + mWarningType + ", emergencyUserAlert="
-                + mEmergencyUserAlert + ", activatePopup=" + mActivatePopup + '}';
-    }
-
-    /**
-     * Describe the kinds of special objects contained in the marshalled representation.
-     * @return a bitmask indicating this Parcelable contains no special objects
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Creator for unparcelling objects. */
-    public static final Creator<SmsCbEtwsInfo> CREATOR = new Creator<SmsCbEtwsInfo>() {
-        @Override
-        public SmsCbEtwsInfo createFromParcel(Parcel in) {
-            return new SmsCbEtwsInfo(in);
-        }
-
-        @Override
-        public SmsCbEtwsInfo[] newArray(int size) {
-            return new SmsCbEtwsInfo[size];
-        }
-    };
-}
diff --git a/src/java/android/telephony/SmsCbLocation.java b/src/java/android/telephony/SmsCbLocation.java
deleted file mode 100644
index 6eb72a8..0000000
--- a/src/java/android/telephony/SmsCbLocation.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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 android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents the location and geographical scope of a cell broadcast message.
- * For GSM/UMTS, the Location Area and Cell ID are set when the broadcast
- * geographical scope is cell wide or Location Area wide. For CDMA, the
- * broadcast geographical scope is always PLMN wide.
- *
- * @hide
- */
-public class SmsCbLocation implements Parcelable {
-
-    /** The PLMN. Note that this field may be an empty string, but isn't allowed to be null. */
-    private final String mPlmn;
-
-    private final int mLac;
-    private final int mCid;
-
-    /**
-     * Construct an empty location object. This is used for some test cases, and for
-     * cell broadcasts saved in older versions of the database without location info.
-     */
-    public SmsCbLocation() {
-        mPlmn = "";
-        mLac = -1;
-        mCid = -1;
-    }
-
-    /**
-     * Construct a location object for the PLMN. This class is immutable, so
-     * the same object can be reused for multiple broadcasts.
-     */
-    public SmsCbLocation(String plmn) {
-        mPlmn = plmn;
-        mLac = -1;
-        mCid = -1;
-    }
-
-    /**
-     * Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so
-     * the same object can be reused for multiple broadcasts.
-     */
-    public SmsCbLocation(String plmn, int lac, int cid) {
-        mPlmn = plmn;
-        mLac = lac;
-        mCid = cid;
-    }
-
-    /**
-     * Initialize the object from a Parcel.
-     */
-    public SmsCbLocation(Parcel in) {
-        mPlmn = in.readString();
-        mLac = in.readInt();
-        mCid = in.readInt();
-    }
-
-    /**
-     * Returns the MCC/MNC of the network as a String.
-     * @return the PLMN identifier (MCC+MNC) as a String
-     */
-    public String getPlmn() {
-        return mPlmn;
-    }
-
-    /**
-     * Returns the GSM location area code, or UMTS service area code.
-     * @return location area code, -1 if unknown, 0xffff max legal value
-     */
-    public int getLac() {
-        return mLac;
-    }
-
-    /**
-     * Returns the GSM or UMTS cell ID.
-     * @return gsm cell id, -1 if unknown, 0xffff max legal value
-     */
-    public int getCid() {
-        return mCid;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = mPlmn.hashCode();
-        hash = hash * 31 + mLac;
-        hash = hash * 31 + mCid;
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o == this) {
-            return true;
-        }
-        if (o == null || !(o instanceof SmsCbLocation)) {
-            return false;
-        }
-        SmsCbLocation other = (SmsCbLocation) o;
-        return mPlmn.equals(other.mPlmn) && mLac == other.mLac && mCid == other.mCid;
-    }
-
-    @Override
-    public String toString() {
-        return '[' + mPlmn + ',' + mLac + ',' + mCid + ']';
-    }
-
-    /**
-     * Test whether this location is within the location area of the specified object.
-     *
-     * @param area the location area to compare with this location
-     * @return true if this location is contained within the specified location area
-     */
-    public boolean isInLocationArea(SmsCbLocation area) {
-        if (mCid != -1 && mCid != area.mCid) {
-            return false;
-        }
-        if (mLac != -1 && mLac != area.mLac) {
-            return false;
-        }
-        return mPlmn.equals(area.mPlmn);
-    }
-
-    /**
-     * Test whether this location is within the location area of the CellLocation.
-     *
-     * @param plmn the PLMN to use for comparison
-     * @param lac the Location Area (GSM) or Service Area (UMTS) to compare with
-     * @param cid the Cell ID to compare with
-     * @return true if this location is contained within the specified PLMN, LAC, and Cell ID
-     */
-    public boolean isInLocationArea(String plmn, int lac, int cid) {
-        if (!mPlmn.equals(plmn)) {
-            return false;
-        }
-
-        if (mLac != -1 && mLac != lac) {
-            return false;
-        }
-
-        if (mCid != -1 && mCid != cid) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest  The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written (ignored).
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mPlmn);
-        dest.writeInt(mLac);
-        dest.writeInt(mCid);
-    }
-
-    public static final Parcelable.Creator<SmsCbLocation> CREATOR
-            = new Parcelable.Creator<SmsCbLocation>() {
-        @Override
-        public SmsCbLocation createFromParcel(Parcel in) {
-            return new SmsCbLocation(in);
-        }
-
-        @Override
-        public SmsCbLocation[] newArray(int size) {
-            return new SmsCbLocation[size];
-        }
-    };
-
-    /**
-     * Describe the kinds of special objects contained in the marshalled representation.
-     * @return a bitmask indicating this Parcelable contains no special objects
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/src/java/android/telephony/SmsCbMessage.java b/src/java/android/telephony/SmsCbMessage.java
deleted file mode 100644
index 046bf8c..0000000
--- a/src/java/android/telephony/SmsCbMessage.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2010 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.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Parcelable object containing a received cell broadcast message. There are four different types
- * of Cell Broadcast messages:
- *
- * <ul>
- * <li>opt-in informational broadcasts, e.g. news, weather, stock quotes, sports scores</li>
- * <li>cell information messages, broadcast on channel 50, indicating the current cell name for
- *  roaming purposes (required to display on the idle screen in Brazil)</li>
- * <li>emergency broadcasts for the Japanese Earthquake and Tsunami Warning System (ETWS)</li>
- * <li>emergency broadcasts for the American Commercial Mobile Alert Service (CMAS)</li>
- * </ul>
- *
- * <p>There are also four different CB message formats: GSM, ETWS Primary Notification (GSM only),
- * UMTS, and CDMA. Some fields are only applicable for some message formats. Other fields were
- * unified under a common name, avoiding some names, such as "Message Identifier", that refer to
- * two completely different concepts in 3GPP and CDMA.
- *
- * <p>The GSM/UMTS Message Identifier field is available via {@link #getServiceCategory}, the name
- * of the equivalent field in CDMA. In both cases the service category is a 16-bit value, but 3GPP
- * and 3GPP2 have completely different meanings for the respective values. For ETWS and CMAS, the
- * application should
- *
- * <p>The CDMA Message Identifier field is available via {@link #getSerialNumber}, which is used
- * to detect the receipt of a duplicate message to be discarded. In CDMA, the message ID is
- * unique to the current PLMN. In GSM/UMTS, there is a 16-bit serial number containing a 2-bit
- * Geographical Scope field which indicates whether the 10-bit message code and 4-bit update number
- * are considered unique to the PLMN, to the current cell, or to the current Location Area (or
- * Service Area in UMTS). The relevant values are concatenated into a single String which will be
- * unique if the messages are not duplicates.
- *
- * <p>The SMS dispatcher does not detect duplicate messages. However, it does concatenate the
- * pages of a GSM multi-page cell broadcast into a single SmsCbMessage object.
- *
- * <p>Interested applications with {@code RECEIVE_SMS_PERMISSION} can register to receive
- * {@code SMS_CB_RECEIVED_ACTION} broadcast intents for incoming non-emergency broadcasts.
- * Only system applications such as the CellBroadcastReceiver may receive notifications for
- * emergency broadcasts (ETWS and CMAS). This is intended to prevent any potential for delays or
- * interference with the immediate display of the alert message and playing of the alert sound and
- * vibration pattern, which could be caused by poorly written or malicious non-system code.
- *
- * @hide
- */
-public class SmsCbMessage implements Parcelable {
-
-    protected static final String LOG_TAG = "SMSCB";
-
-    /** Cell wide geographical scope with immediate display (GSM/UMTS only). */
-    public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
-
-    /** PLMN wide geographical scope (GSM/UMTS and all CDMA broadcasts). */
-    public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
-
-    /** Location / service area wide geographical scope (GSM/UMTS only). */
-    public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
-
-    /** Cell wide geographical scope (GSM/UMTS only). */
-    public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
-
-    /** GSM or UMTS format cell broadcast. */
-    public static final int MESSAGE_FORMAT_3GPP = 1;
-
-    /** CDMA format cell broadcast. */
-    public static final int MESSAGE_FORMAT_3GPP2 = 2;
-
-    /** Normal message priority. */
-    public static final int MESSAGE_PRIORITY_NORMAL = 0;
-
-    /** Interactive message priority. */
-    public static final int MESSAGE_PRIORITY_INTERACTIVE = 1;
-
-    /** Urgent message priority. */
-    public static final int MESSAGE_PRIORITY_URGENT = 2;
-
-    /** Emergency message priority. */
-    public static final int MESSAGE_PRIORITY_EMERGENCY = 3;
-
-    /** Format of this message (for interpretation of service category values). */
-    private final int mMessageFormat;
-
-    /** Geographical scope of broadcast. */
-    private final int mGeographicalScope;
-
-    /**
-     * Serial number of broadcast (message identifier for CDMA, geographical scope + message code +
-     * update number for GSM/UMTS). The serial number plus the location code uniquely identify
-     * a cell broadcast for duplicate detection.
-     */
-    private final int mSerialNumber;
-
-    /**
-     * Location identifier for this message. It consists of the current operator MCC/MNC as a
-     * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
-     * message is not binary 01, the Location Area is included for comparison. If the GS is
-     * 00 or 11, the Cell ID is also included. LAC and Cell ID are -1 if not specified.
-     */
-    private final SmsCbLocation mLocation;
-
-    /**
-     * 16-bit CDMA service category or GSM/UMTS message identifier. For ETWS and CMAS warnings,
-     * the information provided by the category is also available via {@link #getEtwsWarningInfo()}
-     * or {@link #getCmasWarningInfo()}.
-     */
-    private final int mServiceCategory;
-
-    /** Message language, as a two-character string, e.g. "en". */
-    private final String mLanguage;
-
-    /** Message body, as a String. */
-    private final String mBody;
-
-    /** Message priority (including emergency priority). */
-    private final int mPriority;
-
-    /** ETWS warning notification information (ETWS warnings only). */
-    private final SmsCbEtwsInfo mEtwsWarningInfo;
-
-    /** CMAS warning notification information (CMAS warnings only). */
-    private final SmsCbCmasInfo mCmasWarningInfo;
-
-    /**
-     * Create a new SmsCbMessage with the specified data.
-     */
-    public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
-            SmsCbLocation location, int serviceCategory, String language, String body,
-            int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo) {
-        mMessageFormat = messageFormat;
-        mGeographicalScope = geographicalScope;
-        mSerialNumber = serialNumber;
-        mLocation = location;
-        mServiceCategory = serviceCategory;
-        mLanguage = language;
-        mBody = body;
-        mPriority = priority;
-        mEtwsWarningInfo = etwsWarningInfo;
-        mCmasWarningInfo = cmasWarningInfo;
-    }
-
-    /** Create a new SmsCbMessage object from a Parcel. */
-    public SmsCbMessage(Parcel in) {
-        mMessageFormat = in.readInt();
-        mGeographicalScope = in.readInt();
-        mSerialNumber = in.readInt();
-        mLocation = new SmsCbLocation(in);
-        mServiceCategory = in.readInt();
-        mLanguage = in.readString();
-        mBody = in.readString();
-        mPriority = in.readInt();
-        int type = in.readInt();
-        switch (type) {
-            case 'E':
-                // unparcel ETWS warning information
-                mEtwsWarningInfo = new SmsCbEtwsInfo(in);
-                mCmasWarningInfo = null;
-                break;
-
-            case 'C':
-                // unparcel CMAS warning information
-                mEtwsWarningInfo = null;
-                mCmasWarningInfo = new SmsCbCmasInfo(in);
-                break;
-
-            default:
-                mEtwsWarningInfo = null;
-                mCmasWarningInfo = null;
-        }
-    }
-
-    /**
-     * Flatten this object into a Parcel.
-     *
-     * @param dest  The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written (ignored).
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mMessageFormat);
-        dest.writeInt(mGeographicalScope);
-        dest.writeInt(mSerialNumber);
-        mLocation.writeToParcel(dest, flags);
-        dest.writeInt(mServiceCategory);
-        dest.writeString(mLanguage);
-        dest.writeString(mBody);
-        dest.writeInt(mPriority);
-        if (mEtwsWarningInfo != null) {
-            // parcel ETWS warning information
-            dest.writeInt('E');
-            mEtwsWarningInfo.writeToParcel(dest, flags);
-        } else if (mCmasWarningInfo != null) {
-            // parcel CMAS warning information
-            dest.writeInt('C');
-            mCmasWarningInfo.writeToParcel(dest, flags);
-        } else {
-            // no ETWS or CMAS warning information
-            dest.writeInt('0');
-        }
-    }
-
-    public static final Parcelable.Creator<SmsCbMessage> CREATOR
-            = new Parcelable.Creator<SmsCbMessage>() {
-        @Override
-        public SmsCbMessage createFromParcel(Parcel in) {
-            return new SmsCbMessage(in);
-        }
-
-        @Override
-        public SmsCbMessage[] newArray(int size) {
-            return new SmsCbMessage[size];
-        }
-    };
-
-    /**
-     * Return the geographical scope of this message (GSM/UMTS only).
-     *
-     * @return Geographical scope
-     */
-    public int getGeographicalScope() {
-        return mGeographicalScope;
-    }
-
-    /**
-     * Return the broadcast serial number of broadcast (message identifier for CDMA, or
-     * geographical scope + message code + update number for GSM/UMTS). The serial number plus
-     * the location code uniquely identify a cell broadcast for duplicate detection.
-     *
-     * @return the 16-bit CDMA message identifier or GSM/UMTS serial number
-     */
-    public int getSerialNumber() {
-        return mSerialNumber;
-    }
-
-    /**
-     * Return the location identifier for this message, consisting of the MCC/MNC as a
-     * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
-     * message is not binary 01, the Location Area is included. If the GS is 00 or 11, the
-     * cell ID is also included. The {@link SmsCbLocation} object includes a method to test
-     * if the location is included within another location area or within a PLMN and CellLocation.
-     *
-     * @return the geographical location code for duplicate message detection
-     */
-    public SmsCbLocation getLocation() {
-        return mLocation;
-    }
-
-    /**
-     * Return the 16-bit CDMA service category or GSM/UMTS message identifier. The interpretation
-     * of the category is radio technology specific. For ETWS and CMAS warnings, the information
-     * provided by the category is available via {@link #getEtwsWarningInfo()} or
-     * {@link #getCmasWarningInfo()} in a radio technology independent format.
-     *
-     * @return the radio technology specific service category
-     */
-    public int getServiceCategory() {
-        return mServiceCategory;
-    }
-
-    /**
-     * Get the ISO-639-1 language code for this message, or null if unspecified
-     *
-     * @return Language code
-     */
-    public String getLanguageCode() {
-        return mLanguage;
-    }
-
-    /**
-     * Get the body of this message, or null if no body available
-     *
-     * @return Body, or null
-     */
-    public String getMessageBody() {
-        return mBody;
-    }
-
-    /**
-     * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}).
-     * @return an integer representing 3GPP or 3GPP2 message format
-     */
-    public int getMessageFormat() {
-        return mMessageFormat;
-    }
-
-    /**
-     * Get the message priority. Normal broadcasts return {@link #MESSAGE_PRIORITY_NORMAL}
-     * and emergency broadcasts return {@link #MESSAGE_PRIORITY_EMERGENCY}. CDMA also may return
-     * {@link #MESSAGE_PRIORITY_INTERACTIVE} or {@link #MESSAGE_PRIORITY_URGENT}.
-     * @return an integer representing the message priority
-     */
-    public int getMessagePriority() {
-        return mPriority;
-    }
-
-    /**
-     * If this is an ETWS warning notification then this method will return an object containing
-     * the ETWS warning type, the emergency user alert flag, and the popup flag. If this is an
-     * ETWS primary notification (GSM only), there will also be a 7-byte timestamp and 43-byte
-     * digital signature. As of Release 10, 3GPP TS 23.041 states that the UE shall ignore the
-     * ETWS primary notification timestamp and digital signature if received.
-     *
-     * @return an SmsCbEtwsInfo object, or null if this is not an ETWS warning notification
-     */
-    public SmsCbEtwsInfo getEtwsWarningInfo() {
-        return mEtwsWarningInfo;
-    }
-
-    /**
-     * If this is a CMAS warning notification then this method will return an object containing
-     * the CMAS message class, category, response type, severity, urgency and certainty.
-     * The message class is always present. Severity, urgency and certainty are present for CDMA
-     * warning notifications containing a type 1 elements record and for GSM and UMTS warnings
-     * except for the Presidential-level alert category. Category and response type are only
-     * available for CDMA notifications containing a type 1 elements record.
-     *
-     * @return an SmsCbCmasInfo object, or null if this is not a CMAS warning notification
-     */
-    public SmsCbCmasInfo getCmasWarningInfo() {
-        return mCmasWarningInfo;
-    }
-
-    /**
-     * Return whether this message is an emergency (PWS) message type.
-     * @return true if the message is a public warning notification; false otherwise
-     */
-    public boolean isEmergencyMessage() {
-        return mPriority == MESSAGE_PRIORITY_EMERGENCY;
-    }
-
-    /**
-     * Return whether this message is an ETWS warning alert.
-     * @return true if the message is an ETWS warning notification; false otherwise
-     */
-    public boolean isEtwsMessage() {
-        return mEtwsWarningInfo != null;
-    }
-
-    /**
-     * Return whether this message is a CMAS warning alert.
-     * @return true if the message is a CMAS warning notification; false otherwise
-     */
-    public boolean isCmasMessage() {
-        return mCmasWarningInfo != null;
-    }
-
-    @Override
-    public String toString() {
-        return "SmsCbMessage{geographicalScope=" + mGeographicalScope + ", serialNumber="
-                + mSerialNumber + ", location=" + mLocation + ", serviceCategory="
-                + mServiceCategory + ", language=" + mLanguage + ", body=" + mBody
-                + ", priority=" + mPriority
-                + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
-                + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") + '}';
-    }
-
-    /**
-     * Describe the kinds of special objects contained in the marshalled representation.
-     * @return a bitmask indicating this Parcelable contains no special objects
-     */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-}
diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java
deleted file mode 100644
index 8063364..0000000
--- a/src/java/android/telephony/SmsManager.java
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
- * 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 android.telephony;
-
-import android.app.ActivityThread;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.BaseBundle;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.telephony.IMms;
-import com.android.internal.telephony.ISms;
-import com.android.internal.telephony.SmsRawData;
-import com.android.internal.telephony.uicc.IccConstants;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/*
- * TODO(code review): Curious question... Why are a lot of these
- * methods not declared as static, since they do not seem to require
- * any local object state?  Presumably this cannot be changed without
- * interfering with the API...
- */
-
-/**
- * Manages SMS operations such as sending data, text, and pdu SMS messages.
- * Get this object by calling the static method {@link #getDefault()}.
- *
- * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
- * and higher, see {@link android.provider.Telephony}.
- */
-public final class SmsManager {
-    private static final String TAG = "SmsManager";
-    /**
-     * A psuedo-subId that represents the default subId at any given time. The actual subId it
-     * represents changes as the default subId is changed.
-     */
-    private static final int DEFAULT_SUBSCRIPTION_ID = -1002;
-
-    /** Singleton object constructed during class initialization. */
-    private static final SmsManager sInstance = new SmsManager(DEFAULT_SUBSCRIPTION_ID);
-    private static final Object sLockObject = new Object();
-
-    /** @hide */
-    public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0;
-    /** @hide */
-    public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1;
-
-    private static final Map<Integer, SmsManager> sSubInstances =
-            new ArrayMap<Integer, SmsManager>();
-
-    /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
-    private int mSubId;
-
-    /*
-     * Key for the various carrier-dependent configuration values.
-     * Some of the values are used by the system in processing SMS or MMS messages. Others
-     * are provided for the convenience of SMS applications.
-     */
-
-    /**
-     * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI
-     * when constructing the download URL of a new MMS (boolean type)
-     */
-    public static final String MMS_CONFIG_APPEND_TRANSACTION_ID =
-            CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL;
-    /**
-     * Whether MMS is enabled for the current carrier (boolean type)
-     */
-    public static final String
-        MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL;
-    /**
-     * Whether group MMS is enabled for the current carrier (boolean type)
-     */
-    public static final String
-            MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL;
-    /**
-     * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead
-     * of the default MMSC (boolean type)
-     */
-    public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED =
-            CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL;
-    /**
-     * Whether alias is enabled (boolean type)
-     */
-    public static final String
-            MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL;
-    /**
-     * Whether audio is allowed to be attached for MMS messages (boolean type)
-     */
-    public static final String
-            MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL;
-    /**
-     * Whether multipart SMS is enabled (boolean type)
-     */
-    public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED =
-            CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL;
-    /**
-     * Whether SMS delivery report is enabled (boolean type)
-     */
-    public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED =
-            CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL;
-    /**
-     * Whether content-disposition field should be expected in an MMS PDU (boolean type)
-     */
-    public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
-            CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL;
-    /**
-     * Whether multipart SMS should be sent as separate messages
-     */
-    public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
-            CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL;
-    /**
-     * Whether MMS read report is enabled (boolean type)
-     */
-    public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED =
-            CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL;
-    /**
-     * Whether MMS delivery report is enabled (boolean type)
-     */
-    public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED =
-            CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL;
-    /**
-     * Max MMS message size in bytes (int type)
-     */
-    public static final String
-            MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT;
-    /**
-     * Max MMS image width (int type)
-     */
-    public static final String
-            MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT;
-    /**
-     * Max MMS image height (int type)
-     */
-    public static final String
-            MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT;
-    /**
-     * Limit of recipients of MMS messages (int type)
-     */
-    public static final String
-            MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT;
-    /**
-     * Min alias character count (int type)
-     */
-    public static final String
-            MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT;
-    /**
-     * Max alias character count (int type)
-     */
-    public static final String
-            MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT;
-    /**
-     * When the number of parts of a multipart SMS reaches this threshold, it should be converted
-     * into an MMS (int type)
-     */
-    public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD =
-            CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT;
-    /**
-     * Some carriers require SMS to be converted into MMS when text length reaches this threshold
-     * (int type)
-     */
-    public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
-            CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT;
-    /**
-     * Max message text size (int type)
-     */
-    public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE =
-            CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT;
-    /**
-     * Max message subject length (int type)
-     */
-    public static final String
-            MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT;
-    /**
-     * MMS HTTP socket timeout in milliseconds (int type)
-     */
-    public static final String
-            MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT;
-    /**
-     * The name of the UA Prof URL HTTP header for MMS HTTP request (String type)
-     */
-    public static final String
-            MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING;
-    /**
-     * The User-Agent header value for MMS HTTP request (String type)
-     */
-    public static final String
-            MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING;
-    /**
-     * The UA Profile URL header value for MMS HTTP request (String type)
-     */
-    public static final String
-            MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING;
-    /**
-     * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type)
-     */
-    public static final String
-            MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING;
-    /**
-     * Email gateway number (String type)
-     */
-    public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER =
-            CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING;
-    /**
-     * The suffix to append to the NAI header value for MMS HTTP request (String type)
-     */
-    public static final String
-            MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING;
-    /**
-     * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want
-     * this shown. (Boolean type)
-     */
-    public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS =
-            CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL;
-    /**
-     * Whether the carrier MMSC supports charset field in Content-Type header. If this is false,
-     * then we don't add "charset" to "Content-Type"
-     */
-    public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER =
-            CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL;
-    /**
-     * If true, add "Connection: close" header to MMS HTTP requests so the connection
-     * is immediately closed (disabling keep-alive). (Boolean type)
-     * @hide
-     */
-    public static final String MMS_CONFIG_CLOSE_CONNECTION =
-            CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL;
-
-    /*
-     * Forwarded constants from SimDialogActivity.
-     */
-    private static String DIALOG_TYPE_KEY = "dialog_type";
-    private static final int SMS_PICK = 2;
-
-    /**
-     * Send a text based SMS.
-     *
-     * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
-     * {@link android.Manifest.permission#SEND_SMS} permission.</p>
-     *
-     * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
-     * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
-     * writes messages sent using this method to the SMS Provider (the default SMS app is always
-     * responsible for writing its sent messages to the SMS Provider). For information about
-     * how to behave as the default SMS app, see {@link android.provider.Telephony}.</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").
-     *
-     * @throws IllegalArgumentException if destinationAddress or text are empty
-     */
-    public void sendTextMessage(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        sendTextMessageInternal(destinationAddress, scAddress, text,
-            sentIntent, deliveryIntent, true /* persistMessageForCarrierApp*/);
-    }
-
-    private void sendTextMessageInternal(String destinationAddress, String scAddress,
-            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
-            boolean persistMessageForCarrierApp) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-
-        if (TextUtils.isEmpty(text)) {
-            throw new IllegalArgumentException("Invalid message body");
-        }
-
-        try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
-                    destinationAddress,
-                    scAddress, text, sentIntent, deliveryIntent,
-                    persistMessageForCarrierApp);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Send a text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Only the carrier app can call this method.</p>
-     *
-     * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
-     * @hide
-     */
-    public void sendTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        sendTextMessageInternal(destinationAddress, scAddress, text,
-            sentIntent, deliveryIntent, false /* persistMessageForCarrierApp*/);
-    }
-
-    /**
-     * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * @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 iccISms = getISmsServiceOrThrow();
-            iccISms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(),
-                    destinationAddress,
-                    scAddress, text, sentIntent, deliveryIntent, persistMessage);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Inject an SMS PDU into the android application framework.
-     *
-     * The caller should have carrier privileges.
-     * @see android.telephony.TelephonyManager#hasCarrierPrivileges
-     *
-     * @param pdu is the byte array of pdu to be injected into android application framework
-     * @param format is the format of SMS pdu (3gpp or 3gpp2)
-     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully received by the
-     *  android application framework, or failed. This intent is broadcasted at
-     *  the same time an SMS received from radio is acknowledged back.
-     *  The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
-     *  <code>RESULT_SMS_GENERIC_ERROR</code> for error.
-     *
-     * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
-     */
-    public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
-        if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
-            // Format must be either 3gpp or 3gpp2.
-            throw new IllegalArgumentException(
-                    "Invalid pdu format. format must be either 3gpp or 3gpp2");
-        }
-        try {
-            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            if (iccISms != null) {
-                iccISms.injectSmsPduForSubscriber(
-                        getSubscriptionId(), pdu, format, receivedIntent);
-            }
-        } catch (RemoteException ex) {
-          // ignore it
-        }
-    }
-
-    /**
-     * Divide a message text into several fragments, none bigger than
-     * the maximum SMS message size.
-     *
-     * @param text the original message.  Must not be null.
-     * @return an <code>ArrayList</code> of strings that, in order,
-     *   comprise the original message
-     *
-     * @throws IllegalArgumentException if text is null
-     */
-    public ArrayList<String> divideMessage(String text) {
-        if (null == text) {
-            throw new IllegalArgumentException("text is null");
-        }
-        return SmsMessage.fragmentText(text);
-    }
-
-    /**
-     * Send a multi-part text based SMS.  The callee should have already
-     * divided the message into correctly sized parts by calling
-     * <code>divideMessage</code>.
-     *
-     * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
-     * {@link android.Manifest.permission#SEND_SMS} permission.</p>
-     *
-     * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
-     * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
-     * writes messages sent using this method to the SMS Provider (the default SMS app is always
-     * responsible for writing its sent messages to the SMS Provider). For information about
-     * how to behave as the default SMS app, see {@link android.provider.Telephony}.</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 parts an <code>ArrayList</code> of strings that, in order,
-     *   comprise the original message
-     * @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 destinationAddress or data are empty
-     */
-    public void sendMultipartTextMessage(
-            String destinationAddress, String scAddress, ArrayList<String> parts,
-            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
-        sendMultipartTextMessageInternal(destinationAddress, scAddress, parts,
-              sentIntents, deliveryIntents, true /* persistMessageForCarrierApp*/);
-    }
-
-    private void sendMultipartTextMessageInternal(
-            String destinationAddress, String scAddress, ArrayList<String> parts,
-            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
-            boolean persistMessageForCarrierApp) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-        if (parts == null || parts.size() < 1) {
-            throw new IllegalArgumentException("Invalid message body");
-        }
-
-        if (parts.size() > 1) {
-            try {
-                ISms iccISms = getISmsServiceOrThrow();
-                iccISms.sendMultipartTextForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
-                        destinationAddress, scAddress, parts,
-                        sentIntents, deliveryIntents, persistMessageForCarrierApp);
-            } catch (RemoteException ex) {
-                // ignore it
-            }
-        } else {
-            PendingIntent sentIntent = null;
-            PendingIntent deliveryIntent = null;
-            if (sentIntents != null && sentIntents.size() > 0) {
-                sentIntent = sentIntents.get(0);
-            }
-            if (deliveryIntents != null && deliveryIntents.size() > 0) {
-                deliveryIntent = deliveryIntents.get(0);
-            }
-            sendTextMessage(destinationAddress, scAddress, parts.get(0),
-                    sentIntent, deliveryIntent);
-        }
-    }
-
-    /**
-     * Send a multi-part text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Only the carrier app can call this method.</p>
-     *
-     * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
-     * @hide
-     **/
-    public void sendMultipartTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, ArrayList<String> parts,
-            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
-        sendMultipartTextMessageInternal(destinationAddress, scAddress, parts,
-            sentIntents, deliveryIntents, false /* persistMessageForCarrierApp*/);
-    }
-
-    /**
-     * 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
-     * {@link android.Manifest.permission#SEND_SMS} permission.</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 destinationPort the port to deliver the message to
-     * @param data 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").
-     *
-     * @throws IllegalArgumentException if destinationAddress or data are empty
-     */
-    public void sendDataMessage(
-            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 iccISms = getISmsServiceOrThrow();
-            iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
-                    destinationAddress, scAddress, destinationPort & 0xFFFF,
-                    data, sentIntent, deliveryIntent);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * @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 iccISms = getISmsServiceOrThrow();
-            iccISms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), destinationAddress, scAddress,
-                    destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-
-
-    /**
-     * 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 is changed.
-     *
-     * @return the SmsManager associated with the default subscription id
-     */
-    public static SmsManager getDefault() {
-        return sInstance;
-    }
-
-    /**
-     * Get the the instance of the SmsManager associated with a particular subscription id
-     *
-     * @param subId an SMS subscription id, typically accessed using
-     *   {@link android.telephony.SubscriptionManager}
-     * @return the instance of the SmsManager associated with subId
-     */
-    public static SmsManager getSmsManagerForSubscriptionId(int subId) {
-        // TODO(shri): Add javadoc link once SubscriptionManager is made public api
-        synchronized(sLockObject) {
-            SmsManager smsManager = sSubInstances.get(subId);
-            if (smsManager == null) {
-                smsManager = new SmsManager(subId);
-                sSubInstances.put(subId, smsManager);
-            }
-            return smsManager;
-        }
-    }
-
-    private SmsManager(int subId) {
-        mSubId = subId;
-    }
-
-    /**
-     * Get the associated subscription id. If the instance was returned by {@link #getDefault()},
-     * then this method may return different values at different points in time (if the user
-     * changes the default subscription id). It will return < 0 if the default subscription id
-     * cannot be determined.
-     *
-     * Additionally, to support legacy applications that are not multi-SIM aware,
-     * if the following are true:
-     *     - We are using a multi-SIM device
-     *     - A default SMS SIM has not been selected
-     *     - At least one SIM subscription is available
-     * then ask the user to set the default SMS SIM.
-     *
-     * @return associated subscription id
-     */
-    public int getSubscriptionId() {
-        final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
-                ? getDefaultSmsSubscriptionId() : mSubId;
-        boolean isSmsSimPickActivityNeeded = false;
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId);
-            }
-        } catch (RemoteException ex) {
-            Log.e(TAG, "Exception in getSubscriptionId");
-        }
-
-        if (isSmsSimPickActivityNeeded) {
-            Log.d(TAG, "getSubscriptionId isSmsSimPickActivityNeeded is true");
-            // ask the user for a default SMS SIM.
-            Intent intent = new Intent();
-            intent.setClassName("com.android.settings",
-                    "com.android.settings.sim.SimDialogActivity");
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            intent.putExtra(DIALOG_TYPE_KEY, SMS_PICK);
-            try {
-                context.startActivity(intent);
-            } catch (ActivityNotFoundException anfe) {
-                // If Settings is not installed, only log the error as we do not want to break
-                // legacy applications.
-                Log.e(TAG, "Unable to launch Settings application.");
-            }
-        }
-
-        return subId;
-    }
-
-    /**
-     * Returns the ISms service, or throws an UnsupportedOperationException if
-     * the service does not exist.
-     */
-    private static ISms getISmsServiceOrThrow() {
-        ISms iccISms = getISmsService();
-        if (iccISms == null) {
-            throw new UnsupportedOperationException("Sms is not supported");
-        }
-        return iccISms;
-    }
-
-    private static ISms getISmsService() {
-        return ISms.Stub.asInterface(ServiceManager.getService("isms"));
-    }
-
-    /**
-     * Copy a raw SMS PDU to the ICC.
-     * ICC (Integrated Circuit Card) is the card of the device.
-     * For example, this can be the SIM or USIM for GSM.
-     *
-     * @param smsc the SMSC for this message, or NULL for the default SMSC
-     * @param pdu the raw PDU to store
-     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
-     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
-     * @return true for success
-     *
-     * @throws IllegalArgumentException if pdu is NULL
-     * {@hide}
-     */
-    public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
-        boolean success = false;
-
-        if (null == pdu) {
-            throw new IllegalArgumentException("pdu is NULL");
-        }
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
-                        status, pdu, smsc);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Delete the specified message from the ICC.
-     * ICC (Integrated Circuit Card) is the card of the device.
-     * For example, this can be the SIM or USIM for GSM.
-     *
-     * @param messageIndex is the record index of the message on ICC
-     * @return true for success
-     *
-     * {@hide}
-     */
-    public boolean
-    deleteMessageFromIcc(int messageIndex) {
-        boolean success = false;
-        byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
-        Arrays.fill(pdu, (byte)0xff);
-
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
-                        messageIndex, STATUS_ON_ICC_FREE, pdu);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Update the specified message on the ICC.
-     * ICC (Integrated Circuit Card) is the card of the device.
-     * For example, this can be the SIM or USIM for GSM.
-     *
-     * @param messageIndex record index of message to update
-     * @param newStatus new message status (STATUS_ON_ICC_READ,
-     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
-     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
-     * @param pdu the raw PDU to store
-     * @return true for success
-     *
-     * {@hide}
-     */
-    public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
-        boolean success = false;
-
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
-                        ActivityThread.currentPackageName(),
-                        messageIndex, newStatus, pdu);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Retrieves all messages currently stored on ICC.
-     * ICC (Integrated Circuit Card) is the card of the device.
-     * For example, this can be the SIM or USIM for GSM.
-     *
-     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
-     *
-     * {@hide}
-     */
-    public ArrayList<SmsMessage> getAllMessagesFromIcc() {
-        List<SmsRawData> records = null;
-
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                records = iccISms.getAllMessagesFromIccEfForSubscriber(
-                        getSubscriptionId(),
-                        ActivityThread.currentPackageName());
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return createMessageListFromRawRecords(records);
-    }
-
-    /**
-     * 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.
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType as defined in class SmsManager, the value can be one of these:
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
-     * @return true if successful, false otherwise
-     * @see #disableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.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.
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType as defined in class SmsManager, the value can be one of these:
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
-     * @return true if successful, false otherwise
-     *
-     * @see #enableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.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 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.
-     *
-     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType as defined in class SmsManager, the value can be one of these:
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
-     * @return true if successful, false otherwise
-     * @see #disableCellBroadcastRange(int, int, int)
-     *
-     * @throws IllegalArgumentException if endMessageId < startMessageId
-     * {@hide}
-     */
-    public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
-        boolean success = false;
-
-        if (endMessageId < startMessageId) {
-            throw new IllegalArgumentException("endMessageId < startMessageId");
-        }
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
-                        startMessageId, endMessageId, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Disable reception of cell broadcast (SMS-CB) messages with the given
-     * message identifier range and RAN type. The RAN type specify this message
-     * ID range 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.
-     *
-     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType as defined in class SmsManager, the value can be one of these:
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
-     *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
-     * @return true if successful, false otherwise
-     *
-     * @see #enableCellBroadcastRange(int, int, int)
-     *
-     * @throws IllegalArgumentException if endMessageId < startMessageId
-     * {@hide}
-     */
-    public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
-        boolean success = false;
-
-        if (endMessageId < startMessageId) {
-            throw new IllegalArgumentException("endMessageId < startMessageId");
-        }
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
-                        startMessageId, endMessageId, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
-     * records returned by <code>getAllMessagesFromIcc()</code>
-     *
-     * @param records SMS EF records, returned by
-     *   <code>getAllMessagesFromIcc</code>
-     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
-     */
-    private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
-        ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
-        if (records != null) {
-            int count = records.size();
-            for (int i = 0; i < count; i++) {
-                SmsRawData data = records.get(i);
-                // List contains all records, including "free" records (null)
-                if (data != null) {
-                    SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
-                    if (sms != null) {
-                        messages.add(sms);
-                    }
-                }
-            }
-        }
-        return messages;
-    }
-
-    /**
-     * SMS over IMS is supported if IMS is registered and SMS is supported
-     * on IMS.
-     *
-     * @return true if SMS over IMS is supported, false otherwise
-     *
-     * @see #getImsSmsFormat()
-     *
-     * @hide
-     */
-    public boolean isImsSmsSupported() {
-        boolean boSupported = false;
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId());
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return boSupported;
-    }
-
-    /**
-     * Gets SMS format supported on IMS.  SMS over IMS format is
-     * either 3GPP or 3GPP2.
-     *
-     * @return SmsMessage.FORMAT_3GPP,
-     *         SmsMessage.FORMAT_3GPP2
-     *      or SmsMessage.FORMAT_UNKNOWN
-     *
-     * @see #isImsSmsSupported()
-     *
-     * @hide
-     */
-    public String getImsSmsFormat() {
-        String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
-        try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId());
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return format;
-    }
-
-    /**
-     * Get default sms subscription id
-     *
-     * @return the default SMS subscription id
-     */
-    public static int getDefaultSmsSubscriptionId() {
-        ISms iccISms = null;
-        try {
-            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            return iccISms.getPreferredSmsSubscription();
-        } catch (RemoteException ex) {
-            return -1;
-        } catch (NullPointerException ex) {
-            return -1;
-        }
-    }
-
-    /**
-     * Get SMS prompt property,  enabled or not
-     *
-     * @return true if enabled, false otherwise
-     * @hide
-     */
-    public boolean isSMSPromptEnabled() {
-        ISms iccISms = null;
-        try {
-            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            return iccISms.isSMSPromptEnabled();
-        } catch (RemoteException ex) {
-            return false;
-        } catch (NullPointerException ex) {
-            return false;
-        }
-    }
-
-    // see SmsMessage.getStatusOnIcc
-
-    /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_FREE      = 0;
-
-    /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_READ      = 1;
-
-    /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_UNREAD    = 3;
-
-    /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_SENT      = 5;
-
-    /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_UNSENT    = 7;
-
-    // SMS send failure result codes
-
-    /** Generic failure cause */
-    static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
-    /** Failed because radio was explicitly turned off */
-    static public final int RESULT_ERROR_RADIO_OFF          = 2;
-    /** Failed because no pdu provided */
-    static public final int RESULT_ERROR_NULL_PDU           = 3;
-    /** Failed because service is currently unavailable */
-    static public final int RESULT_ERROR_NO_SERVICE         = 4;
-    /** Failed because we reached the sending queue limit.  {@hide} */
-    static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
-    /** Failed because FDN is enabled. {@hide} */
-    static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
-
-    static private final String PHONE_PACKAGE_NAME = "com.android.phone";
-
-    /**
-     * Send an MMS message
-     *
-     * @param context application context
-     * @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
-     * @throws IllegalArgumentException if contentUri is empty
-     */
-    public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
-            Bundle configOverrides, PendingIntent sentIntent) {
-        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,
-                    locationUrl, configOverrides, sentIntent);
-        } catch (RemoteException e) {
-            // Ignore it
-        }
-    }
-
-    /**
-     * Download an MMS message from carrier by a given location URL
-     *
-     * @param context application context
-     * @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(Context context, String locationUrl, Uri contentUri,
-            Bundle configOverrides, PendingIntent downloadedIntent) {
-        if (TextUtils.isEmpty(locationUrl)) {
-            throw new IllegalArgumentException("Empty MMS location URL");
-        }
-        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
-        }
-    }
-
-    // MMS send/download failure result codes
-    public static final int MMS_ERROR_UNSPECIFIED = 1;
-    public static final int MMS_ERROR_INVALID_APN = 2;
-    public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
-    public static final int MMS_ERROR_HTTP_FAILURE = 4;
-    public static final int MMS_ERROR_IO_ERROR = 5;
-    public static final int MMS_ERROR_RETRY = 6;
-    public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
-    public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
-
-    /** Intent extra name for MMS sending result data in byte array type */
-    public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
-    /** 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.
-     *
-     * @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");
-        }
-        try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendStoredText(
-                    getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
-                    scAddress, sentIntent, deliveryIntent);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * 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>
-     *
-     * @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");
-        }
-        try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendStoredMultipartText(
-                    getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
-                    scAddress, sentIntents, deliveryIntents);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * 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.
-     *
-     * @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.
-     *
-     * @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;
-    }
-
-    /**
-     * 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;
-    }
-
-}
diff --git a/src/java/android/telephony/SmsMessage.java b/src/java/android/telephony/SmsMessage.java
deleted file mode 100644
index 73e1f1a..0000000
--- a/src/java/android/telephony/SmsMessage.java
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- * 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 android.telephony;
-
-import android.os.Binder;
-import android.os.Parcel;
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
-
-
-/**
- * A Short Message Service message.
- * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
- */
-public class SmsMessage {
-    private static final String LOG_TAG = "SmsMessage";
-
-    /**
-     * SMS Class enumeration.
-     * See TS 23.038.
-     *
-     */
-    public enum MessageClass{
-        UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
-    }
-
-    /** User data text encoding code unit size */
-    public static final int ENCODING_UNKNOWN = 0;
-    public static final int ENCODING_7BIT = 1;
-    public static final int ENCODING_8BIT = 2;
-    public static final int ENCODING_16BIT = 3;
-    /**
-     * @hide This value is not defined in global standard. Only in Korea, this is used.
-     */
-    public static final int ENCODING_KSC5601 = 4;
-
-    /** The maximum number of payload bytes per message */
-    public static final int MAX_USER_DATA_BYTES = 140;
-
-    /**
-     * The maximum number of payload bytes per message if a user data header
-     * is present.  This assumes the header only contains the
-     * CONCATENATED_8_BIT_REFERENCE element.
-     */
-    public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
-
-    /** The maximum number of payload septets per message */
-    public static final int MAX_USER_DATA_SEPTETS = 160;
-
-    /**
-     * The maximum number of payload septets per message if a user data header
-     * is present.  This assumes the header only contains the
-     * CONCATENATED_8_BIT_REFERENCE element.
-     */
-    public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
-
-    /**
-     * Indicates a 3GPP format SMS message.
-     * @hide pending API council approval
-     */
-    public static final String FORMAT_3GPP = "3gpp";
-
-    /**
-     * Indicates a 3GPP2 format SMS message.
-     * @hide pending API council approval
-     */
-    public static final String FORMAT_3GPP2 = "3gpp2";
-
-    /** Contains actual SmsMessage. Only public for debugging and for framework layer.
-     *
-     * @hide
-     */
-    public SmsMessageBase mWrappedSmsMessage;
-
-    /** Indicates the subId
-     *
-     * @hide
-     */
-    private int mSubId = 0;
-
-    /** set Subscription information
-     *
-     * @hide
-     */
-    public void setSubId(int subId) {
-        mSubId = subId;
-    }
-
-    /** get Subscription information
-     *
-     * @hide
-     */
-    public int getSubId() {
-        return mSubId;
-    }
-
-    public static class SubmitPdu {
-
-        public byte[] encodedScAddress; // Null if not applicable.
-        public byte[] encodedMessage;
-
-        @Override
-        public String toString() {
-            return "SubmitPdu: encodedScAddress = "
-                    + Arrays.toString(encodedScAddress)
-                    + ", encodedMessage = "
-                    + Arrays.toString(encodedMessage);
-        }
-
-        /**
-         * @hide
-         */
-        protected SubmitPdu(SubmitPduBase spb) {
-            this.encodedMessage = spb.encodedMessage;
-            this.encodedScAddress = spb.encodedScAddress;
-        }
-
-    }
-
-    private SmsMessage(SmsMessageBase smb) {
-        mWrappedSmsMessage = smb;
-    }
-
-    /**
-     * Create an SmsMessage from a raw PDU. Guess format based on Voice
-     * technology first, if it fails use other format.
-     * All applications which handle
-     * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast
-     * intent <b>must</b> now pass the new {@code format} String extra from the intent
-     * into the new method {@code createFromPdu(byte[], String)} which takes an
-     * extra format parameter. This is required in order to correctly decode the PDU on
-     * devices that require support for both 3GPP and 3GPP2 formats at the same time,
-     * such as dual-mode GSM/CDMA and CDMA/LTE phones.
-     * @deprecated Use {@link #createFromPdu(byte[], String)} instead.
-     */
-    @Deprecated
-    public static SmsMessage createFromPdu(byte[] pdu) {
-         SmsMessage message = null;
-
-        // cdma(3gpp2) vs gsm(3gpp) format info was not given,
-        // guess from active voice phone type
-        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
-        String format = (PHONE_TYPE_CDMA == activePhone) ?
-                SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
-        message = createFromPdu(pdu, format);
-
-        if (null == message || null == message.mWrappedSmsMessage) {
-            // decoding pdu failed based on activePhone type, must be other format
-            format = (PHONE_TYPE_CDMA == activePhone) ?
-                    SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2;
-            message = createFromPdu(pdu, format);
-        }
-        return message;
-    }
-
-    /**
-     * Create an SmsMessage from a raw PDU with the specified message format. The
-     * message format is passed in the
-     * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} as the {@code format}
-     * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
-     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
-     *
-     * @param pdu the message PDU from the
-     * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
-     * @param format the format extra from the
-     * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
-     */
-    public static SmsMessage createFromPdu(byte[] pdu, String format) {
-        SmsMessageBase wrappedMessage;
-
-        if (SmsConstants.FORMAT_3GPP2.equals(format)) {
-            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
-        } else if (SmsConstants.FORMAT_3GPP.equals(format)) {
-            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
-        } else {
-            Rlog.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
-            return null;
-        }
-
-        if (wrappedMessage != null) {
-            return new SmsMessage(wrappedMessage);
-        } else {
-            Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null");
-            return null;
-        }
-    }
-
-    /**
-     * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
-     * +CMT unsolicited response (PDU mode, of course)
-     *  +CMT: [&lt;alpha>],<length><CR><LF><pdu>
-     *
-     * Only public for debugging and for RIL
-     *
-     * {@hide}
-     */
-    public static SmsMessage newFromCMT(String[] lines) {
-        // received SMS in 3GPP format
-        SmsMessageBase wrappedMessage =
-                com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
-
-        if (wrappedMessage != null) {
-            return new SmsMessage(wrappedMessage);
-        } else {
-            Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
-            return null;
-        }
-    }
-
-    /** @hide */
-    public static SmsMessage newFromParcel(Parcel p) {
-        // received SMS in 3GPP2 format
-        SmsMessageBase wrappedMessage =
-                com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
-
-        return new SmsMessage(wrappedMessage);
-    }
-
-    /**
-     * Create an SmsMessage from an SMS EF record.
-     *
-     * @param index Index of SMS record. This should be index in ArrayList
-     *              returned by SmsManager.getAllMessagesFromSim + 1.
-     * @param data Record data.
-     * @return An SmsMessage representing the record.
-     *
-     * @hide
-     */
-    public static SmsMessage createFromEfRecord(int index, byte[] data) {
-        SmsMessageBase wrappedMessage;
-
-        if (isCdmaVoice()) {
-            wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
-                    index, data);
-        } else {
-            wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
-                    index, data);
-        }
-
-        if (wrappedMessage != null) {
-            return new SmsMessage(wrappedMessage);
-        } else {
-            Rlog.e(LOG_TAG, "createFromEfRecord(): wrappedMessage is null");
-            return null;
-        }
-    }
-
-    /**
-     * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
-     * length in bytes (not hex chars) less the SMSC header
-     *
-     * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices.
-     * We should probably deprecate it and remove the obsolete test case.
-     */
-    public static int getTPLayerLengthForPDU(String pdu) {
-        if (isCdmaVoice()) {
-            return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
-        } else {
-            return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
-        }
-    }
-
-    /*
-     * TODO(cleanup): It would make some sense if the result of
-     * preprocessing a message to determine the proper encoding (i.e.
-     * the resulting data structure from calculateLength) could be
-     * passed as an argument to the actual final encoding function.
-     * This would better ensure that the logic behind size calculation
-     * actually matched the encoding.
-     */
-
-    /**
-     * Calculates the number of SMS's required to encode the message body and
-     * the number of characters remaining until the next message.
-     *
-     * @param msgBody the message to encode
-     * @param use7bitOnly if true, characters that are not part of the
-     *         radio-specific 7-bit encoding are counted as single
-     *         space chars.  If false, and if the messageBody contains
-     *         non-7-bit encodable characters, length is calculated
-     *         using a 16-bit encoding.
-     * @return an int[4] with int[0] being the number of SMS's
-     *         required, int[1] the number of code units used, and
-     *         int[2] is the number of code units remaining until the
-     *         next message. int[3] is an indicator of the encoding
-     *         code unit size (see the ENCODING_* definitions in SmsConstants)
-     */
-    public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
-        // this function is for MO SMS
-        TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
-            com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly,
-                    true) :
-            com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
-        int ret[] = new int[4];
-        ret[0] = ted.msgCount;
-        ret[1] = ted.codeUnitCount;
-        ret[2] = ted.codeUnitsRemaining;
-        ret[3] = ted.codeUnitSize;
-        return ret;
-    }
-
-    /**
-     * Divide a message text into several fragments, none bigger than
-     * the maximum SMS message text size.
-     *
-     * @param text text, must not be null.
-     * @return an <code>ArrayList</code> of strings that, in order,
-     *   comprise the original msg text
-     *
-     * @hide
-     */
-    public static ArrayList<String> fragmentText(String text) {
-        // This function is for MO SMS
-        TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
-            com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false, true) :
-            com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);
-
-        // TODO(cleanup): The code here could be rolled into the logic
-        // below cleanly if these MAX_* constants were defined more
-        // flexibly...
-
-        int limit;
-        if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
-            int udhLength;
-            if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
-                udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
-            } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
-                udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
-            } else {
-                udhLength = 0;
-            }
-
-            if (ted.msgCount > 1) {
-                udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
-            }
-
-            if (udhLength != 0) {
-                udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
-            }
-
-            limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;
-        } else {
-            if (ted.msgCount > 1) {
-                limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
-                // If EMS is not supported, break down EMS into single segment SMS
-                // and add page info " x/y".
-                // In the case of UCS2 encoding, we need 8 bytes for this,
-                // but we only have 6 bytes from UDH, so truncate the limit for
-                // each segment by 2 bytes (1 char).
-                // Make sure total number of segments is less than 10.
-                if (!hasEmsSupport() && ted.msgCount < 10) {
-                    limit -= 2;
-                }
-            } else {
-                limit = SmsConstants.MAX_USER_DATA_BYTES;
-            }
-        }
-
-        String newMsgBody = null;
-        Resources r = Resources.getSystem();
-        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
-            newMsgBody  = Sms7BitEncodingTranslator.translate(text);
-        }
-        if (TextUtils.isEmpty(newMsgBody)) {
-            newMsgBody = text;
-        }
-        int pos = 0;  // Index in code units.
-        int textLen = newMsgBody.length();
-        ArrayList<String> result = new ArrayList<String>(ted.msgCount);
-        while (pos < textLen) {
-            int nextPos = 0;  // Counts code units.
-            if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
-                if (useCdmaFormatForMoSms() && ted.msgCount == 1) {
-                    // For a singleton CDMA message, the encoding must be ASCII...
-                    nextPos = pos + Math.min(limit, textLen - pos);
-                } else {
-                    // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
-                    nextPos = GsmAlphabet.findGsmSeptetLimitIndex(newMsgBody, pos, limit,
-                            ted.languageTable, ted.languageShiftTable);
-                }
-            } else {  // Assume unicode.
-                nextPos = SmsMessageBase.findNextUnicodePosition(pos, limit, newMsgBody);
-            }
-            if ((nextPos <= pos) || (nextPos > textLen)) {
-                Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
-                          nextPos + " >= " + textLen + ")");
-                break;
-            }
-            result.add(newMsgBody.substring(pos, nextPos));
-            pos = nextPos;
-        }
-        return result;
-    }
-
-    /**
-     * Calculates the number of SMS's required to encode the message body and
-     * the number of characters remaining until the next message, given the
-     * current encoding.
-     *
-     * @param messageBody the message to encode
-     * @param use7bitOnly if true, characters that are not part of the radio
-     *         specific (GSM / CDMA) alphabet encoding are converted to as a
-     *         single space characters. If false, a messageBody containing
-     *         non-GSM or non-CDMA alphabet characters are encoded using
-     *         16-bit encoding.
-     * @return an int[4] with int[0] being the number of SMS's required, int[1]
-     *         the number of code units used, and int[2] is the number of code
-     *         units remaining until the next message. int[3] is the encoding
-     *         type that should be used for the message.
-     */
-    public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
-        return calculateLength((CharSequence)messageBody, use7bitOnly);
-    }
-
-    /*
-     * TODO(cleanup): It looks like there is now no useful reason why
-     * apps should generate pdus themselves using these routines,
-     * instead of handing the raw data to SMSDispatcher (and thereby
-     * have the phone process do the encoding).  Moreover, CDMA now
-     * has shared state (in the form of the msgId system property)
-     * which can only be modified by the phone process, and hence
-     * makes the output of these routines incorrect.  Since they now
-     * serve no purpose, they should probably just return null
-     * directly, and be deprecated.  Going further in that direction,
-     * the above parsers of serialized pdu data should probably also
-     * be gotten rid of, hiding all but the necessarily visible
-     * structured data from client apps.  A possible concern with
-     * doing this is that apps may be using these routines to generate
-     * pdus that are then sent elsewhere, some network server, for
-     * example, and that always returning null would thereby break
-     * otherwise useful apps.
-     */
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message.
-     * This method will not attempt to use any GSM national language 7 bit encodings.
-     *
-     * @param scAddress Service Centre address.  Null means use default.
-     * @return a <code>SubmitPdu</code> containing the encoded SC
-     *         address, if applicable, and the encoded message.
-     *         Returns null on encode error.
-     */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destinationAddress, String message, boolean statusReportRequested) {
-        SubmitPduBase spb;
-
-        if (useCdmaFormatForMoSms()) {
-            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested, null);
-        } else {
-            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, message, statusReportRequested);
-        }
-
-        return new SubmitPdu(spb);
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
-     * This method will not attempt to use any GSM national language 7 bit encodings.
-     *
-     * @param scAddress Service Centre address. null == use default
-     * @param destinationAddress the address of the destination for the message
-     * @param destinationPort the port to deliver the message to at the
-     *        destination
-     * @param data the data for the message
-     * @return a <code>SubmitPdu</code> containing the encoded SC
-     *         address, if applicable, and the encoded message.
-     *         Returns null on encode error.
-     */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destinationAddress, short destinationPort, byte[] data,
-            boolean statusReportRequested) {
-        SubmitPduBase spb;
-
-        if (useCdmaFormatForMoSms()) {
-            spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, destinationPort, data, statusReportRequested);
-        } else {
-            spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
-                    destinationAddress, destinationPort, data, statusReportRequested);
-        }
-
-        return new SubmitPdu(spb);
-    }
-
-    /**
-     * Returns the address of the SMS service center that relayed this message
-     * or null if there is none.
-     */
-    public String getServiceCenterAddress() {
-        return mWrappedSmsMessage.getServiceCenterAddress();
-    }
-
-    /**
-     * Returns the originating address (sender) of this SMS message in String
-     * form or null if unavailable
-     */
-    public String getOriginatingAddress() {
-        return mWrappedSmsMessage.getOriginatingAddress();
-    }
-
-    /**
-     * Returns the originating address, or email from address if this message
-     * was from an email gateway. Returns null if originating address
-     * unavailable.
-     */
-    public String getDisplayOriginatingAddress() {
-        return mWrappedSmsMessage.getDisplayOriginatingAddress();
-    }
-
-    /**
-     * Returns the message body as a String, if it exists and is text based.
-     * @return message body is there is one, otherwise null
-     */
-    public String getMessageBody() {
-        return mWrappedSmsMessage.getMessageBody();
-    }
-
-    /**
-     * Returns the class of this message.
-     */
-    public MessageClass getMessageClass() {
-        switch(mWrappedSmsMessage.getMessageClass()) {
-            case CLASS_0: return MessageClass.CLASS_0;
-            case CLASS_1: return MessageClass.CLASS_1;
-            case CLASS_2: return MessageClass.CLASS_2;
-            case CLASS_3: return MessageClass.CLASS_3;
-            default: return MessageClass.UNKNOWN;
-
-        }
-    }
-
-    /**
-     * Returns the message body, or email message body if this message was from
-     * an email gateway. Returns null if message body unavailable.
-     */
-    public String getDisplayMessageBody() {
-        return mWrappedSmsMessage.getDisplayMessageBody();
-    }
-
-    /**
-     * Unofficial convention of a subject line enclosed in parens empty string
-     * if not present
-     */
-    public String getPseudoSubject() {
-        return mWrappedSmsMessage.getPseudoSubject();
-    }
-
-    /**
-     * Returns the service centre timestamp in currentTimeMillis() format
-     */
-    public long getTimestampMillis() {
-        return mWrappedSmsMessage.getTimestampMillis();
-    }
-
-    /**
-     * Returns true if message is an email.
-     *
-     * @return true if this message came through an email gateway and email
-     *         sender / subject / parsed body are available
-     */
-    public boolean isEmail() {
-        return mWrappedSmsMessage.isEmail();
-    }
-
-     /**
-     * @return if isEmail() is true, body of the email sent through the gateway.
-     *         null otherwise
-     */
-    public String getEmailBody() {
-        return mWrappedSmsMessage.getEmailBody();
-    }
-
-    /**
-     * @return if isEmail() is true, email from address of email sent through
-     *         the gateway. null otherwise
-     */
-    public String getEmailFrom() {
-        return mWrappedSmsMessage.getEmailFrom();
-    }
-
-    /**
-     * Get protocol identifier.
-     */
-    public int getProtocolIdentifier() {
-        return mWrappedSmsMessage.getProtocolIdentifier();
-    }
-
-    /**
-     * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
-     * SMS
-     */
-    public boolean isReplace() {
-        return mWrappedSmsMessage.isReplace();
-    }
-
-    /**
-     * Returns true for CPHS MWI toggle message.
-     *
-     * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
-     *         B.4.2
-     */
-    public boolean isCphsMwiMessage() {
-        return mWrappedSmsMessage.isCphsMwiMessage();
-    }
-
-    /**
-     * returns true if this message is a CPHS voicemail / message waiting
-     * indicator (MWI) clear message
-     */
-    public boolean isMWIClearMessage() {
-        return mWrappedSmsMessage.isMWIClearMessage();
-    }
-
-    /**
-     * returns true if this message is a CPHS voicemail / message waiting
-     * indicator (MWI) set message
-     */
-    public boolean isMWISetMessage() {
-        return mWrappedSmsMessage.isMWISetMessage();
-    }
-
-    /**
-     * returns true if this message is a "Message Waiting Indication Group:
-     * Discard Message" notification and should not be stored.
-     */
-    public boolean isMwiDontStore() {
-        return mWrappedSmsMessage.isMwiDontStore();
-    }
-
-    /**
-     * returns the user data section minus the user data header if one was
-     * present.
-     */
-    public byte[] getUserData() {
-        return mWrappedSmsMessage.getUserData();
-    }
-
-    /**
-     * Returns the raw PDU for the message.
-     *
-     * @return the raw PDU for the message.
-     */
-    public byte[] getPdu() {
-        return mWrappedSmsMessage.getPdu();
-    }
-
-    /**
-     * Returns the status of the message on the SIM (read, unread, sent, unsent).
-     *
-     * @return the status of the message on the SIM.  These are:
-     *         SmsManager.STATUS_ON_SIM_FREE
-     *         SmsManager.STATUS_ON_SIM_READ
-     *         SmsManager.STATUS_ON_SIM_UNREAD
-     *         SmsManager.STATUS_ON_SIM_SEND
-     *         SmsManager.STATUS_ON_SIM_UNSENT
-     * @deprecated Use getStatusOnIcc instead.
-     */
-    @Deprecated public int getStatusOnSim() {
-        return mWrappedSmsMessage.getStatusOnIcc();
-    }
-
-    /**
-     * Returns the status of the message on the ICC (read, unread, sent, unsent).
-     *
-     * @return the status of the message on the ICC.  These are:
-     *         SmsManager.STATUS_ON_ICC_FREE
-     *         SmsManager.STATUS_ON_ICC_READ
-     *         SmsManager.STATUS_ON_ICC_UNREAD
-     *         SmsManager.STATUS_ON_ICC_SEND
-     *         SmsManager.STATUS_ON_ICC_UNSENT
-     */
-    public int getStatusOnIcc() {
-        return mWrappedSmsMessage.getStatusOnIcc();
-    }
-
-    /**
-     * Returns the record index of the message on the SIM (1-based index).
-     * @return the record index of the message on the SIM, or -1 if this
-     *         SmsMessage was not created from a SIM SMS EF record.
-     * @deprecated Use getIndexOnIcc instead.
-     */
-    @Deprecated public int getIndexOnSim() {
-        return mWrappedSmsMessage.getIndexOnIcc();
-    }
-
-    /**
-     * Returns the record index of the message on the ICC (1-based index).
-     * @return the record index of the message on the ICC, or -1 if this
-     *         SmsMessage was not created from a ICC SMS EF record.
-     */
-    public int getIndexOnIcc() {
-        return mWrappedSmsMessage.getIndexOnIcc();
-    }
-
-    /**
-     * GSM:
-     * For an SMS-STATUS-REPORT message, this returns the status field from
-     * the status report.  This field indicates the status of a previously
-     * submitted SMS, if requested.  See TS 23.040, 9.2.3.15 TP-Status for a
-     * description of values.
-     * CDMA:
-     * For not interfering with status codes from GSM, the value is
-     * shifted to the bits 31-16.
-     * The value is composed of an error class (bits 25-24) and a status code (bits 23-16).
-     * Possible codes are described in C.S0015-B, v2.0, 4.5.21.
-     *
-     * @return 0 indicates the previously sent message was received.
-     *         See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21
-     *         for a description of other possible values.
-     */
-    public int getStatus() {
-        return mWrappedSmsMessage.getStatus();
-    }
-
-    /**
-     * Return true iff the message is a SMS-STATUS-REPORT message.
-     */
-    public boolean isStatusReportMessage() {
-        return mWrappedSmsMessage.isStatusReportMessage();
-    }
-
-    /**
-     * Returns true iff the <code>TP-Reply-Path</code> bit is set in
-     * this message.
-     */
-    public boolean isReplyPathPresent() {
-        return mWrappedSmsMessage.isReplyPathPresent();
-    }
-
-    /**
-     * Determines whether or not to use CDMA format for MO SMS.
-     * If SMS over IMS is supported, then format is based on IMS SMS format,
-     * otherwise format is based on current phone type.
-     *
-     * @return true if Cdma format should be used for MO SMS, false otherwise.
-     */
-    private static boolean useCdmaFormatForMoSms() {
-        if (!SmsManager.getDefault().isImsSmsSupported()) {
-            // use Voice technology to determine SMS format.
-            return isCdmaVoice();
-        }
-        // IMS is registered with SMS support, check the SMS format supported
-        return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
-    }
-
-    /**
-     * Determines whether or not to current phone type is cdma.
-     *
-     * @return true if current phone type is cdma, false otherwise.
-     */
-    private static boolean isCdmaVoice() {
-        int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
-        return (PHONE_TYPE_CDMA == activePhone);
-    }
-
-    /**
-     * Decide if the carrier supports long SMS.
-     * {@hide}
-     */
-    public static boolean hasEmsSupport() {
-        if (!isNoEmsSupportConfigListExisted()) {
-            return true;
-        }
-
-        String simOperator;
-        String gid;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
-            gid = TelephonyManager.getDefault().getGroupIdLevel1();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        if (!TextUtils.isEmpty(simOperator)) {
-            for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
-                if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
-                        (TextUtils.isEmpty(currentConfig.mGid1) ||
-                                (!TextUtils.isEmpty(currentConfig.mGid1) &&
-                                        currentConfig.mGid1.equalsIgnoreCase(gid)))) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check where to add " x/y" in each SMS segment, begin or end.
-     * {@hide}
-     */
-    public static boolean shouldAppendPageNumberAsPrefix() {
-        if (!isNoEmsSupportConfigListExisted()) {
-            return false;
-        }
-
-        String simOperator;
-        String gid;
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
-            gid = TelephonyManager.getDefault().getGroupIdLevel1();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-
-        for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
-            if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
-                (TextUtils.isEmpty(currentConfig.mGid1) ||
-                (!TextUtils.isEmpty(currentConfig.mGid1)
-                && currentConfig.mGid1.equalsIgnoreCase(gid)))) {
-                return currentConfig.mIsPrefix;
-            }
-        }
-        return false;
-    }
-
-    private static class NoEmsSupportConfig {
-        String mOperatorNumber;
-        String mGid1;
-        boolean mIsPrefix;
-
-        public NoEmsSupportConfig(String[] config) {
-            mOperatorNumber = config[0];
-            mIsPrefix = "prefix".equals(config[1]);
-            mGid1 = config.length > 2 ? config[2] : null;
-        }
-
-        @Override
-        public String toString() {
-            return "NoEmsSupportConfig { mOperatorNumber = " + mOperatorNumber
-                    + ", mIsPrefix = " + mIsPrefix + ", mGid1 = " + mGid1 + " }";
-        }
-    }
-
-    private static NoEmsSupportConfig[] mNoEmsSupportConfigList = null;
-    private static boolean mIsNoEmsSupportConfigListLoaded = false;
-
-    private static boolean isNoEmsSupportConfigListExisted() {
-        if (!mIsNoEmsSupportConfigListLoaded) {
-            Resources r = Resources.getSystem();
-            if (r != null) {
-                String[] listArray = r.getStringArray(
-                        com.android.internal.R.array.no_ems_support_sim_operators);
-                if ((listArray != null) && (listArray.length > 0)) {
-                    mNoEmsSupportConfigList = new NoEmsSupportConfig[listArray.length];
-                    for (int i=0; i<listArray.length; i++) {
-                        mNoEmsSupportConfigList[i] = new NoEmsSupportConfig(listArray[i].split(";"));
-                    }
-                }
-                mIsNoEmsSupportConfigListLoaded = true;
-            }
-        }
-
-        if (mNoEmsSupportConfigList != null && mNoEmsSupportConfigList.length != 0) {
-            return true;
-        }
-
-        return false;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/AppSmsManager.java b/src/java/com/android/internal/telephony/AppSmsManager.java
new file mode 100644
index 0000000..11e7f10
--- /dev/null
+++ b/src/java/com/android/internal/telephony/AppSmsManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.app.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.SmsMessage;
+import android.util.ArrayMap;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.security.SecureRandom;
+import java.util.Map;
+
+
+/**
+ *  Manager for app specific incoming SMS requests. This can be used to implement SMS based
+ *  communication channels (e.g. for SMS based phone number verification) without needing the
+ *  {@link Manifest.permission#RECEIVE_SMS} permission.
+ *
+ *  {@link #createAppSpecificSmsRequest} allows an application to provide a {@link PendingIntent}
+ *  that is triggered when an incoming SMS is received that contains the provided token.
+ */
+public class AppSmsManager {
+    private static final String LOG_TAG = "AppSmsManager";
+
+    private final SecureRandom mRandom;
+    private final Context mContext;
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private final Map<String, AppRequestInfo> mTokenMap;
+    @GuardedBy("mLock")
+    private final Map<String, AppRequestInfo> mPackageMap;
+
+    public AppSmsManager(Context context) {
+        mRandom = new SecureRandom();
+        mTokenMap = new ArrayMap<>();
+        mPackageMap = new ArrayMap<>();
+        mContext = context;
+    }
+
+    /**
+     * Create an app specific incoming SMS request for the the calling package.
+     *
+     * This method returns a token that if included in a subsequent incoming SMS message the
+     * {@link Intents.SMS_RECEIVED_ACTION} intent will be delivered only to the calling package and
+     * will not require the application have the {@link Manifest.permission#RECEIVE_SMS} permission.
+     *
+     * An app can only have one request at a time, if the app already has a request it will be
+     * dropped and the new one will be added.
+     *
+     * @return Token to include in an SMS to have it delivered directly to the app.
+     */
+    public String createAppSpecificSmsToken(String callingPkg, PendingIntent intent) {
+        // Check calling uid matches callingpkg.
+        AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        appOps.checkPackage(Binder.getCallingUid(), callingPkg);
+
+        // Generate a nonce to store the request under.
+        String token = generateNonce();
+        synchronized (mLock) {
+            // Only allow one request in flight from a package.
+            if (mPackageMap.containsKey(callingPkg)) {
+                removeRequestLocked(mPackageMap.get(callingPkg));
+            }
+            // Store state.
+            AppRequestInfo info = new AppRequestInfo(callingPkg, intent, token);
+            addRequestLocked(info);
+        }
+        return token;
+    }
+
+    /**
+     * Handle an incoming SMS_DELIVER_ACTION intent if it is an app-only SMS.
+     */
+    public boolean handleSmsReceivedIntent(Intent intent) {
+        // Sanity check the action.
+        if (intent.getAction() != Intents.SMS_DELIVER_ACTION) {
+            Log.wtf(LOG_TAG, "Got intent with incorrect action: " + intent.getAction());
+            return false;
+        }
+
+        synchronized (mLock) {
+            AppRequestInfo info = findAppRequestInfoSmsIntentLocked(intent);
+            if (info == null) {
+                // The message didn't contain a token -- nothing to do.
+                return false;
+            }
+            try {
+                Intent fillIn = new Intent();
+                fillIn.putExtras(intent.getExtras());
+                info.pendingIntent.send(mContext, 0, fillIn);
+            } catch (PendingIntent.CanceledException e) {
+                // The pending intent is canceled, send this SMS as normal.
+                removeRequestLocked(info);
+                return false;
+            }
+
+            removeRequestLocked(info);
+            return true;
+        }
+    }
+
+    private AppRequestInfo findAppRequestInfoSmsIntentLocked(Intent intent) {
+        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
+        if (messages == null) {
+            return null;
+        }
+        StringBuilder fullMessageBuilder = new StringBuilder();
+        for (SmsMessage message : messages) {
+            if (message == null || message.getMessageBody() == null) {
+                continue;
+            }
+            fullMessageBuilder.append(message.getMessageBody());
+        }
+
+        String fullMessage = fullMessageBuilder.toString();
+
+        // Look for any tokens in the full message.
+        for (String token : mTokenMap.keySet()) {
+            if (fullMessage.contains(token)) {
+                return mTokenMap.get(token);
+            }
+        }
+        return null;
+    }
+
+    private String generateNonce() {
+        byte[] bytes = new byte[8];
+        mRandom.nextBytes(bytes);
+        return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
+    }
+
+    private void removeRequestLocked(AppRequestInfo info) {
+        mTokenMap.remove(info.token);
+        mPackageMap.remove(info.packageName);
+    }
+
+    private void addRequestLocked(AppRequestInfo info) {
+        mTokenMap.put(info.token, info);
+        mPackageMap.put(info.packageName, info);
+    }
+
+    private final class AppRequestInfo {
+        public final String packageName;
+        public final PendingIntent pendingIntent;
+        public final String token;
+
+        AppRequestInfo(String packageName, PendingIntent pendingIntent, String token) {
+            this.packageName = packageName;
+            this.pendingIntent = pendingIntent;
+            this.token = token;
+        }
+    }
+
+}
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index df91ceb..8865901 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -18,16 +18,13 @@
 package com.android.internal.telephony;
 
 import android.content.Context;
-import android.os.Message;
-import android.os.RegistrantList;
-import android.os.Registrant;
-import android.os.Handler;
 import android.os.AsyncResult;
-import android.telephony.RadioAccessFamily;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
 import android.telephony.TelephonyManager;
 
-import com.android.internal.telephony.RadioCapability;
-
 /**
  * {@hide}
  */
@@ -43,8 +40,8 @@
     protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList();
     protected RegistrantList mNotAvailRegistrants = new RegistrantList();
     protected RegistrantList mCallStateRegistrants = new RegistrantList();
-    protected RegistrantList mVoiceNetworkStateRegistrants = new RegistrantList();
-    protected RegistrantList mDataNetworkStateRegistrants = new RegistrantList();
+    protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
+    protected RegistrantList mDataCallListChangedRegistrants = new RegistrantList();
     protected RegistrantList mVoiceRadioTechChangedRegistrants = new RegistrantList();
     protected RegistrantList mImsNetworkStateChangedRegistrants = new RegistrantList();
     protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList();
@@ -237,27 +234,27 @@
     }
 
     @Override
-    public void registerForVoiceNetworkStateChanged(Handler h, int what, Object obj) {
+    public void registerForNetworkStateChanged(Handler h, int what, Object obj) {
         Registrant r = new Registrant (h, what, obj);
 
-        mVoiceNetworkStateRegistrants.add(r);
+        mNetworkStateRegistrants.add(r);
     }
 
     @Override
-    public void unregisterForVoiceNetworkStateChanged(Handler h) {
-        mVoiceNetworkStateRegistrants.remove(h);
+    public void unregisterForNetworkStateChanged(Handler h) {
+        mNetworkStateRegistrants.remove(h);
     }
 
     @Override
-    public void registerForDataNetworkStateChanged(Handler h, int what, Object obj) {
+    public void registerForDataCallListChanged(Handler h, int what, Object obj) {
         Registrant r = new Registrant (h, what, obj);
 
-        mDataNetworkStateRegistrants.add(r);
+        mDataCallListChangedRegistrants.add(r);
     }
 
     @Override
-    public void unregisterForDataNetworkStateChanged(Handler h) {
-        mDataNetworkStateRegistrants.remove(h);
+    public void unregisterForDataCallListChanged(Handler h) {
+        mDataCallListChangedRegistrants.remove(h);
     }
 
     @Override
@@ -785,7 +782,6 @@
 
             if (mState.isAvailable() && !oldState.isAvailable()) {
                 mAvailRegistrants.notifyRegistrants();
-                onRadioAvailable();
             }
 
             if (!mState.isAvailable() && oldState.isAvailable()) {
@@ -804,9 +800,6 @@
         }
     }
 
-    protected void onRadioAvailable() {
-    }
-
     /**
      * {@inheritDoc}
      */
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index d532175..8d2093e 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -53,6 +53,7 @@
     int ACM_LIMIT_EXCEEDED = 68;
     int CALL_BARRED        = 240;
     int FDN_BLOCKED        = 241;
+    int IMEI_NOT_ACCEPTED  = 243;
 
     // Stk Call Control
     int DIAL_MODIFIED_TO_USSD = 244;
diff --git a/src/java/com/android/internal/telephony/CallManager.java b/src/java/com/android/internal/telephony/CallManager.java
index 4016217..2775fe6 100644
--- a/src/java/com/android/internal/telephony/CallManager.java
+++ b/src/java/com/android/internal/telephony/CallManager.java
@@ -1493,6 +1493,7 @@
      * <code>obj.result</code> will be an "MmiCode" object
      */
     public void registerForMmiComplete(Handler h, int what, Object obj){
+        Rlog.d(LOG_TAG, "registerForMmiComplete");
         mMmiCompleteRegistrants.addUnique(h, what, obj);
     }
 
@@ -2317,7 +2318,7 @@
                     mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
                     break;
                 case EVENT_MMI_COMPLETE:
-                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
+                    Rlog.d(LOG_TAG, "CallManager: handleMessage (EVENT_MMI_COMPLETE)");
                     mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
                     break;
                 case EVENT_ECM_TIMER_RESET:
diff --git a/src/java/com/android/internal/telephony/CallTracker.java b/src/java/com/android/internal/telephony/CallTracker.java
index ad64a4a..31c5e42 100644
--- a/src/java/com/android/internal/telephony/CallTracker.java
+++ b/src/java/com/android/internal/telephony/CallTracker.java
@@ -16,10 +16,13 @@
 
 package com.android.internal.telephony;
 
+import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
 import android.text.TextUtils;
 
 import java.io.FileDescriptor;
@@ -203,8 +206,20 @@
         if (dialNumber == null) {
             return dialNumber;
         }
-        String[] convertMaps = phone.getContext().getResources().getStringArray(
-                com.android.internal.R.array.dial_string_replace);
+        String[] convertMaps = null;
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle bundle = configManager.getConfig();
+        if (bundle != null) {
+            convertMaps =
+                    bundle.getStringArray(CarrierConfigManager.KEY_DIAL_STRING_REPLACE_STRING_ARRAY);
+        }
+        if (convertMaps == null) {
+            // By default no replacement is necessary
+            log("convertNumberIfNecessary convertMaps is null");
+            return dialNumber;
+        }
+
         log("convertNumberIfNecessary Roaming"
             + " convertMaps.length " + convertMaps.length
             + " dialNumber.length() " + dialNumber.length());
@@ -214,39 +229,30 @@
         }
 
         String[] entry;
-        String[] tmpArray;
         String outNumber = "";
-        boolean needConvert = false;
         for(String convertMap : convertMaps) {
             log("convertNumberIfNecessary: " + convertMap);
+            // entry format is  "dialStringToReplace:dialStringReplacement"
             entry = convertMap.split(":");
-            if (entry.length > 1) {
-                tmpArray = entry[1].split(",");
-                if (!TextUtils.isEmpty(entry[0]) && dialNumber.equals(entry[0])) {
-                    if (tmpArray.length >= 2 && !TextUtils.isEmpty(tmpArray[1])) {
-                        if (compareGid1(phone, tmpArray[1])) {
-                            needConvert = true;
-                        }
-                    } else if (outNumber.isEmpty()) {
-                        needConvert = true;
-                    }
-
-                    if (needConvert) {
-                        if(!TextUtils.isEmpty(tmpArray[0]) && tmpArray[0].endsWith("MDN")) {
-                            String mdn = phone.getLine1Number();
-                            if (!TextUtils.isEmpty(mdn) ) {
-                                if (mdn.startsWith("+")) {
-                                    outNumber = mdn;
-                                } else {
-                                    outNumber = tmpArray[0].substring(0, tmpArray[0].length() -3)
-                                            + mdn;
-                                }
+            if (entry != null && entry.length > 1) {
+                String dsToReplace = entry[0];
+                String dsReplacement = entry[1];
+                if (!TextUtils.isEmpty(dsToReplace) && dialNumber.equals(dsToReplace)) {
+                    // Needs to be converted
+                    if (!TextUtils.isEmpty(dsReplacement) && dsReplacement.endsWith("MDN")) {
+                        String mdn = phone.getLine1Number();
+                        if (!TextUtils.isEmpty(mdn)) {
+                            if (mdn.startsWith("+")) {
+                                outNumber = mdn;
+                            } else {
+                                outNumber = dsReplacement.substring(0, dsReplacement.length() -3)
+                                        + mdn;
                             }
-                        } else {
-                            outNumber = tmpArray[0];
                         }
-                        needConvert = false;
+                    } else {
+                        outNumber = dsReplacement;
                     }
+                    break;
                 }
             }
         }
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
new file mode 100644
index 0000000..2b91720
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.provider.Settings;
+import android.telephony.Rlog;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Carrier Action Agent(CAA) paired with
+ * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent},
+ * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules,
+ * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean)
+ * carrierActionSetRadioEnabled} for example.
+ *
+ * CAA supports dynamic registration where different telephony modules could listen for a specific
+ * carrier action event and implement their own handler. CCA will dispatch the event to all
+ * interested parties and maintain the received action states internally for future inspection.
+ * Each CarrierActionAgent is associated with a phone object.
+ */
+public class CarrierActionAgent extends Handler {
+    private static final String LOG_TAG = "CarrierActionAgent";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
+
+    /** A list of carrier actions */
+    public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED      = 0;
+    public static final int CARRIER_ACTION_SET_RADIO_ENABLED             = 1;
+    public static final int CARRIER_ACTION_RESET                         = 2;
+
+    /** Member variables */
+    private final Phone mPhone;
+    /** registrant list per carrier action */
+    private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList();
+    private RegistrantList mRadioEnableRegistrants = new RegistrantList();
+    /** local log for carrier actions */
+    private LocalLog mMeteredApnEnabledLog = new LocalLog(10);
+    private LocalLog mRadioEnabledLog = new LocalLog(10);
+    /** carrier actions, true by default */
+    private Boolean mCarrierActionOnMeteredApnEnabled = true;
+    private Boolean mCarrierActionOnRadioEnabled = true;
+    /** content observer for APM change */
+    private final SettingsObserver mSettingsObserver;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+            if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
+                if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+                    // ignore rebroadcast since carrier apps are direct boot aware.
+                    return;
+                }
+                if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState) ||
+                        IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
+                    sendEmptyMessage(CARRIER_ACTION_RESET);
+                }
+            }
+        }
+    };
+
+    private class SettingsObserver extends ContentObserver {
+        SettingsObserver() {
+            super(null);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0) {
+                sendEmptyMessage(CARRIER_ACTION_RESET);
+            }
+        }
+    }
+
+    /** Constructor */
+    public CarrierActionAgent(Phone phone) {
+        mPhone = phone;
+        mPhone.getContext().registerReceiver(mReceiver,
+                new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+        mSettingsObserver = new SettingsObserver();
+        mPhone.getContext().getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
+                false, mSettingsObserver);
+        if (DBG) log("Creating CarrierActionAgent");
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+                mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
+                log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
+                mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
+                        + mCarrierActionOnMeteredApnEnabled);
+                mMeteredApnEnableRegistrants.notifyRegistrants(
+                        new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
+                break;
+            case CARRIER_ACTION_SET_RADIO_ENABLED:
+                mCarrierActionOnRadioEnabled = (boolean) msg.obj;
+                log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
+                mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
+                mRadioEnableRegistrants.notifyRegistrants(
+                        new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
+                break;
+            case CARRIER_ACTION_RESET:
+                log("CARRIER_ACTION_RESET");
+                carrierActionSetMeteredApnsEnabled(true);
+                carrierActionSetRadioEnabled(true);
+                // notify configured carrier apps for reset
+                mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
+                        new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+                break;
+            default:
+                loge("Unknown carrier action: " + msg.what);
+        }
+    }
+
+    /**
+     * Return current carrier action values
+     */
+    public Object getCarrierActionValue(int action) {
+        Object val = getCarrierAction(action);
+        if (val == null) {
+            throw new IllegalArgumentException("invalid carrier action: " + action);
+        }
+        return val;
+    }
+
+    /**
+     * Action set from carrier app to enable/disable radio
+     */
+    public void carrierActionSetRadioEnabled(boolean enabled) {
+        sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
+    }
+
+    /**
+     * Action set from carrier app to enable/disable metered APNs
+     */
+    public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
+        sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
+    }
+
+    private RegistrantList getRegistrantsFromAction(int action) {
+        switch (action) {
+            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+                return mMeteredApnEnableRegistrants;
+            case CARRIER_ACTION_SET_RADIO_ENABLED:
+                return mRadioEnableRegistrants;
+            default:
+                loge("Unsupported action: " + action);
+                return null;
+        }
+    }
+
+    private Object getCarrierAction(int action) {
+        switch (action) {
+            case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+                return mCarrierActionOnMeteredApnEnabled;
+            case CARRIER_ACTION_SET_RADIO_ENABLED:
+                return mCarrierActionOnRadioEnabled;
+            default:
+                loge("Unsupported action: " + action);
+                return null;
+        }
+    }
+
+    /**
+     * Register with CAA for a specific event.
+     * @param action which carrier action registrant is interested in
+     * @param notifyNow if carrier action has once set, notify registrant right after
+     *                  registering, so that registrants will get the latest carrier action.
+     */
+    public void registerForCarrierAction(int action, Handler h, int what, Object obj,
+                                         boolean notifyNow) {
+        Object carrierAction = getCarrierAction(action);
+        if (carrierAction == null) {
+            throw new IllegalArgumentException("invalid carrier action: " + action);
+        }
+        RegistrantList list = getRegistrantsFromAction(action);
+        Registrant r = new Registrant(h, what, obj);
+        list.add(r);
+        if (notifyNow) {
+            r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
+        }
+    }
+
+    /**
+     * Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
+     * @param action which carrier action caller is no longer interested in
+     */
+    public void unregisterForCarrierAction(Handler h, int action) {
+        RegistrantList list = getRegistrantsFromAction(action);
+        if (list == null) {
+            throw new IllegalArgumentException("invalid carrier action: " + action);
+        }
+        list.remove(h);
+    }
+
+    @VisibleForTesting
+    public ContentObserver getContentObserver() {
+        return mSettingsObserver;
+    }
+
+    private void log(String s) {
+        Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+    }
+
+    private void loge(String s) {
+        Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+    }
+
+    private void logv(String s) {
+        Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
+        ipw.increaseIndent();
+        mMeteredApnEnabledLog.dump(fd, ipw, args);
+        ipw.decreaseIndent();
+
+        pw.println(" mCarrierActionOnRadioEnabled Log:");
+        ipw.increaseIndent();
+        mRadioEnabledLog.dump(fd, ipw, args);
+        ipw.decreaseIndent();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
index 3123ccb..ab010cc 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
@@ -28,6 +28,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.carrier.CarrierService;
 import android.telephony.SubscriptionManager;
@@ -48,6 +50,12 @@
 public class CarrierServiceBindHelper {
     private static final String LOG_TAG = "CarrierSvcBindHelper";
 
+    /**
+     * How long to linger a binding after an app loses carrier privileges, as long as no new
+     * binding comes in to take its place.
+     */
+    private static final int UNBIND_DELAY_MILLIS = 30 * 1000; // 30 seconds
+
     private Context mContext;
     private AppBinding[] mBindings;
     private String[] mLastSimState;
@@ -70,6 +78,7 @@
     };
 
     private static final int EVENT_REBIND = 0;
+    private static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1;
 
     private Handler mHandler = new Handler() {
         @Override
@@ -83,6 +92,10 @@
                     log("Rebinding if necessary for phoneId: " + binding.getPhoneId());
                     binding.rebind();
                     break;
+                case EVENT_PERFORM_IMMEDIATE_UNBIND:
+                    binding = (AppBinding) msg.obj;
+                    binding.performImmediateUnbind();
+                    break;
             }
         }
     };
@@ -129,6 +142,7 @@
         private long lastUnbindMillis;
         private String carrierPackage;
         private String carrierServiceClass;
+        private long mUnbindScheduledUptimeMillis = -1;
 
         public AppBinding(int phoneId) {
             this.phoneId = phoneId;
@@ -158,15 +172,16 @@
 
             if (carrierPackageNames == null || carrierPackageNames.size() <= 0) {
                 log("No carrier app for: " + phoneId);
-                unbind();
+                // Unbind after a delay in case this is a temporary blip in carrier privileges.
+                unbind(false /* immediate */);
                 return;
             }
 
             log("Found carrier app: " + carrierPackageNames);
             String candidateCarrierPackage = carrierPackageNames.get(0);
-            // If we are binding to a different package, unbind from the current one.
+            // If we are binding to a different package, unbind immediately from the current one.
             if (!TextUtils.equals(carrierPackage, candidateCarrierPackage)) {
-                unbind();
+                unbind(true /* immediate */);
             }
 
             // Look up the carrier service
@@ -187,15 +202,17 @@
             if (metadata == null ||
                 !metadata.getBoolean("android.service.carrier.LONG_LIVED_BINDING", false)) {
                 log("Carrier app does not want a long lived binding");
-                unbind();
+                unbind(true /* immediate */);
                 return;
             }
 
             if (!TextUtils.equals(carrierServiceClass, candidateServiceClass)) {
-                // Unbind if the carrier service component has changed.
-                unbind();
+                // Unbind immediately if the carrier service component has changed.
+                unbind(true /* immediate */);
             } else if (connection != null) {
-                // Component is unchanged and connection is up - do nothing.
+                // Component is unchanged and connection is up - do nothing, but cancel any
+                // scheduled unbinds.
+                cancelScheduledUnbind();
                 return;
             }
 
@@ -212,8 +229,9 @@
 
             String error;
             try {
-                if (mContext.bindService(carrierService, connection, Context.BIND_AUTO_CREATE |
-                            Context.BIND_FOREGROUND_SERVICE)) {
+                if (mContext.bindServiceAsUser(carrierService, connection,
+                        Context.BIND_AUTO_CREATE |  Context.BIND_FOREGROUND_SERVICE,
+                        mHandler, Process.myUserHandle())) {
                     return;
                 }
 
@@ -224,19 +242,46 @@
 
             log("Unable to bind to " + carrierPackage + " for phone " + phoneId +
                 ". Error: " + error);
-            unbind();
+            unbind(true /* immediate */);
         }
 
-        void unbind() {
+        /**
+         * Release the binding.
+         *
+         * @param immediate whether the binding should be released immediately or after a short
+         *                  delay. This should be true unless the reason for the unbind is that no
+         *                  app has carrier privileges, in which case it is useful to delay
+         *                  unbinding in case this is a temporary SIM blip.
+         */
+        void unbind(boolean immediate) {
             if (connection == null) {
+                // Already fully unbound.
                 return;
             }
 
+            // Only let the binding linger if a delayed unbind is requested *and* the connection is
+            // currently active. If the connection is down, unbind immediately as the app is likely
+            // not running anyway and it may be a permanent disconnection (e.g. the app was
+            // disabled).
+            if (immediate || !connection.connected) {
+                cancelScheduledUnbind();
+                performImmediateUnbind();
+            } else if (mUnbindScheduledUptimeMillis == -1) {
+                long currentUptimeMillis = SystemClock.uptimeMillis();
+                mUnbindScheduledUptimeMillis = currentUptimeMillis + UNBIND_DELAY_MILLIS;
+                log("Scheduling unbind in " + UNBIND_DELAY_MILLIS + " millis");
+                mHandler.sendMessageAtTime(
+                        mHandler.obtainMessage(EVENT_PERFORM_IMMEDIATE_UNBIND, this),
+                        mUnbindScheduledUptimeMillis);
+            }
+        }
+
+        private void performImmediateUnbind() {
             // Log debug information
             unbindCount++;
             lastUnbindMillis = System.currentTimeMillis();
 
-            // Clear package state now that no binding is present.
+            // Clear package state now that no binding is desired.
             carrierPackage = null;
             carrierServiceClass = null;
 
@@ -244,6 +289,12 @@
             log("Unbinding from carrier app");
             mContext.unbindService(connection);
             connection = null;
+            mUnbindScheduledUptimeMillis = -1;
+        }
+
+        private void cancelScheduledUnbind() {
+            mHandler.removeMessages(EVENT_PERFORM_IMMEDIATE_UNBIND);
+            mUnbindScheduledUptimeMillis = -1;
         }
 
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -253,6 +304,7 @@
             pw.println("  lastBindStartMillis: " + lastBindStartMillis);
             pw.println("  unbindCount: " + unbindCount);
             pw.println("  lastUnbindMillis: " + lastUnbindMillis);
+            pw.println("  mUnbindScheduledUptimeMillis: " + mUnbindScheduledUptimeMillis);
             pw.println();
         }
     }
@@ -322,7 +374,7 @@
                 }
                 if (appBindingPackage == null || isBindingForPackage) {
                     if (forceUnbind) {
-                        appBinding.unbind();
+                        appBinding.unbind(true /* immediate */);
                     }
                     appBinding.rebind();
                 }
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 735bfe2..9865d1b 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -30,6 +30,8 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
 
+import com.android.internal.telephony.util.NotificationChannelController;
+
 /**
  * This contains Carrier specific logic based on the states/events
  * managed in ServiceStateTracker.
@@ -174,6 +176,7 @@
                 .setStyle(new Notification.BigTextStyle().bigText(details))
                 .setContentText(details)
                 .setContentIntent(settingsIntent)
+                .setChannel(NotificationChannelController.CHANNEL_ID_ALERT)
                 .build();
 
         notificationManager.notify(NOTIFICATION_ID, mNotification);
diff --git a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
new file mode 100644
index 0000000..f3bc1fd
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.service.carrier.CarrierMessagingService;
+import android.service.carrier.ICarrierMessagingCallback;
+import android.service.carrier.ICarrierMessagingService;
+import android.service.carrier.MessagePdu;
+import android.telephony.CarrierMessagingServiceManager;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.uicc.UiccCard;
+import com.android.internal.telephony.uicc.UiccController;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Filters incoming SMS with carrier services.
+ * <p> A new instance must be created for filtering each message.
+ */
+public class CarrierServicesSmsFilter {
+    protected static final boolean DBG = true;
+
+    private final Context mContext;
+    private final Phone mPhone;
+    private final byte[][] mPdus;
+    private final int mDestPort;
+    private final String mPduFormat;
+    private final CarrierServicesSmsFilterCallbackInterface mCarrierServicesSmsFilterCallback;
+    private final String mLogTag;
+
+    @VisibleForTesting
+    public CarrierServicesSmsFilter(
+            Context context,
+            Phone phone,
+            byte[][] pdus,
+            int destPort,
+            String pduFormat,
+            CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback,
+            String logTag) {
+        mContext = context;
+        mPhone = phone;
+        mPdus = pdus;
+        mDestPort = destPort;
+        mPduFormat = pduFormat;
+        mCarrierServicesSmsFilterCallback = carrierServicesSmsFilterCallback;
+        mLogTag = logTag;
+    }
+
+    /**
+     * @return {@code true} if the SMS was handled by carrier services.
+     */
+    @VisibleForTesting
+    public boolean filter() {
+        Optional<String> carrierAppForFiltering = getCarrierAppPackageForFiltering();
+        List<String> smsFilterPackages = new ArrayList<>();
+        if (carrierAppForFiltering.isPresent()) {
+            smsFilterPackages.add(carrierAppForFiltering.get());
+        }
+        String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
+                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+        if (carrierImsPackage != null) {
+            smsFilterPackages.add(carrierImsPackage);
+        }
+        FilterAggregator filterAggregator = new FilterAggregator(smsFilterPackages.size());
+        for (String smsFilterPackage : smsFilterPackages) {
+            filterWithPackage(smsFilterPackage, filterAggregator);
+        }
+        boolean handled = smsFilterPackages.size() > 0;
+        return handled;
+    }
+
+    private Optional<String> getCarrierAppPackageForFiltering() {
+        List<String> carrierPackages = null;
+        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
+        if (card != null) {
+            carrierPackages = card.getCarrierPackageNamesForIntent(
+                    mContext.getPackageManager(),
+                    new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+        } else {
+            Rlog.e(mLogTag, "UiccCard not initialized.");
+        }
+        if (carrierPackages != null && carrierPackages.size() == 1) {
+            log("Found carrier package.");
+            return Optional.of(carrierPackages.get(0));
+        }
+
+        // It is possible that carrier app is not present as a CarrierPackage, but instead as a
+        // system app
+        List<String> systemPackages =
+                getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+
+        if (systemPackages != null && systemPackages.size() == 1) {
+            log("Found system package.");
+            return Optional.of(systemPackages.get(0));
+        }
+        logv("Unable to find carrier package: " + carrierPackages
+                + ", nor systemPackages: " + systemPackages);
+        return Optional.empty();
+    }
+
+    private void filterWithPackage(String packageName, FilterAggregator filterAggregator) {
+        CarrierSmsFilter smsFilter = new CarrierSmsFilter(mPdus, mDestPort, mPduFormat);
+        CarrierSmsFilterCallback smsFilterCallback =
+                new CarrierSmsFilterCallback(filterAggregator, smsFilter);
+        smsFilter.filterSms(packageName, smsFilterCallback);
+    }
+
+    private List<String> getSystemAppForIntent(Intent intent) {
+        List<String> packages = new ArrayList<String>();
+        PackageManager packageManager = mContext.getPackageManager();
+        List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
+        String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS";
+
+        for (ResolveInfo info : receivers) {
+            if (info.serviceInfo == null) {
+                loge("Can't get service information from " + info);
+                continue;
+            }
+            String packageName = info.serviceInfo.packageName;
+            if (packageManager.checkPermission(carrierFilterSmsPerm, packageName)
+                    == packageManager.PERMISSION_GRANTED) {
+                packages.add(packageName);
+                if (DBG) log("getSystemAppForIntent: added package " + packageName);
+            }
+        }
+        return packages;
+    }
+
+    private void log(String message) {
+        Rlog.d(mLogTag, message);
+    }
+
+    private void loge(String message) {
+        Rlog.e(mLogTag, message);
+    }
+
+    private void logv(String message) {
+        Rlog.e(mLogTag, message);
+    }
+
+    /**
+     * Result of filtering SMS is returned in this callback.
+     */
+    @VisibleForTesting
+    public interface CarrierServicesSmsFilterCallbackInterface {
+        void onFilterComplete(int result);
+    }
+
+    /**
+     * Asynchronously binds to the carrier messaging service, and filters out the message if
+     * instructed to do so by the carrier messaging service. A new instance must be used for every
+     * message.
+     */
+    private final class CarrierSmsFilter extends CarrierMessagingServiceManager {
+        private final byte[][] mPdus;
+        private final int mDestPort;
+        private final String mSmsFormat;
+        // Instantiated in filterSms.
+        private volatile CarrierSmsFilterCallback mSmsFilterCallback;
+
+        CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat) {
+            mPdus = pdus;
+            mDestPort = destPort;
+            mSmsFormat = smsFormat;
+        }
+
+        /**
+         * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated
+         * asynchronously once the service is ready using {@link #onServiceReady}.
+         */
+        void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) {
+            mSmsFilterCallback = smsFilterCallback;
+            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
+                loge("bindService() for carrier messaging service failed");
+                smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+            } else {
+                logv("bindService() for carrier messaging service succeeded");
+            }
+        }
+
+        /**
+         * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
+         * delivered to {@code smsFilterCallback}.
+         */
+        @Override
+        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+            try {
+                carrierMessagingService.filterSms(
+                        new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
+                        mPhone.getSubId(), mSmsFilterCallback);
+            } catch (RemoteException e) {
+                loge("Exception filtering the SMS: " + e);
+                mSmsFilterCallback.onFilterComplete(
+                        CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+            }
+        }
+    }
+
+    /**
+     * A callback used to notify the platform of the carrier messaging app filtering result. Once
+     * the result is ready, the carrier messaging service connection is disposed.
+     */
+    private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub {
+        private final FilterAggregator mFilterAggregator;
+        private final CarrierMessagingServiceManager mCarrierMessagingServiceManager;
+
+        CarrierSmsFilterCallback(FilterAggregator filterAggregator,
+                                 CarrierMessagingServiceManager carrierMessagingServiceManager) {
+            mFilterAggregator = filterAggregator;
+            mCarrierMessagingServiceManager = carrierMessagingServiceManager;
+        }
+
+        /**
+         * This method should be called only once.
+         */
+        @Override
+        public void onFilterComplete(int result) {
+            mCarrierMessagingServiceManager.disposeConnection(mContext);
+            mFilterAggregator.onFilterComplete(result);
+        }
+
+        @Override
+        public void onSendSmsComplete(int result, int messageRef) {
+            loge("Unexpected onSendSmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
+            loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
+            loge("Unexpected onSendMmsComplete call with result: " + result);
+        }
+
+        @Override
+        public void onDownloadMmsComplete(int result) {
+            loge("Unexpected onDownloadMmsComplete call with result: " + result);
+        }
+    }
+
+    private final class FilterAggregator {
+        private final Object mFilterLock = new Object();
+        private int mNumPendingFilters;
+        private int mFilterResult;
+
+        FilterAggregator(int numFilters) {
+            mNumPendingFilters = numFilters;
+            mFilterResult = CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT;
+        }
+
+        void onFilterComplete(int result) {
+            synchronized (mFilterLock) {
+                mNumPendingFilters--;
+                combine(result);
+                if (mNumPendingFilters == 0) {
+                    // Calling identity was the CarrierMessagingService in this callback, change it
+                    // back to ours.
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mCarrierServicesSmsFilterCallback.onFilterComplete(mFilterResult);
+                    } finally {
+                        // return back to the CarrierMessagingService, restore the calling identity.
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            }
+        }
+
+        private void combine(int result) {
+            mFilterResult = mFilterResult | result;
+        }
+    }
+}
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index 19a508c..4d6d464 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -16,144 +16,262 @@
 package com.android.internal.telephony;
 
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
+
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
 
 /**
  * This class act as an CarrierSignalling Agent.
- * it load registered carrier signalling receivers from Carrier Config and cache the result to avoid
+ * it load registered carrier signalling receivers from carrier config, cache the result to avoid
  * repeated polling and send the intent to the interested receivers.
- * each CarrierSignalAgent is associated with a phone object.
+ * Each CarrierSignalAgent is associated with a phone object.
  */
 public class CarrierSignalAgent {
 
-    private static final String LOG_TAG = "CarrierSignalAgent";
+    private static final String LOG_TAG = CarrierSignalAgent.class.getSimpleName();
     private static final boolean DBG = true;
+    private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
+    private static final boolean WAKE = true;
+    private static final boolean NO_WAKE = false;
+
+    /** delimiters for parsing config of the form: pakName./receiverName : signal1, signal2,..*/
+    private static final String COMPONENT_NAME_DELIMITER = "\\s*:\\s*";
+    private static final String CARRIER_SIGNAL_DELIMITER = "\\s*,\\s*";
 
     /** Member variables */
     private final Phone mPhone;
+
     /**
-     * This is a map of intent action -> string array of carrier signal receiver names which are
-     * interested in this intent action
+     * This is a map of intent action -> array list of component name of statically registered
+     * carrier signal receivers(wakeup receivers).
+     * Those intents are declared in the Manifest files, aiming to wakeup broadcast receivers.
+     * Carrier apps should be careful when configuring the wake signal list to avoid unnecessary
+     * wakeup.
+     * @see CarrierConfigManager#KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY
      */
-    private final HashMap<String, String[]> mCachedCarrierSignalReceiverNames =
-            new HashMap<>();
+    private final Map<String, List<ComponentName>> mCachedWakeSignalConfigs = new HashMap<>();
+
     /**
-     * This is a map of intent action -> carrier config key of signal receiver names which are
-     * interested in this intent action
+     * This is a map of intent action -> array list of component name of dynamically registered
+     * carrier signal receivers(non-wakeup receivers). Those intents will not wake up the apps.
+     * Note Carrier apps should avoid configuring no wake signals in there Manifest files.
+     * @see CarrierConfigManager#KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY
      */
-    private final Map<String, String> mIntentToCarrierConfigKeyMap =
-            new HashMap<String, String>() {{
-                put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
-                        CarrierConfigManager.KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY);
-                put(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
-                        CarrierConfigManager.KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY);
-                put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
-                        CarrierConfigManager.KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY);
-            }};
+    private final Map<String, List<ComponentName>> mCachedNoWakeSignalConfigs = new HashMap<>();
+
+    /**
+     * This is a list of supported signals from CarrierSignalAgent
+     */
+    private final Set<String> mCarrierSignalList = new HashSet<>(Arrays.asList(
+            TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
+            TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
+            TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+            TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+
+    private final LocalLog mErrorLocalLog = new LocalLog(20);
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (DBG) log("CarrierSignalAgent receiver action: " + action);
+            if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+                // notify carrier apps before cache get purged
+                if (mPhone.getIccCard() != null
+                        && IccCardConstants.State.ABSENT == mPhone.getIccCard().getState()) {
+                    notifyCarrierSignalReceivers(
+                            new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+                }
+                loadCarrierConfig();
+            }
+        }
+    };
 
     /** Constructor */
     public CarrierSignalAgent(Phone phone) {
         mPhone = phone;
+        loadCarrierConfig();
+        // reload configurations on CARRIER_CONFIG_CHANGED
+        mPhone.getContext().registerReceiver(mReceiver,
+                new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
     }
 
     /**
-     * Read carrier signalling receiver name from CarrierConfig based on the intent type
-     * @return array of receiver Name: the package (a String) name / the class (a String) name
+     * load carrier config and cached the results into a hashMap action -> array list of components.
      */
-    private String[] getCarrierSignalReceiverName(String intentAction) {
-        String receiverType = mIntentToCarrierConfigKeyMap.get(intentAction);
-        if(receiverType == null) {
-            return null;
+    private void loadCarrierConfig() {
+        CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle b = null;
+        if (configManager != null) {
+            b = configManager.getConfig();
         }
-        String[] receiverNames = mCachedCarrierSignalReceiverNames.get(intentAction);
-        // In case of cache miss, we need to look up/load from carrier config.
-        if (!mCachedCarrierSignalReceiverNames.containsKey(intentAction)) {
-            CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
-                    .getSystemService(Context.CARRIER_CONFIG_SERVICE);
-            PersistableBundle b = null;
-            if (configManager != null) {
-                b = configManager.getConfig();
+        if (b != null) {
+            synchronized (mCachedWakeSignalConfigs) {
+                mCachedWakeSignalConfigs.clear();
+                log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY);
+                parseAndCache(b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY),
+                        mCachedWakeSignalConfigs);
             }
-            if (b != null) {
-                receiverNames = b.getStringArray(receiverType);
-                if(receiverNames!=null) {
-                    for(String name: receiverNames) {
-                        Rlog.d("loadCarrierSignalReceiverNames: ", name);
+
+            synchronized (mCachedNoWakeSignalConfigs) {
+                mCachedNoWakeSignalConfigs.clear();
+                log("Loading carrier config: "
+                        + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY);
+                parseAndCache(b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY),
+                        mCachedNoWakeSignalConfigs);
+            }
+        }
+    }
+
+    /**
+     * Parse each config with the form {pakName./receiverName : signal1, signal2,.} and cached the
+     * result internally to avoid repeated polling
+     * @see #CARRIER_SIGNAL_DELIMITER
+     * @see #COMPONENT_NAME_DELIMITER
+     * @param configs raw information from carrier config
+     */
+    private void parseAndCache(String[] configs,
+                               Map<String, List<ComponentName>> cachedConfigs) {
+        if (!ArrayUtils.isEmpty(configs)) {
+            for (String config : configs) {
+                if (!TextUtils.isEmpty(config)) {
+                    String[] splitStr = config.trim().split(COMPONENT_NAME_DELIMITER, 2);
+                    if (splitStr.length == 2) {
+                        ComponentName componentName = ComponentName
+                                .unflattenFromString(splitStr[0]);
+                        if (componentName == null) {
+                            loge("Invalid component name: " + splitStr[0]);
+                            continue;
+                        }
+                        String[] signals = splitStr[1].split(CARRIER_SIGNAL_DELIMITER);
+                        for (String s : signals) {
+                            if (!mCarrierSignalList.contains(s)) {
+                                loge("Invalid signal name: " + s);
+                                continue;
+                            }
+                            List<ComponentName> componentList = cachedConfigs.get(s);
+                            if (componentList == null) {
+                                componentList = new ArrayList<>();
+                                cachedConfigs.put(s, componentList);
+                            }
+                            componentList.add(componentName);
+                            if (VDBG) {
+                                logv("Add config " + "{signal: " + s
+                                        + " componentName: " + componentName + "}");
+                            }
+                        }
+                    } else {
+                        loge("invalid config format: " + config);
                     }
                 }
             }
-            mCachedCarrierSignalReceiverNames.put(intentAction, receiverNames);
         }
-        return receiverNames;
     }
 
     /**
-     * Check if there are registered carrier broadcast receivers to handle any registered intents.
+     * Check if there are registered carrier broadcast receivers to handle the passing intent
      */
-    public boolean hasRegisteredCarrierSignalReceivers() {
-        for(String intent : mIntentToCarrierConfigKeyMap.keySet()) {
-            if(!ArrayUtils.isEmpty(getCarrierSignalReceiverName(intent))) {
-                return true;
-            }
-        }
-        return false;
+    public boolean hasRegisteredReceivers(String action) {
+        return mCachedWakeSignalConfigs.containsKey(action)
+                || mCachedNoWakeSignalConfigs.containsKey(action);
     }
 
-    public boolean notifyCarrierSignalReceivers(Intent intent) {
-        // Read a list of broadcast receivers from carrier config manager
-        // which are interested on certain intent type
-        String[] receiverName = getCarrierSignalReceiverName(intent.getAction());
-        if (receiverName == null) {
-            loge("Carrier receiver name is null");
-            return false;
-        }
+    /**
+     * Broadcast the intents explicitly.
+     * Some sanity check will be applied before broadcasting.
+     * - for non-wakeup(runtime) receivers, make sure the intent is not declared in their manifests
+     * and apply FLAG_EXCLUDE_STOPPED_PACKAGES to avoid wake-up
+     * - for wakeup(manifest) receivers, make sure there are matched receivers with registered
+     * intents.
+     *
+     * @param intent intent which signals carrier apps
+     * @param receivers a list of component name for broadcast receivers.
+     *                  Those receivers could either be statically declared in Manifest or
+     *                  registered during run-time.
+     * @param wakeup true indicate wakeup receivers otherwise non-wakeup receivers
+     */
+    private void broadcast(Intent intent, List<ComponentName> receivers, boolean wakeup) {
         final PackageManager packageManager = mPhone.getContext().getPackageManager();
-        boolean ret = false;
+        for (ComponentName name : receivers) {
+            Intent signal = new Intent(intent);
+            signal.setComponent(name);
 
-        for(String name : receiverName) {
-            ComponentName componentName = ComponentName.unflattenFromString(name);
-            if (componentName == null) {
-                loge("Carrier receiver name could not be parsed");
-                return false;
-            }
-            intent.setComponent(componentName);
-            // Check if broadcast receiver is available
-            if (packageManager.queryBroadcastReceivers(intent,
+            if (wakeup && packageManager.queryBroadcastReceivers(signal,
                     PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
-                loge("Carrier signal receiver is configured, but not available: " + name);
-                break;
+                loge("Carrier signal receivers are configured but unavailable: "
+                        + signal.getComponent());
+                return;
+            }
+            if (!wakeup && !packageManager.queryBroadcastReceivers(signal,
+                    PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+                loge("Runtime signals shouldn't be configured in Manifest: "
+                        + signal.getComponent());
+                return;
             }
 
-            intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            signal.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
+            signal.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            if (!wakeup) signal.setFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
 
             try {
-                mPhone.getContext().sendBroadcast(intent);
-                if (DBG) log("send Intent to carrier signal receiver with action: " +
-                        intent.getAction());
-                ret = true;
+                mPhone.getContext().sendBroadcast(signal);
+                if (DBG) {
+                    log("Sending signal " + signal.getAction() + ((signal.getComponent() != null)
+                            ? " to the carrier signal receiver: " + signal.getComponent() : ""));
+                }
             } catch (ActivityNotFoundException e) {
-                loge("sendBroadcast failed: " + e);
+                loge("Send broadcast failed: " + e);
+            }
+        }
+    }
+
+    /**
+     * Match the intent against cached tables to find a list of registered carrier signal
+     * receivers and broadcast the intent.
+     * @param intent broadcasting intent, it could belong to wakeup, non-wakeup signal list or both
+     *
+     */
+    public void notifyCarrierSignalReceivers(Intent intent) {
+        List<ComponentName> receiverList;
+
+        synchronized (mCachedWakeSignalConfigs) {
+            receiverList = mCachedWakeSignalConfigs.get(intent.getAction());
+            if (!ArrayUtils.isEmpty(receiverList)) {
+                broadcast(intent, receiverList, WAKE);
             }
         }
 
-        return ret;
-    }
-
-    /* Clear cached receiver names */
-    public void reset() {
-        mCachedCarrierSignalReceiverNames.clear();
+        synchronized (mCachedNoWakeSignalConfigs) {
+            receiverList = mCachedNoWakeSignalConfigs.get(intent.getAction());
+            if (!ArrayUtils.isEmpty(receiverList)) {
+                broadcast(intent, receiverList, NO_WAKE);
+            }
+        }
     }
 
     private void log(String s) {
@@ -161,6 +279,33 @@
     }
 
     private void loge(String s) {
+        mErrorLocalLog.log(s);
         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
     }
+
+    private void logv(String s) {
+        Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        pw.println("mCachedWakeSignalConfigs:");
+        ipw.increaseIndent();
+        for (Map.Entry<String, List<ComponentName>> entry : mCachedWakeSignalConfigs.entrySet()) {
+            pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue());
+        }
+        ipw.decreaseIndent();
+
+        pw.println("mCachedNoWakeSignalConfigs:");
+        ipw.increaseIndent();
+        for (Map.Entry<String, List<ComponentName>> entry : mCachedNoWakeSignalConfigs.entrySet()) {
+            pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue());
+        }
+        ipw.decreaseIndent();
+
+        pw.println("error log:");
+        ipw.increaseIndent();
+        mErrorLocalLog.dump(fd, pw, args);
+        ipw.decreaseIndent();
+    }
 }
diff --git a/src/java/com/android/internal/telephony/CarrierSmsUtils.java b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
new file mode 100644
index 0000000..a64aea7
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+
+import java.util.List;
+
+/**
+ * This is a basic utility class for common Carrier SMS Functions
+ */
+public class CarrierSmsUtils {
+    protected static final boolean VDBG = false;
+    protected static final String TAG = CarrierSmsUtils.class.getSimpleName();
+
+    private static final String CARRIER_IMS_PACKAGE_KEY =
+            CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING;
+
+    /** Return a Carrier-overridden IMS package, if it exists and is a CarrierSmsFilter
+     *
+     * @param context calling context
+     * @param phone object from telephony
+     * @param intent that should match a CarrierSmsFilter
+     * @return the name of the IMS CarrierService package
+     */
+    @Nullable
+    public static String getCarrierImsPackageForIntent(
+            Context context, Phone phone, Intent intent) {
+
+        String carrierImsPackage = getCarrierImsPackage(context, phone);
+        if (carrierImsPackage == null) {
+            if (VDBG) Rlog.v(TAG, "No CarrierImsPackage override found");
+            return null;
+        }
+
+        PackageManager packageManager = context.getPackageManager();
+        List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
+        for (ResolveInfo info : receivers) {
+            if (info.serviceInfo == null) {
+                Rlog.e(TAG, "Can't get service information from " + info);
+                continue;
+            }
+
+            if (carrierImsPackage.equals(info.serviceInfo.packageName)) {
+                return carrierImsPackage;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private static String getCarrierImsPackage(Context context, Phone phone) {
+        CarrierConfigManager cm = (CarrierConfigManager) context.getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        if (cm == null) {
+            Rlog.e(TAG, "Failed to retrieve CarrierConfigManager");
+            return null;
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            PersistableBundle config = cm.getConfigForSubId(phone.getSubId());
+            if (config == null) {
+                if (VDBG) Rlog.v(TAG, "No CarrierConfig for subId:" + phone.getSubId());
+                return null;
+            }
+            return config.getString(CARRIER_IMS_PACKAGE_KEY, null);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private CarrierSmsUtils() {}
+}
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
index 5cb329a..4227148 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
@@ -16,16 +16,20 @@
 
 package com.android.internal.telephony;
 
+import static android.provider.Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG;
+
 import android.Manifest;
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.os.Message;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.provider.Telephony;
-import android.telephony.SubscriptionManager;
 import android.telephony.SmsCbMessage;
+import android.telephony.SubscriptionManager;
 
 /**
  * Dispatch new Cell Broadcasts to receivers. Acquires a private wakelock until the broadcast
@@ -82,16 +86,38 @@
         if (message.isEmergencyMessage()) {
             log("Dispatching emergency SMS CB, SmsCbMessage is: " + message);
             intent = new Intent(Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
+            // Explicitly send the intent to the default cell broadcast receiver.
+            intent.setPackage(mContext.getResources().getString(
+                    com.android.internal.R.string.config_defaultCellBroadcastReceiverPkg));
             receiverPermission = Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
             appOp = AppOpsManager.OP_RECEIVE_EMERGECY_SMS;
         } else {
             log("Dispatching SMS CB, SmsCbMessage is: " + message);
             intent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
+            // Send implicit intent since there are various 3rd party carrier apps listen to
+            // this intent.
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             receiverPermission = Manifest.permission.RECEIVE_SMS;
             appOp = AppOpsManager.OP_RECEIVE_SMS;
         }
+
         intent.putExtra("message", message);
         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
+
+        if (Build.IS_DEBUGGABLE) {
+            // Send additional broadcast intent to the specified package. This is only for sl4a
+            // automation tests.
+            final String additionalPackage = Settings.Secure.getString(
+                    mContext.getContentResolver(), CMAS_ADDITIONAL_BROADCAST_PKG);
+            if (additionalPackage != null) {
+                Intent additionalIntent = new Intent(intent);
+                additionalIntent.setPackage(additionalPackage);
+                mContext.sendOrderedBroadcastAsUser(additionalIntent, UserHandle.ALL,
+                        receiverPermission, appOp, null, getHandler(), Activity.RESULT_OK, null,
+                        null);
+            }
+        }
+
         mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission, appOp,
                 mReceiver, getHandler(), Activity.RESULT_OK, null, null);
     }
diff --git a/src/java/com/android/internal/telephony/ClientWakelockAccountant.java b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
new file mode 100644
index 0000000..c47faab
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.ClientRequestStats;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
+
+public class ClientWakelockAccountant {
+    public static final String LOG_TAG = "ClientWakelockAccountant: ";
+
+    @VisibleForTesting
+    public ClientRequestStats mRequestStats = new ClientRequestStats();
+    @VisibleForTesting
+    public ArrayList<RilWakelockInfo> mPendingRilWakelocks = new ArrayList<>();
+
+    @VisibleForTesting
+    public ClientWakelockAccountant(String callingPackage) {
+        mRequestStats.setCallingPackage(callingPackage);
+    }
+
+    @VisibleForTesting
+    public void startAttributingWakelock(int request,
+            int token, int concurrentRequests, long time) {
+
+        RilWakelockInfo wlInfo = new RilWakelockInfo(request, token, concurrentRequests, time);
+        synchronized (mPendingRilWakelocks) {
+            mPendingRilWakelocks.add(wlInfo);
+        }
+    }
+
+    @VisibleForTesting
+    public void stopAttributingWakelock(int request, int token, long time) {
+        RilWakelockInfo wlInfo = removePendingWakelock(request, token);
+        if (wlInfo != null) {
+            completeRequest(wlInfo, time);
+        }
+    }
+
+    @VisibleForTesting
+    public void stopAllPendingRequests(long time) {
+        synchronized (mPendingRilWakelocks) {
+            for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+                completeRequest(wlInfo, time);
+            }
+            mPendingRilWakelocks.clear();
+        }
+    }
+
+    @VisibleForTesting
+    public void changeConcurrentRequests(int concurrentRequests, long time) {
+        synchronized (mPendingRilWakelocks) {
+            for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+                wlInfo.updateConcurrentRequests(concurrentRequests, time);
+            }
+        }
+    }
+
+    private void completeRequest(RilWakelockInfo wlInfo, long time) {
+        wlInfo.setResponseTime(time);
+        synchronized (mRequestStats) {
+            mRequestStats.addCompletedWakelockTime(wlInfo.getWakelockTimeAttributedToClient());
+            mRequestStats.incrementCompletedRequestsCount();
+            mRequestStats.updateRequestHistograms(wlInfo.getRilRequestSent(),
+                    (int) wlInfo.getWakelockTimeAttributedToClient());
+        }
+    }
+
+    @VisibleForTesting
+    public int getPendingRequestCount() {
+        return mPendingRilWakelocks.size();
+    }
+
+    @VisibleForTesting
+    public synchronized long updatePendingRequestWakelockTime(long uptime) {
+        long totalPendingWakelockTime = 0;
+        synchronized (mPendingRilWakelocks) {
+            for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+                wlInfo.updateTime(uptime);
+                totalPendingWakelockTime += wlInfo.getWakelockTimeAttributedToClient();
+            }
+        }
+        synchronized (mRequestStats) {
+            mRequestStats.setPendingRequestsCount(getPendingRequestCount());
+            mRequestStats.setPendingRequestsWakelockTime(totalPendingWakelockTime);
+        }
+        return totalPendingWakelockTime;
+    }
+
+    private RilWakelockInfo removePendingWakelock(int request, int token) {
+        RilWakelockInfo result = null;
+        synchronized (mPendingRilWakelocks) {
+            for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+                if ((wlInfo.getTokenNumber() == token) &&
+                    (wlInfo.getRilRequestSent() == request)) {
+                    result = wlInfo;
+                }
+            }
+            if( result != null ) {
+                mPendingRilWakelocks.remove(result);
+            }
+        }
+        if(result == null) {
+            Rlog.w(LOG_TAG, "Looking for Request<" + request + "," + token + "> in "
+                + mPendingRilWakelocks);
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ClientWakelockAccountant{" +
+                "mRequestStats=" + mRequestStats +
+                ", mPendingRilWakelocks=" + mPendingRilWakelocks +
+                '}';
+    }
+}
diff --git a/src/java/com/android/internal/telephony/ClientWakelockTracker.java b/src/java/com/android/internal/telephony/ClientWakelockTracker.java
new file mode 100644
index 0000000..5bec60b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ClientWakelockTracker.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.telephony;
+
+import android.os.SystemClock;
+import android.telephony.ClientRequestStats;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ClientWakelockTracker {
+    public static final String LOG_TAG = "ClientWakelockTracker";
+    @VisibleForTesting
+    public HashMap<String, ClientWakelockAccountant> mClients =
+        new HashMap<String, ClientWakelockAccountant>();
+    @VisibleForTesting
+    public ArrayList<ClientWakelockAccountant> mActiveClients = new ArrayList<>();
+
+    @VisibleForTesting
+    public void startTracking(String clientId, int requestId, int token, int numRequestsInQueue) {
+        ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+        long uptime = SystemClock.uptimeMillis();
+        client.startAttributingWakelock(requestId, token, numRequestsInQueue, uptime);
+        updateConcurrentRequests(numRequestsInQueue, uptime);
+        synchronized (mActiveClients) {
+            if (!mActiveClients.contains(client)) {
+                mActiveClients.add(client);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public void stopTracking(String clientId, int requestId, int token, int numRequestsInQueue) {
+        ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+        long uptime = SystemClock.uptimeMillis();
+        client.stopAttributingWakelock(requestId, token, uptime);
+        if(client.getPendingRequestCount() == 0) {
+            synchronized (mActiveClients) {
+                mActiveClients.remove(client);
+            }
+        }
+        updateConcurrentRequests(numRequestsInQueue, uptime);
+    }
+
+    @VisibleForTesting
+    public void stopTrackingAll() {
+        long uptime = SystemClock.uptimeMillis();
+        synchronized (mActiveClients) {
+            for (ClientWakelockAccountant client : mActiveClients) {
+                client.stopAllPendingRequests(uptime);
+            }
+            mActiveClients.clear();
+        }
+    }
+
+    List<ClientRequestStats> getClientRequestStats() {
+        List<ClientRequestStats> list;
+        long uptime = SystemClock.uptimeMillis();
+        synchronized (mClients) {
+            list = new ArrayList<>(mClients.size());
+            for (String key :  mClients.keySet()) {
+                ClientWakelockAccountant client = mClients.get(key);
+                client.updatePendingRequestWakelockTime(uptime);
+                list.add(new ClientRequestStats(client.mRequestStats));
+            }
+        }
+        return list;
+    }
+
+    private ClientWakelockAccountant getClientWakelockAccountant(String clientId) {
+        ClientWakelockAccountant client;
+        synchronized (mClients) {
+            if (mClients.containsKey(clientId)) {
+                client = mClients.get(clientId);
+            } else {
+                client = new ClientWakelockAccountant(clientId);
+                mClients.put(clientId, client);
+            }
+        }
+        return client;
+    }
+
+    private void updateConcurrentRequests(int numRequestsInQueue, long time) {
+        if(numRequestsInQueue != 0) {
+            synchronized (mActiveClients) {
+                for (ClientWakelockAccountant cI : mActiveClients) {
+                    cI.changeConcurrentRequests(numRequestsInQueue, time);
+                }
+            }
+        }
+    }
+
+    public boolean isClientActive(String clientId) {
+        ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+        synchronized (mActiveClients) {
+            if (mActiveClients.contains(client)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    void dumpClientRequestTracker() {
+        Rlog.d(RIL.RILJ_LOG_TAG, "-------mClients---------------");
+        synchronized (mClients) {
+            for (String key : mClients.keySet()) {
+                Rlog.d(RIL.RILJ_LOG_TAG, "Client : " + key);
+                Rlog.d(RIL.RILJ_LOG_TAG, mClients.get(key).toString());
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index f23905a..106ec54 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -16,19 +16,19 @@
 
 package com.android.internal.telephony;
 
+import android.os.Handler;
+import android.os.Message;
+import android.os.WorkSource;
+import android.service.carrier.CarrierIdentifier;
+import android.telephony.ClientRequestStats;
+
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.dataconnection.DataProfile;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import com.android.internal.telephony.RadioCapability;
 import com.android.internal.telephony.uicc.IccCardStatus;
 
-import android.os.Message;
-import android.os.Handler;
-import android.service.carrier.CarrierIdentifier;
-
 import java.util.List;
 
-
 /**
  * {@hide}
  */
@@ -190,10 +190,14 @@
 
     void registerForCallStateChanged(Handler h, int what, Object obj);
     void unregisterForCallStateChanged(Handler h);
-    void registerForVoiceNetworkStateChanged(Handler h, int what, Object obj);
-    void unregisterForVoiceNetworkStateChanged(Handler h);
-    void registerForDataNetworkStateChanged(Handler h, int what, Object obj);
-    void unregisterForDataNetworkStateChanged(Handler h);
+    /** Register for network state changed event */
+    void registerForNetworkStateChanged(Handler h, int what, Object obj);
+    /** Unregister from network state changed event */
+    void unregisterForNetworkStateChanged(Handler h);
+    /** Register for data call list changed event */
+    void registerForDataCallListChanged(Handler h, int what, Object obj);
+    /** Unregister from data call list changed event */
+    void unregisterForDataCallListChanged(Handler h);
 
     /** InCall voice privacy notifications */
     void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj);
@@ -1384,8 +1388,9 @@
      * Query neighboring cell ids
      *
      * @param response s callback message to cell ids
+     * @param workSource calling WorkSource
      */
-    void getNeighboringCids(Message response);
+    default void getNeighboringCids(Message response, WorkSource workSource){}
 
     /**
      * Request to enable/disable network state change notifications when
@@ -1599,26 +1604,17 @@
      *
      * @param radioTechnology
      *            Radio technology to use. Values is one of RIL_RADIO_TECHNOLOGY_*
-     * @param profile
-     *            Profile Number. Values is one of DATA_PROFILE_*
-     * @param apn
-     *            the APN to connect to if radio technology is GSM/UMTS.
-     *            Otherwise null for CDMA.
-     * @param user
-     *            the username for APN, or NULL
-     * @param password
-     *            the password for APN, or NULL
-     * @param authType
-     *            the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
-     * @param protocol
-     *            one of the PDP_type values in TS 27.007 section 10.1.1.
-     *            For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @param dataProfile
+     *            Data profile for data call setup
+     * @param isRoaming
+     *            Device is roaming or not
+     * @param allowRoaming
+     *            Flag indicating data roaming is enabled or not
      * @param result
      *            Callback message
      */
-    public void setupDataCall(int radioTechnology, int profile,
-            String apn, String user, String password, int authType,
-            String protocol, Message result);
+    void setupDataCall(int radioTechnology, DataProfile dataProfile, boolean isRoaming,
+                       boolean allowRoaming, Message result);
 
     /**
      * Deactivate packet data connection
@@ -1727,8 +1723,9 @@
      * AsyncResult.result is a of Collection<CellInfo>
      *
      * @param result is sent back to handler and result.obj is a AsyncResult
+     * @param workSource calling WorkSource
      */
-    void getCellInfoList(Message result);
+    default void getCellInfoList(Message result, WorkSource workSource) {}
 
     /**
      * Sets the minimum time in milli-seconds between when RIL_UNSOL_CELL_INFO_LIST
@@ -1744,8 +1741,9 @@
      * @param response.obj is AsyncResult ar when sent to associated handler
      *                        ar.exception carries exception on failure or null on success
      *                        otherwise the error.
+     * @param workSource calling WorkSource
      */
-    void setCellInfoListRate(int rateInMillis, Message response);
+    default void setCellInfoListRate(int rateInMillis, Message response, WorkSource workSource){}
 
     /**
      * Fires when RIL_UNSOL_CELL_INFO_LIST is received from the RIL.
@@ -1756,33 +1754,26 @@
     /**
      * Set Initial Attach Apn
      *
-     * @param apn
-     *            the APN to connect to if radio technology is GSM/UMTS.
-     * @param protocol
-     *            one of the PDP_type values in TS 27.007 section 10.1.1.
-     *            For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     * @param authType
-     *            authentication protocol used for this PDP context
-     *            (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
-     * @param username
-     *            the username for APN, or NULL
-     * @param password
-     *            the password for APN, or NULL
+     * @param dataProfile
+     *            data profile for initial APN attach
+     * @param isRoaming
+     *            indicating the device is roaming or not
      * @param result
      *            callback message contains the information of SUCCESS/FAILURE
      */
-    public void setInitialAttachApn(String apn, String protocol, int authType, String username,
-            String password, Message result);
+    void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result);
 
     /**
      * Set data profiles in modem
      *
      * @param dps
      *            Array of the data profiles set to modem
+     * @param isRoaming
+     *            Indicating if the device is roaming or not
      * @param result
      *            callback message contains the information of SUCCESS/FAILURE
      */
-    public void setDataProfile(DataProfile[] dps, Message result);
+    void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result);
 
     /**
      * Notifiy that we are testing an emergency call
@@ -1795,10 +1786,11 @@
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
      * @param AID Application id. See ETSI 102.221 and 101.220.
+     * @param p2 P2 parameter (described in ISO 7816-4).
      * @param response Callback message. response.obj will be an int [1] with
      *            element [0] set to the id of the logical channel.
      */
-    public void iccOpenLogicalChannel(String AID, Message response);
+    public void iccOpenLogicalChannel(String AID, int p2, Message response);
 
     /**
      * Close a previously opened logical channel to the SIM.
@@ -2052,4 +2044,33 @@
      * @param h handler to be removed
      */
     public void unregisterForPcoData(Handler h);
+
+    /**
+     * Send the updated device state
+     *
+     * @param stateType Device state type
+     * @param state True if enabled, otherwise disabled
+     * @param result callback message contains the information of SUCCESS/FAILURE
+     */
+    void sendDeviceState(int stateType, boolean state, Message result);
+
+    /**
+     * Send the device state to the modem
+     *
+     * @param filter unsolicited response filter. See DeviceStateMonitor.UnsolicitedResponseFilter
+     * @param result callback message contains the information of SUCCESS/FAILURE
+     */
+    void setUnsolResponseFilter(int filter, Message result);
+
+    /**
+     * Set SIM card power up or down
+     *
+     * @param powerUp True if powering up the sim card
+     * @param result callback message contains the information of SUCCESS/FAILURE
+     */
+    void setSimCardPower(boolean powerUp, Message result);
+
+    default public List<ClientRequestStats> getClientRequestStats() {
+        return null;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 39523b4..8a77465 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -188,6 +188,7 @@
     private int mVideoState;
     private int mConnectionCapabilities;
     private boolean mIsWifi;
+    private boolean mAudioModeIsVoip;
     private int mAudioQuality;
     private int mCallSubstate;
     private android.telecom.Connection.VideoProvider mVideoProvider;
@@ -501,7 +502,9 @@
     }
 
     protected final void clearPostDialListeners() {
-        mPostDialListeners.clear();
+        if (mPostDialListeners != null) {
+            mPostDialListeners.clear();
+        }
     }
 
     protected final void notifyPostDialListeners() {
@@ -700,6 +703,15 @@
     }
 
     /**
+     * Returns whether the connection uses voip audio mode
+     *
+     * @return {@code True} if the connection uses voip audio mode
+     */
+    public boolean getAudioModeIsVoip() {
+        return mAudioModeIsVoip;
+    }
+
+    /**
      * Returns the {@link android.telecom.Connection.VideoProvider} for the connection.
      *
      * @return The {@link android.telecom.Connection.VideoProvider}.
@@ -770,6 +782,15 @@
     }
 
     /**
+     * Set the voip audio mode for the connection
+     *
+     * @param isVoip {@code True} if voip audio mode is being used.
+     */
+    public void setAudioModeIsVoip(boolean isVoip) {
+        mAudioModeIsVoip = isVoip;
+    }
+
+    /**
      * Set the audio quality for the connection.
      *
      * @param audioQuality The audio quality.
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 0c23cf8..b83a6d1 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -28,12 +28,8 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.PreciseCallState;
-import android.telephony.DisconnectCause;
 
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallManager;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.PhoneConstantConversions;
 import com.android.internal.telephony.PhoneConstants;
 
 import java.util.List;
@@ -64,7 +60,8 @@
         try {
             if (mRegistry != null) {
                   mRegistry.notifyCallStateForPhoneId(phoneId, subId,
-                        convertCallState(sender.getState()), incomingNumber);
+                        PhoneConstantConversions.convertCallState(
+                            sender.getState()), incomingNumber);
             }
         } catch (RemoteException ex) {
             // system process is dead
@@ -182,7 +179,7 @@
         try {
             if (mRegistry != null) {
                 mRegistry.notifyDataConnectionForSubscriber(subId,
-                    convertDataState(state),
+                    PhoneConstantConversions.convertDataState(state),
                     sender.isDataConnectivityPossible(apnType), reason,
                     sender.getActiveApnHost(apnType),
                     apnType,
@@ -294,75 +291,31 @@
     }
 
     @Override
-    public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
+    public void notifyDataActivationStateChanged(Phone sender, int activationState) {
         try {
-            mRegistry.notifyOemHookRawEventForSubscriber(subId, rawData);
+            mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(),
+                    sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_DATA, activationState);
         } catch (RemoteException ex) {
             // system process is dead
         }
     }
 
-    /**
-     * Convert the {@link PhoneConstants.State} enum into the TelephonyManager.CALL_STATE_*
-     * constants for the public API.
-     */
-    public static int convertCallState(PhoneConstants.State state) {
-        switch (state) {
-            case RINGING:
-                return TelephonyManager.CALL_STATE_RINGING;
-            case OFFHOOK:
-                return TelephonyManager.CALL_STATE_OFFHOOK;
-            default:
-                return TelephonyManager.CALL_STATE_IDLE;
+    @Override
+    public void notifyVoiceActivationStateChanged(Phone sender, int activationState) {
+        try {
+            mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(),
+                    sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_VOICE, activationState);
+        } catch (RemoteException ex) {
+            // system process is dead
         }
     }
 
-    /**
-     * Convert the TelephonyManager.CALL_STATE_* constants into the
-     * {@link PhoneConstants.State} enum for the public API.
-     */
-    public static PhoneConstants.State convertCallState(int state) {
-        switch (state) {
-            case TelephonyManager.CALL_STATE_RINGING:
-                return PhoneConstants.State.RINGING;
-            case TelephonyManager.CALL_STATE_OFFHOOK:
-                return PhoneConstants.State.OFFHOOK;
-            default:
-                return PhoneConstants.State.IDLE;
-        }
-    }
-
-    /**
-     * Convert the {@link PhoneConstants.DataState} enum into the TelephonyManager.DATA_* constants
-     * for the public API.
-     */
-    public static int convertDataState(PhoneConstants.DataState state) {
-        switch (state) {
-            case CONNECTING:
-                return TelephonyManager.DATA_CONNECTING;
-            case CONNECTED:
-                return TelephonyManager.DATA_CONNECTED;
-            case SUSPENDED:
-                return TelephonyManager.DATA_SUSPENDED;
-            default:
-                return TelephonyManager.DATA_DISCONNECTED;
-        }
-    }
-
-    /**
-     * Convert the TelephonyManager.DATA_* constants into {@link PhoneConstants.DataState} enum
-     * for the public API.
-     */
-    public static PhoneConstants.DataState convertDataState(int state) {
-        switch (state) {
-            case TelephonyManager.DATA_CONNECTING:
-                return PhoneConstants.DataState.CONNECTING;
-            case TelephonyManager.DATA_CONNECTED:
-                return PhoneConstants.DataState.CONNECTED;
-            case TelephonyManager.DATA_SUSPENDED:
-                return PhoneConstants.DataState.SUSPENDED;
-            default:
-                return PhoneConstants.DataState.DISCONNECTED;
+    @Override
+    public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
+        try {
+            mRegistry.notifyOemHookRawEventForSubscriber(subId, rawData);
+        } catch (RemoteException ex) {
+            // system process is dead
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
new file mode 100644
index 0000000..73ab075
--- /dev/null
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE;
+import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED;
+import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.display.DisplayManager;
+import android.hardware.radio.V1_0.IndicationFilter;
+import android.net.ConnectivityManager;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.telephony.Rlog;
+import android.util.LocalLog;
+import android.view.Display;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * The device state monitor monitors the device state such as charging state, power saving sate,
+ * and then passes down the information to the radio modem for the modem to perform its own
+ * proprietary power saving strategy. Device state monitor also turns off the unsolicited
+ * response from the modem when the device does not need to receive it, for example, device's
+ * screen is off and does not have activities like tethering, remote display, etc...This effectively
+ * prevents the CPU from waking up by those unnecessary unsolicited responses such as signal
+ * strength update.
+ */
+public class DeviceStateMonitor extends Handler {
+    protected static final boolean DBG = false;      /* STOPSHIP if true */
+    protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
+
+    private static final int EVENT_RIL_CONNECTED                = 0;
+    private static final int EVENT_SCREEN_STATE_CHANGED         = 1;
+    private static final int EVENT_POWER_SAVE_MODE_CHANGED      = 2;
+    private static final int EVENT_CHARGING_STATE_CHANGED       = 3;
+    private static final int EVENT_TETHERING_STATE_CHANGED      = 4;
+
+    private final Phone mPhone;
+
+    private final LocalLog mLocalLog = new LocalLog(100);
+
+    /**
+     * Flag for wifi/usb/bluetooth tethering turned on or not
+     */
+    private boolean mIsTetheringOn;
+
+    /**
+     * Screen state provided by Display Manager. True indicates one of the screen is on, otherwise
+     * all off.
+     */
+    private boolean mIsScreenOn;
+
+    /**
+     * Indicating the device is plugged in and is supplying sufficient power that the battery level
+     * is going up (or the battery is fully charged). See BatteryManager.isCharging() for the
+     * details
+     */
+    private boolean mIsCharging;
+
+    /**
+     * Flag for device power save mode. See PowerManager.isPowerSaveMode() for the details.
+     * Note that it is not possible both mIsCharging and mIsPowerSaveOn are true at the same time.
+     * The system will automatically end power save mode when the device starts charging.
+     */
+    private boolean mIsPowerSaveOn;
+
+    /**
+     * Low data expected mode. True indicates low data traffic is expected, for example, when the
+     * device is idle (e.g. screen is off and not doing tethering in the background). Note this
+     * doesn't mean no data is expected.
+     */
+    private boolean mIsLowDataExpected;
+
+    /**
+     * The unsolicited response filter. See IndicationFilter defined in types.hal for the definition
+     * of each bit.
+     */
+    private int mUnsolicitedResponseFilter = IndicationFilter.ALL;
+
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+                @Override
+                public void onDisplayAdded(int displayId) { }
+
+                @Override
+                public void onDisplayRemoved(int displayId) { }
+
+                @Override
+                public void onDisplayChanged(int displayId) {
+                    boolean screenOn = isScreenOn();
+                    Message msg = obtainMessage(EVENT_SCREEN_STATE_CHANGED);
+                    msg.arg1 = screenOn ? 1 : 0;
+                    sendMessage(msg);
+                }
+            };
+
+    /**
+     * Device state broadcast receiver
+     */
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            log("received: " + intent, true);
+
+            Message msg;
+            switch (intent.getAction()) {
+                case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
+                    msg = obtainMessage(EVENT_POWER_SAVE_MODE_CHANGED);
+                    msg.arg1 = isPowerSaveModeOn() ? 1 : 0;
+                    log("Power Save mode " + ((msg.arg1 == 1) ? "on" : "off"), true);
+                    break;
+                case BatteryManager.ACTION_CHARGING:
+                    msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
+                    msg.arg1 = 1;   // charging
+                    break;
+                case BatteryManager.ACTION_DISCHARGING:
+                    msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
+                    msg.arg1 = 0;   // not charging
+                    break;
+                case ConnectivityManager.ACTION_TETHER_STATE_CHANGED:
+                    ArrayList<String> activeTetherIfaces = intent.getStringArrayListExtra(
+                            ConnectivityManager.EXTRA_ACTIVE_TETHER);
+
+                    boolean isTetheringOn = activeTetherIfaces != null
+                            && activeTetherIfaces.size() > 0;
+                    log("Tethering " + (isTetheringOn ? "on" : "off"), true);
+                    msg = obtainMessage(EVENT_TETHERING_STATE_CHANGED);
+                    msg.arg1 = isTetheringOn ? 1 : 0;
+                    break;
+                default:
+                    log("Unexpected broadcast intent: " + intent, false);
+                    return;
+            }
+            sendMessage(msg);
+        }
+    };
+
+    /**
+     * Device state monitor constructor. Note that each phone object should have its own device
+     * state monitor, meaning there will be two device monitors on the multi-sim device.
+     *
+     * @param phone Phone object
+     */
+    public DeviceStateMonitor(Phone phone) {
+        mPhone = phone;
+        DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
+                Context.DISPLAY_SERVICE);
+        dm.registerDisplayListener(mDisplayListener, null);
+
+        mIsPowerSaveOn = isPowerSaveModeOn();
+        mIsCharging = isDeviceCharging();
+        mIsScreenOn = isScreenOn();
+        // Assuming tethering is always off after boot up.
+        mIsTetheringOn = false;
+        mIsLowDataExpected = false;
+
+        log("DeviceStateMonitor mIsPowerSaveOn=" + mIsPowerSaveOn + ",mIsScreenOn="
+                + mIsScreenOn + ",mIsCharging=" + mIsCharging, false);
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        filter.addAction(BatteryManager.ACTION_CHARGING);
+        filter.addAction(BatteryManager.ACTION_DISCHARGING);
+        filter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone);
+
+        mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
+    }
+
+    /**
+     * @return True if low data is expected
+     */
+    private boolean isLowDataExpected() {
+        return mIsPowerSaveOn || (!mIsCharging && !mIsTetheringOn && !mIsScreenOn);
+    }
+
+    /**
+     * @return True if signal strength update should be turned off.
+     */
+    private boolean shouldTurnOffSignalStrength() {
+        return mIsPowerSaveOn || (!mIsCharging && !mIsScreenOn);
+    }
+
+    /**
+     * @return True if full network update should be turned off. Only significant changes will
+     * trigger the network update unsolicited response.
+     */
+    private boolean shouldTurnOffFullNetworkUpdate() {
+        return mIsPowerSaveOn || (!mIsCharging && !mIsScreenOn && !mIsTetheringOn);
+    }
+
+    /**
+     * @return True if data dormancy status update should be turned off.
+     */
+    private boolean shouldTurnOffDormancyUpdate() {
+        return mIsPowerSaveOn || (!mIsCharging && !mIsTetheringOn && !mIsScreenOn);
+    }
+
+    /**
+     * Message handler
+     *
+     * @param msg The message
+     */
+    @Override
+    public void handleMessage(Message msg) {
+        log("handleMessage msg=" + msg, false);
+        switch (msg.what) {
+            case EVENT_RIL_CONNECTED:
+                onRilConnected();
+                break;
+            default:
+                updateDeviceState(msg.what, msg.arg1 != 0);
+        }
+    }
+
+    /**
+     * Update the device and send the information to the modem.
+     *
+     * @param eventType Device state event type
+     * @param state True if enabled/on, otherwise disabled/off.
+     */
+    private void updateDeviceState(int eventType, boolean state) {
+        switch (eventType) {
+            case EVENT_SCREEN_STATE_CHANGED:
+                if (mIsScreenOn == state) return;
+                mIsScreenOn = state;
+                break;
+            case EVENT_CHARGING_STATE_CHANGED:
+                if (mIsCharging == state) return;
+                mIsCharging = state;
+                sendDeviceState(CHARGING_STATE, mIsCharging);
+                break;
+            case EVENT_TETHERING_STATE_CHANGED:
+                if (mIsTetheringOn == state) return;
+                mIsTetheringOn = state;
+                break;
+            case EVENT_POWER_SAVE_MODE_CHANGED:
+                if (mIsPowerSaveOn == state) return;
+                mIsPowerSaveOn = state;
+                sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
+                break;
+            default:
+                return;
+        }
+
+        if (mIsLowDataExpected != isLowDataExpected()) {
+            mIsLowDataExpected = !mIsLowDataExpected;
+            sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
+        }
+
+        int newFilter = 0;
+        if (!shouldTurnOffSignalStrength()) {
+            newFilter |= IndicationFilter.SIGNAL_STRENGTH;
+        }
+
+        if (!shouldTurnOffFullNetworkUpdate()) {
+            newFilter |= IndicationFilter.FULL_NETWORK_STATE;
+        }
+
+        if (!shouldTurnOffDormancyUpdate()) {
+            newFilter |= IndicationFilter.DATA_CALL_DORMANCY_CHANGED;
+        }
+
+        setUnsolResponseFilter(newFilter, false);
+    }
+
+    /**
+     * Called when RIL is connected during boot up or reconnected after modem restart.
+     *
+     * When modem crashes, if the user turns the screen off before RIL reconnects, device
+     * state and filter cannot be sent to modem. Resend the state here so that modem
+     * has the correct state (to stop signal strength reporting, etc).
+     */
+    private void onRilConnected() {
+        log("RIL connected.", true);
+        sendDeviceState(CHARGING_STATE, mIsCharging);
+        sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
+        sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
+        setUnsolResponseFilter(mUnsolicitedResponseFilter, true);
+    }
+
+    /**
+     * Convert the device state type into string
+     *
+     * @param type Device state type
+     * @return The converted string
+     */
+    private String deviceTypeToString(int type) {
+        switch (type) {
+            case CHARGING_STATE: return "CHARGING_STATE";
+            case LOW_DATA_EXPECTED: return "LOW_DATA_EXPECTED";
+            case POWER_SAVE_MODE: return "POWER_SAVE_MODE";
+            default: return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Send the device state to the modem.
+     *
+     * @param type Device state type. See DeviceStateType defined in types.hal.
+     * @param state True if enabled/on, otherwise disabled/off
+     */
+    private void sendDeviceState(int type, boolean state) {
+        log("send type: " + deviceTypeToString(type) + ", state=" + state, true);
+        mPhone.mCi.sendDeviceState(type, state, null);
+    }
+
+    /**
+     * Turn on/off the unsolicited response from the modem.
+     *
+     * @param newFilter See UnsolicitedResponseFilter in types.hal for the definition of each bit.
+     * @param force Always set the filter when true.
+     */
+    private void setUnsolResponseFilter(int newFilter, boolean force) {
+        if (force || newFilter != mUnsolicitedResponseFilter) {
+            log("old filter: " + mUnsolicitedResponseFilter + ", new filter: " + newFilter, true);
+            mPhone.mCi.setUnsolResponseFilter(newFilter, null);
+            mUnsolicitedResponseFilter = newFilter;
+        }
+    }
+
+    /**
+     * @return True if the device is currently in power save mode.
+     * See {@link android.os.BatteryManager#isPowerSaveMode BatteryManager.isPowerSaveMode()}.
+     */
+    private boolean isPowerSaveModeOn() {
+        final PowerManager pm = (PowerManager) mPhone.getContext().getSystemService(
+                Context.POWER_SERVICE);
+        return pm.isPowerSaveMode();
+    }
+
+    /**
+     * @return Return true if the battery is currently considered to be charging. This means that
+     * the device is plugged in and is supplying sufficient power that the battery level is
+     * going up (or the battery is fully charged).
+     * See {@link android.os.BatteryManager#isCharging BatteryManager.isCharging()}.
+     */
+    private boolean isDeviceCharging() {
+        final BatteryManager bm = (BatteryManager) mPhone.getContext().getSystemService(
+                Context.BATTERY_SERVICE);
+        return bm.isCharging();
+    }
+
+    /**
+     * @return True if one the device's screen (e.g. main screen, wifi display, HDMI display, or
+     *         Android auto, etc...) is on.
+     */
+    private boolean isScreenOn() {
+        // Note that we don't listen to Intent.SCREEN_ON and Intent.SCREEN_OFF because they are no
+        // longer adequate for monitoring the screen state since they are not sent in cases where
+        // the screen is turned off transiently such as due to the proximity sensor.
+        final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService(
+                Context.DISPLAY_SERVICE);
+        Display[] displays = dm.getDisplays();
+
+        if (displays != null) {
+            for (Display display : displays) {
+                // Anything other than STATE_ON is treated as screen off, such as STATE_DOZE,
+                // STATE_DOZE_SUSPEND, etc...
+                if (display.getState() == Display.STATE_ON) {
+                    log("Screen " + Display.typeToString(display.getType()) + " on", true);
+                    return true;
+                }
+            }
+            log("Screens all off", true);
+            return false;
+        }
+
+        log("No displays found", true);
+        return false;
+    }
+
+    /**
+     * @param msg Debug message
+     * @param logIntoLocalLog True if log into the local log
+     */
+    private void log(String msg, boolean logIntoLocalLog) {
+        if (DBG) Rlog.d(TAG, msg);
+        if (logIntoLocalLog) {
+            mLocalLog.log(msg);
+        }
+    }
+
+    /**
+     * Print the DeviceStateMonitor into the given stream.
+     *
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param pw A PrintWriter to which the dump is to be set.
+     * @param args Additional arguments to the dump request.
+     */
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.increaseIndent();
+        ipw.println("mIsTetheringOn=" + mIsTetheringOn);
+        ipw.println("mIsScreenOn=" + mIsScreenOn);
+        ipw.println("mIsCharging=" + mIsCharging);
+        ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
+        ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
+        ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
+        ipw.println("Local logs:");
+        ipw.increaseIndent();
+        mLocalLog.dump(fd, ipw, args);
+        ipw.decreaseIndent();
+        ipw.decreaseIndent();
+        ipw.flush();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index f340e80..7c9e997 100755
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -24,19 +24,20 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaCellLocation;
 import android.telephony.gsm.GsmCellLocation;
 import android.text.TextUtils;
-import java.util.Iterator;
-import android.telephony.Rlog;
 import android.util.EventLog;
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
@@ -44,8 +45,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * {@hide}
@@ -398,8 +400,7 @@
             dialString = convertNumberIfNecessary(mPhone, dialString);
         }
 
-        String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
-        boolean isPhoneInEcmMode = inEcm.equals("true");
+        boolean isPhoneInEcmMode = mPhone.isInEcm();
         boolean isEmergencyCall =
                 PhoneNumberUtils.isLocalEmergencyNumber(mPhone.getContext(), dialString);
 
@@ -466,9 +467,17 @@
             mPendingMO = new GsmCdmaConnection(mPhone,
                     checkForTestEmergencyNumber(dialString), this, mForegroundCall,
                     mIsInEmergencyCall);
-            // Some network need a empty flash before sending the normal one
-            m3WayCallFlashDelay = mPhone.getContext().getResources()
-                    .getInteger(com.android.internal.R.integer.config_cdma_3waycall_flash_delay);
+            // Some networks need an empty flash before sending the normal one
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            PersistableBundle bundle = configManager.getConfig();
+            if (bundle != null) {
+                m3WayCallFlashDelay =
+                        bundle.getInt(CarrierConfigManager.KEY_CDMA_3WAYCALL_FLASH_DELAY_INT);
+            } else {
+                // The default 3-way call flash delay is 0s
+                m3WayCallFlashDelay = 0;
+            }
             if (m3WayCallFlashDelay > 0) {
                 mCi.sendCDMAFeatureCode("", obtainMessage(EVENT_THREE_WAY_DIAL_BLANK_FLASH));
             } else {
@@ -1090,10 +1099,10 @@
         //dumpState();
     }
 
-    private void updateMetrics(GsmCdmaConnection []connections) {
+    private void updateMetrics(GsmCdmaConnection[] connections) {
         ArrayList<GsmCdmaConnection> activeConnections = new ArrayList<>();
-        for(GsmCdmaConnection conn : connections) {
-            if(conn != null) activeConnections.add(conn);
+        for (GsmCdmaConnection conn : connections) {
+            if (conn != null) activeConnections.add(conn);
         }
         mMetrics.writeRilCallList(mPhone.getPhoneId(), activeConnections);
     }
@@ -1283,7 +1292,7 @@
         int count = call.mConnections.size();
         for (int i = 0; i < count; i++) {
             GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
-            if (cn.getGsmCdmaIndex() == index) {
+            if (!cn.mDisconnected && cn.getGsmCdmaIndex() == index) {
                 mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
                 mCi.hangupConnection(index, obtainCompleteMessage());
                 return;
@@ -1298,8 +1307,10 @@
             int count = call.mConnections.size();
             for (int i = 0; i < count; i++) {
                 GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
-                mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
-                mCi.hangupConnection(cn.getGsmCdmaIndex(), obtainCompleteMessage());
+                if (!cn.mDisconnected) {
+                    mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
+                    mCi.hangupConnection(cn.getGsmCdmaIndex(), obtainCompleteMessage());
+                }
             }
         } catch (CallStateException ex) {
             Rlog.e(LOG_TAG, "hangupConnectionByIndex caught " + ex);
@@ -1311,7 +1322,7 @@
         int count = call.mConnections.size();
         for (int i = 0; i < count; i++) {
             GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
-            if (cn.getGsmCdmaIndex() == index) {
+            if (!cn.mDisconnected && cn.getGsmCdmaIndex() == index) {
                 return cn;
             }
         }
@@ -1548,11 +1559,11 @@
     private void checkAndEnableDataCallAfterEmergencyCallDropped() {
         if (mIsInEmergencyCall) {
             mIsInEmergencyCall = false;
-            String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+            boolean inEcm = mPhone.isInEcm();
             if (Phone.DEBUG_PHONE) {
                 log("checkAndEnableDataCallAfterEmergencyCallDropped,inEcm=" + inEcm);
             }
-            if (inEcm.compareTo("false") == 0) {
+            if (!inEcm) {
                 // Re-initiate data connection
                 mPhone.mDcTracker.setInternalDataEnabled(true);
                 mPhone.notifyEmergencyCallRegistrants(false);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index 868955c..cfda75e 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -26,16 +26,15 @@
 import android.os.SystemClock;
 import android.telephony.CarrierConfigManager;
 import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
-import com.android.internal.telephony.uicc.UiccCardApplication;
-import com.android.internal.telephony.uicc.UiccController;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
+import com.android.internal.telephony.uicc.UiccCardApplication;
 
 /**
  * {@hide}
@@ -226,8 +225,7 @@
         releaseAllWakeLocks();
     }
 
-    static boolean
-    equalsHandlesNulls (Object a, Object b) {
+    static boolean equalsHandlesNulls(Object a, Object b) {
         return (a == null) ? (b == null) : a.equals (b);
     }
 
@@ -448,6 +446,9 @@
             case CallFailCause.FDN_BLOCKED:
                 return DisconnectCause.FDN_BLOCKED;
 
+            case CallFailCause.IMEI_NOT_ACCEPTED:
+                return DisconnectCause.IMEI_NOT_ACCEPTED;
+
             case CallFailCause.UNOBTAINABLE_NUMBER:
                 return DisconnectCause.UNOBTAINABLE_NUMBER;
 
@@ -805,13 +806,13 @@
     protected void finalize()
     {
         /**
-         * It is understood that This finializer is not guaranteed
+         * It is understood that This finalizer is not guaranteed
          * to be called and the release lock call is here just in
          * case there is some path that doesn't call onDisconnect
          * and or onConnectedInOrOut.
          */
-        if (mPartialWakeLock.isHeld()) {
-            Rlog.e(LOG_TAG, "[GsmCdmaConn] UNEXPECTED; mPartialWakeLock is held when finalizing.");
+        if (mPartialWakeLock != null && mPartialWakeLock.isHeld()) {
+            Rlog.e(LOG_TAG, "UNEXPECTED; mPartialWakeLock is held when finalizing.");
         }
         clearPostDialListeners();
         releaseWakeLock();
@@ -936,33 +937,37 @@
         notifyPostDialListeners();
     }
 
-    private void
-    createWakeLock(Context context) {
+    private void createWakeLock(Context context) {
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
     }
 
-    private void
-    acquireWakeLock() {
-        log("acquireWakeLock");
-        mPartialWakeLock.acquire();
-    }
-
-    private void
-    releaseWakeLock() {
-        synchronized(mPartialWakeLock) {
-            if (mPartialWakeLock.isHeld()) {
-                log("releaseWakeLock");
-                mPartialWakeLock.release();
+    private void acquireWakeLock() {
+        if (mPartialWakeLock != null) {
+            synchronized (mPartialWakeLock) {
+                log("acquireWakeLock");
+                mPartialWakeLock.acquire();
             }
         }
     }
 
-    private void
-    releaseAllWakeLocks() {
-        synchronized(mPartialWakeLock) {
-            while (mPartialWakeLock.isHeld()) {
-                mPartialWakeLock.release();
+    private void releaseWakeLock() {
+        if (mPartialWakeLock != null) {
+            synchronized (mPartialWakeLock) {
+                if (mPartialWakeLock.isHeld()) {
+                    log("releaseWakeLock");
+                    mPartialWakeLock.release();
+                }
+            }
+        }
+    }
+
+    private void releaseAllWakeLocks() {
+        if (mPartialWakeLock != null) {
+            synchronized (mPartialWakeLock) {
+                while (mPartialWakeLock.isHeld()) {
+                    mPartialWakeLock.release();
+                }
             }
         }
     }
@@ -983,8 +988,7 @@
     // This function is to find the next PAUSE character index if
     // multiple pauses in a row. Otherwise it finds the next non PAUSE or
     // non WAIT character index.
-    private static int
-    findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
+    private static int findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
         boolean wMatched = isWait(phoneNumber.charAt(currIndex));
         int index = currIndex + 1;
         int length = phoneNumber.length();
@@ -1011,12 +1015,12 @@
         return index;
     }
 
-    //CDMA
+    // CDMA
     // This function returns either PAUSE or WAIT character to append.
     // It is based on the next non PAUSE/WAIT character in the phoneNumber and the
     // index for the current PAUSE/WAIT character
-    private static char
-    findPOrWCharToAppend(String phoneNumber, int currPwIndex, int nextNonPwCharIndex) {
+    private static char findPOrWCharToAppend(String phoneNumber, int currPwIndex,
+                                             int nextNonPwCharIndex) {
         char c = phoneNumber.charAt(currPwIndex);
         char ret;
 
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 07afe0c..237a726 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -16,7 +16,19 @@
 
 package com.android.internal.telephony;
 
-import android.app.ActivityManagerNative;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
+
+import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -33,8 +45,10 @@
 import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.RegistrantList;
+import android.os.ResultReceiver;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.WorkSource;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.provider.Telephony;
@@ -42,56 +56,46 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.CellLocation;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-
+import android.telephony.UssdResponse;
 import android.telephony.cdma.CdmaCellLocation;
 import android.text.TextUtils;
-import android.telephony.Rlog;
 import android.util.Log;
 
 import com.android.ims.ImsManager;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaMmiCode;
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.cdma.EriManager;
-import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.gsm.GsmMmiCode;
 import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardProxy;
 import com.android.internal.telephony.uicc.IccException;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
+import com.android.internal.telephony.uicc.IsimRecords;
+import com.android.internal.telephony.uicc.IsimUiccRecords;
 import com.android.internal.telephony.uicc.RuimRecords;
 import com.android.internal.telephony.uicc.SIMRecords;
 import com.android.internal.telephony.uicc.UiccCard;
 import com.android.internal.telephony.uicc.UiccCardApplication;
 import com.android.internal.telephony.uicc.UiccController;
-import com.android.internal.telephony.uicc.IsimRecords;
-import com.android.internal.telephony.uicc.IsimUiccRecords;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-
 /**
  * {@hide}
  */
@@ -124,14 +128,12 @@
     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
     // mEcmExitRespRegistrant is informed after the phone has been exited
-    //the emergency callback mode
-    //keep track of if phone is in emergency callback mode
-    private boolean mIsPhoneInEcmState;
     private Registrant mEcmExitRespRegistrant;
     private String mEsn;
     private String mMeid;
     // string to define how the carrier specifies its own ota sp number
     private String mCarrierOtaSpNumSchema;
+
     // A runnable which is used to automatically exit from Ecm after a period of time.
     private Runnable mExitEcmRunnable = new Runnable() {
         @Override
@@ -155,6 +157,7 @@
     public ServiceStateTracker mSST;
     private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
     private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
+    private DeviceStateMonitor mDeviceStateMonitor;
 
     private int mPrecisePhoneType;
 
@@ -207,6 +210,7 @@
         // DcTracker uses SST so needs to be created after it is instantiated
         mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
+        mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
         logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
     }
 
@@ -279,8 +283,7 @@
         } else {
             mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
             // This is needed to handle phone process crashes
-            String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
-            mIsPhoneInEcmState = inEcm.equals("true");
+            mIsPhoneInEcmState = getInEcmMode();
             if (mIsPhoneInEcmState) {
                 // Send a message which will invoke handleExitEmergencyCallbackMode
                 mCi.exitEmergencyCallbackMode(
@@ -384,7 +387,7 @@
     @Override
     protected void finalize() {
         if(DBG) logd("GsmCdmaPhone finalized");
-        if (mWakeLock.isHeld()) {
+        if (mWakeLock != null && mWakeLock.isHeld()) {
             Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
             mWakeLock.release();
         }
@@ -409,9 +412,9 @@
     }
 
     @Override
-    public CellLocation getCellLocation() {
+    public CellLocation getCellLocation(WorkSource workSource) {
         if (isPhoneTypeGsm()) {
-            return mSST.getCellLocation();
+            return mSST.getCellLocation(workSource);
         } else {
             CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
 
@@ -470,9 +473,8 @@
                 // get voice mail count from SIM
                 countVoiceMessages = r.getVoiceMessageCount();
             }
-            int countVoiceMessagesStored = getStoredVoiceMessageCount();
-            if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) {
-                countVoiceMessages = countVoiceMessagesStored;
+            if (countVoiceMessages == IccRecords.DEFAULT_VOICE_MESSAGE_COUNT) {
+                countVoiceMessages = getStoredVoiceMessageCount();
             }
             logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
                     + " subId " + getSubId());
@@ -630,7 +632,7 @@
         Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
-        ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+        ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
         if (DBG) logd("sendEmergencyCallbackModeChange");
     }
 
@@ -640,7 +642,7 @@
             Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
             intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
-            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+            ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
             if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
         }
     }
@@ -1057,7 +1059,7 @@
             throw new CallStateException("Sending UUS information NOT supported in CDMA!");
         }
 
-        boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
+        boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
         Phone imsPhone = mImsPhone;
 
         CarrierConfigManager configManager =
@@ -1138,10 +1140,52 @@
         }
     }
 
+    /**
+     * @return {@code true} if the user should be informed of an attempt to dial an international
+     * number while on WFC only, {@code false} otherwise.
+     */
+    public boolean isNotificationOfWfcCallRequired(String dialString) {
+        CarrierConfigManager configManager =
+                (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle config = configManager.getConfigForSubId(getSubId());
+
+        // Determine if carrier config indicates that international calls over WFC should trigger a
+        // notification to the user. This is controlled by carrier configuration and is off by
+        // default.
+        boolean shouldNotifyInternationalCallOnWfc = config != null
+                && config.getBoolean(
+                        CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
+
+        if (!shouldNotifyInternationalCallOnWfc) {
+            return false;
+        }
+
+        Phone imsPhone = mImsPhone;
+        boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
+        boolean shouldConfirmCall =
+                        // Using IMS
+                        isImsUseEnabled()
+                        && imsPhone != null
+                        // VoLTE not available
+                        && !imsPhone.isVolteEnabled()
+                        // WFC is available
+                        && imsPhone.isWifiCallingEnabled()
+                        && !isEmergency
+                        // Dialing international number
+                        && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
+        return shouldConfirmCall;
+    }
+
     @Override
     protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
                                       Bundle intentExtras)
             throws CallStateException {
+        return dialInternal(dialString, uusInfo, videoState, intentExtras, null);
+    }
+
+    protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
+                                      Bundle intentExtras, ResultReceiver wrappedCallback)
+            throws CallStateException {
 
         // Need to make sure dialString gets parsed properly
         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
@@ -1154,9 +1198,9 @@
 
             // Only look at the Network portion for mmi
             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
-            GsmMmiCode mmi =
-                    GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
-            if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
+            GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
+                    mUiccApplication.get(), wrappedCallback);
+            if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
 
             if (mmi == null) {
                 return mCT.dial(newDialString, uusInfo, intentExtras);
@@ -1165,13 +1209,7 @@
             } else {
                 mPendingMMIs.add(mmi);
                 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
-                try {
-                    mmi.processCode();
-                } catch (CallStateException e) {
-                    //do nothing
-                }
-
-                // FIXME should this return null or something else?
+                mmi.processCode();
                 return null;
             }
         } else {
@@ -1179,7 +1217,7 @@
         }
     }
 
-    @Override
+   @Override
     public boolean handlePinMmi(String dialString) {
         MmiCode mmi;
         if (isPhoneTypeGsm()) {
@@ -1203,6 +1241,52 @@
         return false;
     }
 
+    private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
+                                   ResultReceiver wrappedCallback) {
+        UssdResponse response = new UssdResponse(ussdRequest, message);
+        Bundle returnData = new Bundle();
+        returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+        wrappedCallback.send(returnCode, returnData);
+    }
+
+    @Override
+    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
+        if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
+            //todo: replace the generic failure with specific error code.
+            sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
+                    wrappedCallback );
+            return true;
+        }
+
+        // Try over IMS if possible.
+        Phone imsPhone = mImsPhone;
+        if ((imsPhone != null)
+                && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
+                || imsPhone.isUtEnabled())) {
+            try {
+                logd("handleUssdRequest: attempting over IMS");
+                return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
+            } catch (CallStateException cse) {
+                if (!CS_FALLBACK.equals(cse.getMessage())) {
+                    return false;
+                }
+                // At this point we've tried over IMS but have been informed we need to handover
+                // back to GSM.
+                logd("handleUssdRequest: fallback to CS required");
+            }
+        }
+
+        // Try USSD over GSM.
+        try {
+            dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null,
+                    wrappedCallback);
+        } catch (Exception e) {
+            logd("handleUssdRequest: exception" + e);
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public void sendUssdResponse(String ussdMessge) {
         if (isPhoneTypeGsm()) {
@@ -1295,23 +1379,14 @@
         }
 
         if (TextUtils.isEmpty(number)) {
-            String[] listArray = getContext().getResources()
-                .getStringArray(com.android.internal.R.array.config_default_vm_number);
-            if (listArray != null && listArray.length > 0) {
-                for (int i=0; i<listArray.length; i++) {
-                    if (!TextUtils.isEmpty(listArray[i])) {
-                        String[] defaultVMNumberArray = listArray[i].split(";");
-                        if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) {
-                            if (defaultVMNumberArray.length == 1) {
-                                number = defaultVMNumberArray[0];
-                            } else if (defaultVMNumberArray.length == 2 &&
-                                    !TextUtils.isEmpty(defaultVMNumberArray[1]) &&
-                                    isMatchGid(defaultVMNumberArray[1])) {
-                                number = defaultVMNumberArray[0];
-                                break;
-                            }
-                        }
-                    }
+            CarrierConfigManager configManager = (CarrierConfigManager)
+                    getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+            PersistableBundle b = configManager.getConfig();
+            if (b != null) {
+                String defaultVmNumber =
+                        b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
+                if (!TextUtils.isEmpty(defaultVmNumber)) {
+                    number = defaultVmNumber;
                 }
             }
         }
@@ -1411,12 +1486,7 @@
 
     @Override
     public String getMeid() {
-        if (isPhoneTypeGsm()) {
-            loge("[GsmCdmaPhone] getMeid() is a CDMA method");
-            return "0";
-        } else {
-            return mMeid;
-        }
+        return mMeid;
     }
 
     @Override
@@ -1729,9 +1799,9 @@
     }
 
     @Override
-    public void getNeighboringCids(Message response) {
+    public void getNeighboringCids(Message response, WorkSource workSource) {
         if (isPhoneTypeGsm()) {
-            mCi.getNeighboringCids(response);
+            mCi.getNeighboringCids(response, workSource);
         } else {
             /*
              * This is currently not implemented.  At least as of June
@@ -1789,12 +1859,12 @@
 
     @Override
     public boolean getDataRoamingEnabled() {
-        return mDcTracker.getDataOnRoamingEnabled();
+        return mDcTracker.getDataRoamingEnabled();
     }
 
     @Override
     public void setDataRoamingEnabled(boolean enable) {
-        mDcTracker.setDataOnRoamingEnabled(enable);
+        mDcTracker.setDataRoamingEnabled(enable);
     }
 
     @Override
@@ -1861,7 +1931,20 @@
          */
         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
                 ((GsmMmiCode)mmi).isSsInfo()))) {
-            mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+
+            ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
+            if (receiverCallback != null) {
+                Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
+                int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
+                    TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
+                sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
+                        receiverCallback );
+            } else {
+                Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
+                mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+            }
+        } else {
+            Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
         }
     }
 
@@ -1879,6 +1962,7 @@
     }
 
     private void onNetworkInitiatedUssd(MmiCode mmi) {
+        Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
         mMmiCompleteRegistrants.notifyRegistrants(
             new AsyncResult(null, mmi, null));
     }
@@ -1923,19 +2007,18 @@
             } else {
                 found.onUssdFinished(ussdMessage, isUssdRequest);
             }
-        } else { // pending USSD not found
+        } else if (!isUssdError && ussdMessage != null) {
+            // pending USSD not found
             // The network may initiate its own USSD request
 
             // ignore everything that isnt a Notify or a Request
             // also, discard if there is no message to present
-            if (!isUssdError && ussdMessage != null) {
-                GsmMmiCode mmi;
-                mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
+            GsmMmiCode mmi;
+            mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
                                                    isUssdRequest,
                                                    GsmCdmaPhone.this,
                                                    mUiccApplication.get());
-                onNetworkInitiatedUssd(mmi);
-            }
+            onNetworkInitiatedUssd(mmi);
         }
     }
 
@@ -1945,6 +2028,7 @@
     private void syncClirSetting() {
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
+        Rlog.i(LOG_TAG, "syncClirSetting: " + CLIR_KEY + getPhoneId() + "=" + clirSetting);
         if (clirSetting >= 0) {
             mCi.setCLIR(clirSetting, null);
         }
@@ -1953,12 +2037,7 @@
     private void handleRadioAvailable() {
         mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
 
-        if (isPhoneTypeGsm()) {
-            mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
-            mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
-        } else {
-            mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
-        }
+        mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
         mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
         startLceAfterRadioIsAvailable();
     }
@@ -2591,7 +2670,7 @@
         if (isPhoneTypeGsm()) {
             return false;
         } else {
-            return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
+            return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
         }
     }
 
@@ -2665,6 +2744,10 @@
             r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
         } else {
             r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+            if (isPhoneTypeCdmaLte()) {
+                // notify simRecordsLoaded registrants for cdmaLte phone
+                r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+            }
         }
     }
 
@@ -2700,9 +2783,9 @@
                     + mIsPhoneInEcmState);
         }
         // if phone is not in Ecm mode, and it's changed to Ecm mode
-        if (mIsPhoneInEcmState == false) {
-            setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
-            mIsPhoneInEcmState = true;
+        if (!mIsPhoneInEcmState) {
+            setIsInEcm(true);
+
             // notify change
             sendEmergencyCallbackModeChange();
 
@@ -2732,8 +2815,7 @@
         // if exiting ecm success
         if (ar.exception == null) {
             if (mIsPhoneInEcmState) {
-                setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
-                mIsPhoneInEcmState = false;
+                setIsInEcm(false);
             }
 
             // release wakeLock
@@ -3102,10 +3184,9 @@
 
         // Send an Intent to the PhoneApp that we had a radio technology change
         Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
-        ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+        ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
     }
 
     private void switchVoiceRadioTech(int newVoiceRadioTech) {
@@ -3189,6 +3270,9 @@
         }
         pw.flush();
         pw.println("++++++++++++++++++++++++++++++++");
+        pw.println("DeviceStateMonitor:");
+        mDeviceStateMonitor.dump(fd, pw, args);
+        pw.println("++++++++++++++++++++++++++++++++");
     }
 
     @Override
@@ -3258,6 +3342,19 @@
         return operatorNumeric;
     }
 
+    /**
+     * @return The country ISO for the subscription associated with this phone.
+     */
+    public String getCountryIso() {
+        int subId = getSubId();
+        SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
+                .getActiveSubscriptionInfo(subId);
+        if (subInfo == null) {
+            return null;
+        }
+        return subInfo.getCountryIso().toUpperCase();
+    }
+
     public void notifyEcbmTimerReset(Boolean flag) {
         mEcmTimerResetRegistrants.notifyResult(flag);
     }
diff --git a/src/java/com/android/internal/telephony/HardwareConfig.java b/src/java/com/android/internal/telephony/HardwareConfig.java
index 0f855de..8623354 100644
--- a/src/java/com/android/internal/telephony/HardwareConfig.java
+++ b/src/java/com/android/internal/telephony/HardwareConfig.java
@@ -112,7 +112,7 @@
      * default constructor.
      */
     public HardwareConfig(int type) {
-        type = type;
+        this.type = type;
     }
 
     /**
@@ -152,7 +152,7 @@
         if (type == DEV_HARDWARE_TYPE_MODEM) {
             char[] bits = Integer.toBinaryString(ratBits).toCharArray();
             uuid = id;
-            state = state;
+            this.state = state;
             rilModel = model;
             rat = new BitSet(bits.length);
             for (int i = 0 ; i < bits.length ; i++) {
@@ -168,7 +168,7 @@
         if (type == DEV_HARDWARE_TYPE_SIM) {
             uuid = id;
             modemUuid = link;
-            state = state;
+            this.state = state;
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/HbpcdUtils.java b/src/java/com/android/internal/telephony/HbpcdUtils.java
old mode 100755
new mode 100644
index acd31a6..2f31942
--- a/src/java/com/android/internal/telephony/HbpcdUtils.java
+++ b/src/java/com/android/internal/telephony/HbpcdUtils.java
@@ -16,17 +16,16 @@
 
 package com.android.internal.telephony;
 
-import android.util.Log;
-import android.content.Context;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.database.Cursor;
+import android.telephony.Rlog;
 
-import com.android.internal.telephony.HbpcdLookup;
+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;
-import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
 
 public final class HbpcdUtils {
     private static final String LOG_TAG = "HbpcdUtils";
@@ -55,16 +54,16 @@
         if (c2 != null) {
             int c2Counter = c2.getCount();
             if (DBG) {
-                Log.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
+                Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
             }
             if (c2Counter == 1) {
                 if (DBG) {
-                    Log.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2 );
+                    Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
                 }
                 c2.moveToFirst();
                 tmpMcc = c2.getInt(0);
                 if (DBG) {
-                    Log.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
+                    Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
                 }
                 c2.close();
                 return tmpMcc;
@@ -86,22 +85,25 @@
             int c3Counter = c3.getCount();
             if (c3Counter > 0) {
                 if (c3Counter > 1) {
-                    Log.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
+                    Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
                 }
-                if (DBG) Log.d(LOG_TAG, "Query conflict sid returned the cursor " + c3 );
+                if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
                 c3.moveToFirst();
                 tmpMcc = c3.getInt(0);
-                if (DBG) Log.d(LOG_TAG,
-                        "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
-                c3.close();
-                if (isNitzTimeZone) {
-                    return tmpMcc;
-                } else {
-                    // time zone is not accurate, it may get wrong mcc, ignore it.
-                    if (DBG) Log.d(LOG_TAG, "time zone is not accurate, mcc may be "
-                            + tmpMcc);
-                        return 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();
             }
         }
 
@@ -113,18 +115,18 @@
                 null, null);
         if (c5 != null) {
             if (c5.getCount() > 0) {
-                if (DBG) Log.d(LOG_TAG, "Query Range returned the cursor " + c5 );
+                if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5);
                 c5.moveToFirst();
                 tmpMcc = c5.getInt(0);
-                if (DBG) Log.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
+                if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
                 c5.close();
                 return tmpMcc;
             }
             c5.close();
         }
-        if (DBG) Log.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
+        if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
 
-        if (DBG) Log.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc =  " + tmpMcc );
+        if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc =  " + tmpMcc);
         // If unknown MCC still could not be resolved,
         return tmpMcc;
     }
@@ -133,7 +135,7 @@
      *  Gets country information with given MCC.
     */
     public String getIddByMcc(int mcc) {
-        if (DBG) Log.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
+        if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
         String idd = "";
 
         Cursor c = null;
@@ -143,19 +145,19 @@
                 MccIdd.MCC + "=" + mcc, null, null);
         if (cur != null) {
             if (cur.getCount() > 0) {
-                if (DBG) Log.d(LOG_TAG, "Query Idd returned the cursor " + cur );
+                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) Log.d(LOG_TAG, "IDD = " + idd);
+                if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd);
 
             }
             cur.close();
         }
         if (c != null) c.close();
 
-        if (DBG) Log.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
+        if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
         return idd;
     }
 }
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 6b32498..0fc08c6 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -25,6 +25,8 @@
 import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
@@ -32,9 +34,9 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Process;
 import android.os.UserManager;
 import android.provider.Telephony;
+import android.service.carrier.CarrierMessagingService;
 import android.telephony.Rlog;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -446,8 +448,7 @@
             return;
         }
         if (!persistMessageForNonDefaultSmsApp) {
-            // Only allow carrier app or phone process to skip auto message persistence.
-            enforceCarrierOrPhonePrivilege();
+            enforcePrivilegedAppPermissions();
         }
         destAddr = filterDestAddress(destAddr);
         mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
@@ -465,7 +466,7 @@
      *  the same time an SMS received from radio is acknowledged back.
      */
     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
-        enforceCarrierPrivilege();
+        enforcePrivilegedAppPermissions();
         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
             log("pdu: " + pdu +
                 "\n format=" + format +
@@ -507,8 +508,8 @@
                 Manifest.permission.SEND_SMS,
                 "Sending SMS message");
         if (!persistMessageForNonDefaultSmsApp) {
-            // Only allow carrier app to skip auto message persistence.
-            enforceCarrierPrivilege();
+            // Only allow carrier app or carrier ims to skip auto message persistence.
+            enforcePrivilegedAppPermissions();
         }
         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
             int i = 0;
@@ -603,9 +604,9 @@
     protected byte[] makeSmsRecordData(int status, byte[] pdu) {
         byte[] data;
         if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
-            data = new byte[IccConstants.SMS_RECORD_LENGTH];
+            data = new byte[SmsManager.SMS_RECORD_LENGTH];
         } else {
-            data = new byte[IccConstants.CDMA_SMS_RECORD_LENGTH];
+            data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH];
         }
 
         // Status bits for this record.  See TS 51.011 10.5.3
@@ -1115,11 +1116,36 @@
         }
     }
 
-    private void enforceCarrierOrPhonePrivilege() {
-        int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.PHONE_UID) {
-            enforceCarrierPrivilege();
+    /**
+     * Enforces that the caller has {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission or is one of the following apps:
+     * <ul>
+     *     <li> IMS App
+     *     <li> Carrier App
+     * </ul>
+     */
+    private void enforcePrivilegedAppPermissions() {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+                == PackageManager.PERMISSION_GRANTED) {
+            return;
         }
+
+        int callingUid = Binder.getCallingUid();
+        String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
+                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+        try {
+            if (carrierImsPackage != null
+                    && callingUid == mContext.getPackageManager().getPackageUid(
+                            carrierImsPackage, 0)) {
+              return;
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            if (Rlog.isLoggable("SMS", Log.DEBUG)) {
+                log("Cannot find configured carrier ims package");
+            }
+        }
+
+        enforceCarrierPrivilege();
     }
 
     private String filterDestAddress(String destAddr) {
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index b7eb32a..a9bada9 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -20,7 +20,7 @@
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
 import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.Notification;
@@ -36,13 +36,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
-import android.os.storage.StorageManager;
 import android.os.AsyncResult;
 import android.os.Binder;
 import android.os.Build;
@@ -54,13 +51,10 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.service.carrier.CarrierMessagingService;
-import android.service.carrier.ICarrierMessagingCallback;
-import android.service.carrier.ICarrierMessagingService;
-import android.service.carrier.MessagePdu;
-import android.telephony.CarrierMessagingServiceManager;
 import android.telephony.Rlog;
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
@@ -70,14 +64,12 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.uicc.UiccCard;
-import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 
 import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -142,8 +134,6 @@
     public static final int DISPLAY_ADDRESS_COLUMN = 9;
 
     public static final String SELECT_BY_ID = "_id=?";
-    public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " +
-            "count=? AND deleted=0";
 
     /** New SMS received as an AsyncResult. */
     public static final int EVENT_NEW_SMS = 1;
@@ -653,6 +643,9 @@
             // broadcast SMS_REJECTED_ACTION intent
             Intent intent = new Intent(Intents.SMS_REJECTED_ACTION);
             intent.putExtra("result", result);
+            // Allow registered broadcast receivers to get this intent even
+            // when they are in the background.
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS);
         }
         acknowledgeLastIncomingSms(success, result, response);
@@ -774,7 +767,7 @@
                 // query for all segments and broadcast message if we have all the parts
                 String[] whereArgs = {address, refNumber, count};
                 cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION,
-                        SELECT_BY_REFERENCE, whereArgs, null);
+                        tracker.getQueryForSegments(), whereArgs, null);
 
                 int cursorCount = cursor.getCount();
                 if (cursorCount < messageCount) {
@@ -954,7 +947,8 @@
                 .setDefaults(Notification.DEFAULT_ALL)
                 .setContentTitle(mContext.getString(R.string.new_sms_notification_title))
                 .setContentText(mContext.getString(R.string.new_sms_notification_content))
-                .setContentIntent(intent);
+                .setContentIntent(intent)
+                .setChannelId(NotificationChannelController.CHANNEL_ID_SMS);
         NotificationManager mNotificationManager =
             (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mNotificationManager.notify(
@@ -988,43 +982,15 @@
      */
     private boolean filterSms(byte[][] pdus, int destPort,
         InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) {
-        List<String> carrierPackages = null;
-        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
-        if (card != null) {
-            carrierPackages = card.getCarrierPackageNamesForIntent(
-                    mContext.getPackageManager(),
-                    new Intent(CarrierMessagingService.SERVICE_INTERFACE));
-        } else {
-            loge("UiccCard not initialized.");
-        }
-
-        if (carrierPackages != null && carrierPackages.size() == 1) {
-            log("Found carrier package.");
-            CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
-                    tracker.getFormat(), resultReceiver);
-            CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter,
-                    userUnlocked);
-            smsFilter.filterSms(carrierPackages.get(0), smsFilterCallback);
+        CarrierServicesSmsFilterCallback filterCallback =
+                new CarrierServicesSmsFilterCallback(
+                        pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked);
+        CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter(
+                mContext, mPhone, pdus, destPort, tracker.getFormat(), filterCallback, getName());
+        if (carrierServicesFilter.filter()) {
             return true;
         }
 
-        // It is possible that carrier app is not present as a CarrierPackage, but instead as a
-        // system app
-        List<String> systemPackages =
-                getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
-
-        if (systemPackages != null && systemPackages.size() == 1) {
-            log("Found system package.");
-            CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
-                    tracker.getFormat(), resultReceiver);
-            CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter,
-                    userUnlocked);
-            smsFilter.filterSms(systemPackages.get(0), smsFilterCallback);
-            return true;
-        }
-        logv("Unable to find carrier package: " + carrierPackages
-                + ", nor systemPackages: " + systemPackages);
-
         if (VisualVoicemailSmsFilter.filter(
                 mContext, pdus, tracker.getFormat(), destPort, mPhone.getSubId())) {
             log("Visual voicemail SMS dropped");
@@ -1035,27 +1001,6 @@
         return false;
     }
 
-    private List<String> getSystemAppForIntent(Intent intent) {
-        List<String> packages = new ArrayList<String>();
-        PackageManager packageManager = mContext.getPackageManager();
-        List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
-        String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS";
-
-        for (ResolveInfo info : receivers) {
-            if (info.serviceInfo == null) {
-                loge("Can't get service information from " + info);
-                continue;
-            }
-            String packageName = info.serviceInfo.packageName;
-                if (packageManager.checkPermission(carrierFilterSmsPerm, packageName) ==
-                        packageManager.PERMISSION_GRANTED) {
-                    packages.add(packageName);
-                    if (DBG) log("getSystemAppForIntent: added package "+ packageName);
-                }
-        }
-        return packages;
-    }
-
     /**
      * Dispatch the intent with the specified permission, appOp, and result receiver, using
      * this state machine's handler thread to run the result receiver.
@@ -1086,7 +1031,7 @@
             // Get a list of currently started users.
             int[] users = null;
             try {
-                users = ActivityManagerNative.getDefault().getRunningUserIds();
+                users = ActivityManager.getService().getRunningUserIds();
             } catch (RemoteException re) {
             }
             if (users == null) {
@@ -1155,7 +1100,8 @@
     }
 
     /**
-     * Creates and dispatches the intent to the default SMS app or the appropriate port.
+     * Creates and dispatches the intent to the default SMS app, appropriate port or via the {@link
+     * AppSmsManager}.
      *
      * @param pdus message pdus
      * @param format the message format, typically "3gpp" or "3gpp2"
@@ -1163,7 +1109,7 @@
      * @param resultReceiver the receiver handling the delivery result
      */
     private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,
-            BroadcastReceiver resultReceiver) {
+            SmsBroadcastReceiver resultReceiver) {
         Intent intent = new Intent();
         intent.putExtra("pdus", pdus);
         intent.putExtra("format", format);
@@ -1191,11 +1137,22 @@
                     intent.putExtra("uri", uri.toString());
                 }
             }
+
+            // Handle app specific sms messages.
+            AppSmsManager appManager = mPhone.getAppSmsManager();
+            if (appManager.handleSmsReceivedIntent(intent)) {
+                // The AppSmsManager handled this intent, we're done.
+                dropSms(resultReceiver);
+                return;
+            }
         } else {
             intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
             Uri uri = Uri.parse("sms://localhost:" + destPort);
             intent.setData(uri);
             intent.setComponent(null);
+            // Allow registered broadcast receivers to get this intent even
+            // when they are in the background.
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         }
 
         Bundle options = handleSmsWhitelisting(intent.getComponent());
@@ -1226,9 +1183,8 @@
         } else {
             // for multi-part messages, deduping should also be done against undeleted
             // segments that can cause ambiguity when contacenating the segments, that is,
-            // segments with same address, reference_number, count and sequence
-            where = "address=? AND reference_number=? AND count=? AND sequence=? AND " +
-                    "((date=? AND message_body=?) OR deleted=0)";
+            // segments with same address, reference_number, count, sequence and message type.
+            where = tracker.getQueryForMultiPartDuplicates();
         }
 
         Cursor cursor = null;
@@ -1305,7 +1261,7 @@
             } else {
                 // set the delete selection args for multi-part message
                 String[] deleteWhereArgs = {address, refNumber, count};
-                tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs);
+                tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs);
             }
             return Intents.RESULT_SMS_HANDLED;
         } catch (Exception e) {
@@ -1344,15 +1300,23 @@
             if (action.equals(Intents.SMS_DELIVER_ACTION)) {
                 // Now dispatch the notification only intent
                 intent.setAction(Intents.SMS_RECEIVED_ACTION);
+                // Allow registered broadcast receivers to get this intent even
+                // when they are in the background.
+                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                 intent.setComponent(null);
                 // All running users will be notified of the received sms.
                 Bundle options = handleSmsWhitelisting(null);
+
                 dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
-                        AppOpsManager.OP_RECEIVE_SMS, options, this, UserHandle.ALL);
+                        AppOpsManager.OP_RECEIVE_SMS,
+                        options, this, UserHandle.ALL);
             } else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
                 // Now dispatch the notification only intent
                 intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
                 intent.setComponent(null);
+                // Allow registered broadcast receivers to get this intent even
+                // when they are in the background.
+                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                 // Only the primary user will receive notification of incoming mms.
                 // That app will do the actual downloading of the mms.
                 Bundle options = null;
@@ -1400,131 +1364,53 @@
     }
 
     /**
-     * Asynchronously binds to the carrier messaging service, and filters out the message if
-     * instructed to do so by the carrier messaging service. A new instance must be used for every
-     * message.
+     * Callback that handles filtering results by carrier services.
      */
-    private final class CarrierSmsFilter extends CarrierMessagingServiceManager {
+    private final class CarrierServicesSmsFilterCallback implements
+            CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface {
         private final byte[][] mPdus;
         private final int mDestPort;
         private final String mSmsFormat;
         private final SmsBroadcastReceiver mSmsBroadcastReceiver;
-        // Instantiated in filterSms.
-        private volatile CarrierSmsFilterCallback mSmsFilterCallback;
+        private final boolean mUserUnlocked;
 
-        CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat,
-                SmsBroadcastReceiver smsBroadcastReceiver) {
+        CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat,
+                         SmsBroadcastReceiver smsBroadcastReceiver,  boolean userUnlocked) {
             mPdus = pdus;
             mDestPort = destPort;
             mSmsFormat = smsFormat;
             mSmsBroadcastReceiver = smsBroadcastReceiver;
-        }
-
-        /**
-         * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated
-         * asynchronously once the service is ready using {@link #onServiceReady}.
-         */
-        void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) {
-            mSmsFilterCallback = smsFilterCallback;
-            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
-                loge("bindService() for carrier messaging service failed");
-                smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
-            } else {
-                logv("bindService() for carrier messaging service succeeded");
-            }
-        }
-
-        /**
-         * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
-         * delivered to {@code smsFilterCallback}.
-         */
-        @Override
-        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
-            try {
-                carrierMessagingService.filterSms(
-                        new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
-                        mPhone.getSubId(), mSmsFilterCallback);
-            } catch (RemoteException e) {
-                loge("Exception filtering the SMS: " + e);
-                mSmsFilterCallback.onFilterComplete(
-                    CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
-            }
-        }
-    }
-
-    /**
-     * A callback used to notify the platform of the carrier messaging app filtering result. Once
-     * the result is ready, the carrier messaging service connection is disposed.
-     */
-    private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub {
-        private final CarrierSmsFilter mSmsFilter;
-        private final boolean mUserUnlocked;
-
-        CarrierSmsFilterCallback(CarrierSmsFilter smsFilter, boolean userUnlocked) {
-            mSmsFilter = smsFilter;
             mUserUnlocked = userUnlocked;
         }
 
-        /**
-         * This method should be called only once.
-         */
         @Override
         public void onFilterComplete(int result) {
-            mSmsFilter.disposeConnection(mContext);
-            // Calling identity was the CarrierMessagingService in this callback, change it back to
-            // ours. This is required for dropSms() and VisualVoicemailSmsFilter.filter().
-            long token = Binder.clearCallingIdentity();
-            try {
-                logv("onFilterComplete: result is " + result);
-                if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
-                    if (VisualVoicemailSmsFilter.filter(mContext, mSmsFilter.mPdus,
-                            mSmsFilter.mSmsFormat, mSmsFilter.mDestPort, mPhone.getSubId())) {
-                        log("Visual voicemail SMS dropped");
-                        dropSms(mSmsFilter.mSmsBroadcastReceiver);
-                        return;
-                    }
-
-                    if (mUserUnlocked) {
-                        dispatchSmsDeliveryIntent(mSmsFilter.mPdus, mSmsFilter.mSmsFormat,
-                                mSmsFilter.mDestPort, mSmsFilter.mSmsBroadcastReceiver);
-                    } else {
-                        // Don't do anything further, leave the message in the raw table if the
-                        // credential-encrypted storage is still locked and show the new message
-                        // notification if the message is visible to the user.
-                        if (!isSkipNotifyFlagSet(result)) {
-                            showNewMessageNotification();
-                        }
-                        sendMessage(EVENT_BROADCAST_COMPLETE);
-                    }
-                } else {
-                    // Drop this SMS.
-                    dropSms(mSmsFilter.mSmsBroadcastReceiver);
+            logv("onFilterComplete: result is " + result);
+            if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
+                if (VisualVoicemailSmsFilter.filter(mContext, mPdus,
+                        mSmsFormat, mDestPort, mPhone.getSubId())) {
+                    log("Visual voicemail SMS dropped");
+                    dropSms(mSmsBroadcastReceiver);
+                    return;
                 }
-            } finally {
-                // return back to the CarrierMessagingService, restore the calling identity.
-                Binder.restoreCallingIdentity(token);
+
+                if (mUserUnlocked) {
+                    dispatchSmsDeliveryIntent(
+                            mPdus, mSmsFormat, mDestPort, mSmsBroadcastReceiver);
+                } else {
+                    // Don't do anything further, leave the message in the raw table if the
+                    // credential-encrypted storage is still locked and show the new message
+                    // notification if the message is visible to the user.
+                    if (!isSkipNotifyFlagSet(result)) {
+                        showNewMessageNotification();
+                    }
+                    sendMessage(EVENT_BROADCAST_COMPLETE);
+                }
+            } else {
+                // Drop this SMS.
+                dropSms(mSmsBroadcastReceiver);
             }
         }
-
-        @Override
-        public void onSendSmsComplete(int result, int messageRef) {
-            loge("Unexpected onSendSmsComplete call with result: " + result);
-        }
-
-        @Override
-        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
-            loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
-        }
-
-        @Override
-        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
-            loge("Unexpected onSendMmsComplete call with result: " + result);
-        }
-
-        @Override
-        public void onDownloadMmsComplete(int result) {
-            loge("Unexpected onDownloadMmsComplete call with result: " + result);
-        }
     }
 
     private void dropSms(SmsBroadcastReceiver receiver) {
diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java
index 9db83ab..c63ccc8 100644
--- a/src/java/com/android/internal/telephony/InboundSmsTracker.java
+++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java
@@ -19,6 +19,7 @@
 import android.content.ContentValues;
 import android.database.Cursor;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.HexDump;
 
 import java.util.Arrays;
@@ -59,21 +60,47 @@
      */
     private final String mDisplayAddress;
 
+    @VisibleForTesting
     /** Destination port flag bit for no destination port. */
-    private static final int DEST_PORT_FLAG_NO_PORT = (1 << 16);
+    public static final int DEST_PORT_FLAG_NO_PORT = (1 << 16);
 
     /** Destination port flag bit to indicate 3GPP format message. */
     private static final int DEST_PORT_FLAG_3GPP = (1 << 17);
 
+    @VisibleForTesting
     /** Destination port flag bit to indicate 3GPP2 format message. */
-    private static final int DEST_PORT_FLAG_3GPP2 = (1 << 18);
+    public static final int DEST_PORT_FLAG_3GPP2 = (1 << 18);
 
+    @VisibleForTesting
     /** Destination port flag bit to indicate 3GPP2 format WAP message. */
-    private static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19);
+    public static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19);
 
     /** Destination port mask (16-bit unsigned value on GSM and CDMA). */
     private static final int DEST_PORT_MASK = 0xffff;
 
+    @VisibleForTesting
+    public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND "
+            + "count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU
+            + "=0) AND deleted=0";
+
+    @VisibleForTesting
+    public static final String SELECT_BY_REFERENCE_3GPP2WAP = "address=? AND reference_number=? "
+            + "AND count=? AND (destination_port & "
+            + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ") AND deleted=0";
+
+    @VisibleForTesting
+    public static final String SELECT_BY_DUPLICATE_REFERENCE = "address=? AND "
+            + "reference_number=? AND count=? AND sequence=? AND "
+            + "((date=? AND message_body=?) OR deleted=0) AND (destination_port & "
+            + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0)";
+
+    @VisibleForTesting
+    public static final String SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP = "address=? AND "
+            + "reference_number=? " + "AND count=? AND sequence=? AND "
+            + "((date=? AND message_body=?) OR deleted=0) AND "
+            + "(destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "="
+            + DEST_PORT_FLAG_3GPP2_WAP_PDU + ")";
+
     /**
      * Create a tracker for a single-part SMS.
      *
@@ -190,7 +217,7 @@
                         + " of " + mMessageCount);
             }
 
-            mDeleteWhere = InboundSmsHandler.SELECT_BY_REFERENCE;
+            mDeleteWhere = getQueryForSegments();
             mDeleteWhereArgs = new String[]{mAddress,
                     Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)};
         }
@@ -293,6 +320,15 @@
         return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
     }
 
+    public String getQueryForSegments() {
+        return mIs3gpp2WapPdu ? SELECT_BY_REFERENCE_3GPP2WAP : SELECT_BY_REFERENCE;
+    }
+
+    public String getQueryForMultiPartDuplicates() {
+        return mIs3gpp2WapPdu ? SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP :
+                SELECT_BY_DUPLICATE_REFERENCE;
+    }
+
     /**
      * Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU
      * messages, which use a 0-based index.
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 0ee153c..51ae81e 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.telephony;
 
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -28,6 +28,12 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.app.LocaleStore;
+import com.android.internal.app.LocaleStore.LocaleInfo;
+
+import libcore.icu.ICU;
+import libcore.icu.TimeZoneNames;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -36,9 +42,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import libcore.icu.ICU;
-import libcore.icu.TimeZoneNames;
-
 /**
  * Mobile Country Code
  *
@@ -94,7 +97,21 @@
         Locale locale = new Locale("", entry.mIso);
         String[] tz = TimeZoneNames.forLocale(locale);
         if (tz.length == 0) return null;
-        return tz[0];
+
+        String zoneName = tz[0];
+
+        /* Use Australia/Sydney instead of Australia/Lord_Howe for Australia.
+         * http://b/33228250
+         * Todo: remove the code, see b/62418027
+         */
+        if (mcc == 505  /* Australia / Norfolk Island */) {
+            for (String zone : tz) {
+                if (zone.contains("Sydney")) {
+                    zoneName = zone;
+                }
+            }
+        }
+        return zoneName;
     }
 
     /**
@@ -211,7 +228,7 @@
 
                     if (updateConfig) {
                         Slog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
-                        ActivityManagerNative.getDefault().updateConfiguration(config);
+                        ActivityManager.getService().updateConfiguration(config);
                     } else {
                         Slog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
                     }
@@ -235,21 +252,21 @@
     static {
         // If we have English (without a country) explicitly prioritize en_US. http://b/28998094
         FALLBACKS.put(Locale.ENGLISH, Locale.US);
-        FALLBACKS.put(Locale.CANADA, Locale.US);
     }
 
     /**
-     * Find the best match we actually have a localization for. This function assumes we
-     * couldn't find an exact match.
+     * Finds a suitable locale among {@code candidates} to use as the fallback locale for
+     * {@code target}. This looks through the list of {@link #FALLBACKS}, and follows the chain
+     * until a locale in {@code candidates} is found.
+     * This function assumes that {@code target} is not in {@code candidates}.
      *
      * TODO: This should really follow the CLDR chain of parent locales! That might be a bit
      * of a problem because we don't really have an en-001 locale on android.
+     *
+     * @return The fallback locale or {@code null} if there is no suitable fallback defined in the
+     *         lookup.
      */
-    private static Locale chooseBestFallback(Locale target, List<Locale> candidates) {
-        if (candidates.isEmpty()) {
-            return null;
-        }
-
+    private static Locale lookupFallback(Locale target, List<Locale> candidates) {
         Locale fallback = target;
         while ((fallback = FALLBACKS.get(fallback)) != null) {
             if (candidates.contains(fallback)) {
@@ -257,11 +274,7 @@
             }
         }
 
-        // Somewhat arbitrarily take the first locale for the language,
-        // unless we get a perfect match later. Note that these come back in no
-        // particular order, so there's no reason to think the first match is
-        // a particularly good match.
-        return candidates.get(0);
+        return null;
     }
 
     /**
@@ -314,14 +327,40 @@
                 }
             }
 
-            Locale bestMatch = chooseBestFallback(target, languageMatches);
+            if (languageMatches.isEmpty()) {
+                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
+                return null;
+            }
+
+            Locale bestMatch = lookupFallback(target, languageMatches);
             if (bestMatch != null) {
-                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a language-only match: " +
-                       bestMatch.toLanguageTag());
+                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
+                        + bestMatch.toLanguageTag());
                 return bestMatch;
             } else {
-                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " +
-                       language);
+                // Ask {@link LocaleStore} whether this locale is considered "translated".
+                // LocaleStore has a broader definition of translated than just the asset locales
+                // above: a locale is "translated" if it has translation assets, or another locale
+                // with the same language and script has translation assets.
+                // If a locale is "translated", it is selectable in setup wizard, and can therefore
+                // be considerd a valid result for this method.
+                if (!TextUtils.isEmpty(target.getCountry())) {
+                    LocaleStore.fillCache(context);
+                    LocaleInfo targetInfo = LocaleStore.getLocaleInfo(target);
+                    if (targetInfo.isTranslated()) {
+                        Slog.d(LOG_TAG, "getLocaleForLanguageCountry: "
+                                + "target locale is translated: " + target);
+                        return target;
+                    }
+                }
+
+                // Somewhat arbitrarily take the first locale for the language,
+                // unless we get a perfect match later. Note that these come back in no
+                // particular order, so there's no reason to think the first match is
+                // a particularly good match.
+                Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
+                        + language);
+                return languageMatches.get(0);
             }
         } catch (Exception e) {
             Slog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
@@ -344,7 +383,7 @@
                 AlarmManager alarm =
                         (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
                 alarm.setTimeZone(zoneId);
-                Slog.d(LOG_TAG, "timezone set to "+zoneId);
+                Slog.d(LOG_TAG, "timezone set to " + zoneId);
             }
         }
     }
@@ -359,7 +398,8 @@
      * @return locale for the mcc or null if none
      */
     public static Locale getLocaleFromMcc(Context context, int mcc, String simLanguage) {
-        String language = (simLanguage == null) ? MccTable.defaultLanguageForMcc(mcc) : simLanguage;
+        boolean hasSimLanguage = !TextUtils.isEmpty(simLanguage);
+        String language = hasSimLanguage ? simLanguage : MccTable.defaultLanguageForMcc(mcc);
         String country = MccTable.countryCodeForMcc(mcc);
 
         Slog.d(LOG_TAG, "getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
@@ -367,10 +407,10 @@
 
         // If we couldn't find a locale that matches the SIM language, give it a go again
         // with the "likely" language for the given country.
-        if (locale == null && simLanguage != null) {
+        if (locale == null && hasSimLanguage) {
             language = MccTable.defaultLanguageForMcc(mcc);
             Slog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
-            return getLocaleForLanguageCountry(context, null, country);
+            return getLocaleForLanguageCountry(context, language, country);
         }
 
         return locale;
@@ -423,7 +463,7 @@
 		sTable.add(new MccEntry(225,"va",2));	//Vatican City State
 		sTable.add(new MccEntry(226,"ro",2));	//Romania
 		sTable.add(new MccEntry(228,"ch",2));	//Switzerland (Confederation of)
-		sTable.add(new MccEntry(230,"cz",2));	//Czech Republic
+		sTable.add(new MccEntry(230,"cz",2));	//Czechia
 		sTable.add(new MccEntry(231,"sk",2));	//Slovak Republic
 		sTable.add(new MccEntry(232,"at",2));	//Austria
 		sTable.add(new MccEntry(234,"gb",2));	//United Kingdom of Great Britain and Northern Ireland
diff --git a/src/java/com/android/internal/telephony/MmiCode.java b/src/java/com/android/internal/telephony/MmiCode.java
index ae55e15..0adf83f 100644
--- a/src/java/com/android/internal/telephony/MmiCode.java
+++ b/src/java/com/android/internal/telephony/MmiCode.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import android.os.ResultReceiver;
+
 /**
  * {@hide}
  */
@@ -75,4 +77,13 @@
      */
     void processCode() throws CallStateException;
 
+    /**
+     * @return the Receiver for the Ussd Callback.
+     */
+    public ResultReceiver getUssdCallbackReceiver();
+
+    /**
+     * @return the dialString.
+     */
+    public String getDialString();
 }
diff --git a/src/java/com/android/internal/telephony/OemHookIndication.java b/src/java/com/android/internal/telephony/OemHookIndication.java
new file mode 100644
index 0000000..122a70e
--- /dev/null
+++ b/src/java/com/android/internal/telephony/OemHookIndication.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.hardware.radio.deprecated.V1_0.IOemHookIndication;
+import android.os.AsyncResult;
+
+import java.util.ArrayList;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW;
+
+/**
+ * Class containing oem hook indication callbacks
+ */
+public class OemHookIndication extends IOemHookIndication.Stub {
+    RIL mRil;
+
+    public OemHookIndication(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * @param indicationType RadioIndicationType
+     * @param data Data sent by oem
+     */
+    public void oemHookRaw(int indicationType, ArrayList<Byte> data) {
+        mRil.processIndication(indicationType);
+
+        byte[] response = RIL.arrayListToPrimitiveArray(data);
+        if (RIL.RILJ_LOGD) {
+            mRil.unsljLogvRet(RIL_UNSOL_OEM_HOOK_RAW,
+                    com.android.internal.telephony.uicc.IccUtils.bytesToHexString(response));
+        }
+
+        if (mRil.mUnsolOemHookRawRegistrant != null) {
+            mRil.mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, response, null));
+        }
+    }
+}
diff --git a/src/java/com/android/internal/telephony/OemHookResponse.java b/src/java/com/android/internal/telephony/OemHookResponse.java
new file mode 100644
index 0000000..0afeac8
--- /dev/null
+++ b/src/java/com/android/internal/telephony/OemHookResponse.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.hardware.radio.deprecated.V1_0.IOemHookResponse;
+import android.hardware.radio.V1_0.RadioError;
+import android.hardware.radio.V1_0.RadioResponseInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Class containing oem hook response callbacks
+ */
+public class OemHookResponse extends IOemHookResponse.Stub {
+    RIL mRil;
+
+    public OemHookResponse(RIL ril) {
+        mRil = ril;
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param data Data returned by oem
+     */
+    public void sendRequestRawResponse(RadioResponseInfo responseInfo, ArrayList<Byte> data) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            byte[] ret = null;
+            if (responseInfo.error == RadioError.NONE) {
+                ret = RIL.arrayListToPrimitiveArray(data);
+                RadioResponse.sendMessageResponse(rr.mResult, ret);
+            }
+            mRil.processResponseDone(rr, responseInfo, ret);
+        }
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param data Data returned by oem
+     */
+    public void sendRequestStringsResponse(RadioResponseInfo responseInfo, ArrayList<String> data) {
+        RadioResponse.responseStringArrayList(mRil, responseInfo, data);
+    }
+}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index e7cfe88..f9da65b 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -34,6 +34,7 @@
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.os.SystemProperties;
+import android.os.WorkSource;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
 import android.service.carrier.CarrierIdentifier;
@@ -41,6 +42,8 @@
 import android.telephony.CellIdentityCdma;
 import android.telephony.CellInfo;
 import android.telephony.CellInfoCdma;
+import android.telephony.CellLocation;
+import android.telephony.ClientRequestStats;
 import android.telephony.PhoneStateListener;
 import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
@@ -55,6 +58,7 @@
 import com.android.ims.ImsManager;
 import com.android.internal.R;
 import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -92,6 +96,8 @@
 
     protected final static Object lockForRadioTechnologyChange = new Object();
 
+    protected final int USSD_MAX_QUEUE = 10;
+
     private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -230,12 +236,19 @@
     protected int mVmCount = 0;
     private boolean mDnsCheckDisabled;
     public DcTracker mDcTracker;
+    /* Used for dispatching signals to configured carrier apps */
+    private CarrierSignalAgent mCarrierSignalAgent;
+    /* Used for dispatching carrier action from carrier apps */
+    private CarrierActionAgent mCarrierActionAgent;
     private boolean mDoesRilSendMultipleCallRing;
     private int mCallRingContinueToken;
     private int mCallRingDelay;
     private boolean mIsVoiceCapable = true;
-    /* Used for communicate between configured CarrierSignalling receivers */
-    private CarrierSignalAgent mCarrierSignalAgent;
+    private final AppSmsManager mAppSmsManager;
+    private SimActivationTracker mSimActivationTracker;
+    // Keep track of whether or not the phone is in Emergency Callback Mode for Phone and
+    // subclasses
+    protected boolean mIsPhoneInEcmState = false;
 
     // Variable to cache the video capability. When RAT changes, we lose this info and are unable
     // to recover from the state. We cache it and notify listeners when they register.
@@ -266,6 +279,11 @@
     protected TelephonyComponentFactory mTelephonyComponentFactory;
 
     //IMS
+    /**
+     * {@link CallStateException} message text used to indicate that an IMS call has failed because
+     * it needs to be retried using GSM or CDMA (e.g. CS fallback).
+     * TODO: Replace this with a proper exception; {@link CallStateException} doesn't make sense.
+     */
     public static final String CS_FALLBACK = "cs_fallback";
     public static final String EXTRA_KEY_ALERT_TITLE = "alertTitle";
     public static final String EXTRA_KEY_ALERT_MESSAGE = "alertMessage";
@@ -435,9 +453,9 @@
         mContext = context;
         mLooper = Looper.myLooper();
         mCi = ci;
-        mCarrierSignalAgent = new CarrierSignalAgent(this);
         mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
         mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
+        mAppSmsManager = telephonyComponentFactory.makeAppSmsManager(context);
 
         if (Build.IS_DEBUGGABLE) {
             mTelephonyTester = new TelephonyTester(this);
@@ -503,6 +521,9 @@
         mSmsUsageMonitor = mTelephonyComponentFactory.makeSmsUsageMonitor(context);
         mUiccController = UiccController.getInstance();
         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
+        mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
+        mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this);
+        mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this);
         if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) {
             mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
         }
@@ -512,7 +533,8 @@
     }
 
     /**
-     * Start listening for IMS service UP/DOWN events.
+     * Start listening for IMS service UP/DOWN events. If using the new ImsResolver APIs, we should
+     * always be setting up ImsPhones.
      */
     public void startMonitoringImsService() {
         if (getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
@@ -521,18 +543,26 @@
 
         synchronized(Phone.lockForRadioTechnologyChange) {
             IntentFilter filter = new IntentFilter();
-            filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
-            filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
+            ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
+            // Don't listen to deprecated intents using the new dynamic binding.
+            if (imsManager != null && !imsManager.isDynamicBinding()) {
+                filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
+                filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
+            }
             filter.addAction(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
             mContext.registerReceiver(mImsIntentReceiver, filter);
 
             // Monitor IMS service - but first poll to see if already up (could miss
-            // intent)
-            ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
-            if (imsManager != null && imsManager.isServiceAvailable()) {
-                mImsServiceReady = true;
-                updateImsPhone();
-                ImsManager.updateImsServiceConfig(mContext, mPhoneId, false);
+            // intent). Also, when using new ImsResolver APIs, the service will be available soon,
+            // so start trying to bind.
+            if (imsManager != null) {
+                // If it is dynamic binding, kick off ImsPhone creation now instead of waiting for
+                // the service to be available.
+                if (imsManager.isDynamicBinding() || imsManager.isServiceAvailable()) {
+                    mImsServiceReady = true;
+                    updateImsPhone();
+                    ImsManager.updateImsServiceConfig(mContext, mPhoneId, false);
+                }
             }
         }
     }
@@ -1158,6 +1188,10 @@
         mCi.getNetworkSelectionMode(message);
     }
 
+    public List<ClientRequestStats> getClientRequestStats() {
+        return mCi.getClientRequestStats();
+    }
+
     /**
      * Manually selects a network. <code>response</code> is
      * dispatched when this is complete.  <code>response.obj</code> will be
@@ -1294,6 +1328,8 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putInt(CLIR_KEY + getPhoneId(), commandInterfaceCLIRMode);
+        Rlog.i(LOG_TAG, "saveClirSetting: " + CLIR_KEY + getPhoneId() + "=" +
+                commandInterfaceCLIRMode);
 
         // Commit and log the result.
         if (!editor.commit()) {
@@ -1525,6 +1561,32 @@
     }
 
     /**
+     * Update voice activation state
+     */
+    public void setVoiceActivationState(int state) {
+        mSimActivationTracker.setVoiceActivationState(state);
+    }
+    /**
+     * Update data activation state
+     */
+    public void setDataActivationState(int state) {
+        mSimActivationTracker.setDataActivationState(state);
+    }
+
+    /**
+     * Returns voice activation state
+     */
+    public int getVoiceActivationState() {
+        return mSimActivationTracker.getVoiceActivationState();
+    }
+    /**
+     * Returns data activation state
+     */
+    public int getDataActivationState() {
+        return mSimActivationTracker.getDataActivationState();
+    }
+
+    /**
      * Update voice mail count related fields and notify listeners
      */
     public void updateVoiceMail() {
@@ -1579,13 +1641,18 @@
     }
 
     /**
+     * @param workSource calling WorkSource
      * @return all available cell information or null if none.
      */
-    public List<CellInfo> getAllCellInfo() {
-        List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo();
+    public List<CellInfo> getAllCellInfo(WorkSource workSource) {
+        List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo(workSource);
         return privatizeCellInfoList(cellInfoList);
     }
 
+    public CellLocation getCellLocation() {
+        return getCellLocation(null);
+    }
+
     /**
      * Clear CDMA base station lat/long values if location setting is disabled.
      * @param cellInfoList the original cell info list from the RIL
@@ -1628,9 +1695,10 @@
      * A onCellInfoChanged.
      *
      * @param rateInMillis the rate
+     * @param workSource calling WorkSource
      */
-    public void setCellInfoListRate(int rateInMillis) {
-        mCi.setCellInfoListRate(rateInMillis, null);
+    public void setCellInfoListRate(int rateInMillis, WorkSource workSource) {
+        mCi.setCellInfoListRate(rateInMillis, null, workSource);
     }
 
     /**
@@ -1735,6 +1803,10 @@
         return mCarrierSignalAgent;
     }
 
+    public CarrierActionAgent getCarrierActionAgent() {
+        return mCarrierActionAgent;
+    }
+
     /**
      *  Query the CDMA roaming preference setting
      *
@@ -1764,6 +1836,15 @@
     }
 
     /**
+     * @return true, if the device is in a state where both voice and data
+     * are supported simultaneously. This can change based on location or network condition.
+     */
+    public boolean isConcurrentVoiceAndDataAllowed() {
+        ServiceStateTracker sst = getServiceStateTracker();
+        return sst == null ? false : sst.isConcurrentVoiceAndDataAllowed();
+    }
+
+    /**
      *  Requests to set the CDMA roaming preference
      * @param cdmaRoamingType one of  CDMA_RM_*
      * @param response is callback message
@@ -1935,7 +2016,9 @@
      * com.android.internal.telephony.gsm.CommandException
      *
      * @see #invokeOemRilRequestRaw(byte[], android.os.Message)
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public void invokeOemRilRequestRaw(byte[] data, Message response) {
         mCi.invokeOemRilRequestRaw(data, response);
     }
@@ -1953,7 +2036,9 @@
      * com.android.internal.telephony.gsm.CommandException
      *
      * @see #invokeOemRilRequestStrings(java.lang.String[], android.os.Message)
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public void invokeOemRilRequestStrings(String[] strings, Message response) {
         mCi.invokeOemRilRequestStrings(strings, response);
     }
@@ -2037,6 +2122,14 @@
         mNotifier.notifyOtaspChanged(this, otaspMode);
     }
 
+    public void notifyVoiceActivationStateChanged(int state) {
+        mNotifier.notifyVoiceActivationStateChanged(this, state);
+    }
+
+    public void notifyDataActivationStateChanged(int state) {
+        mNotifier.notifyDataActivationStateChanged(this, state);
+    }
+
     public void notifySignalStrength() {
         mNotifier.notifySignalStrength(this);
     }
@@ -2056,13 +2149,26 @@
         return false;
     }
 
+    // This property is used to handle phone process crashes, and is the same for CDMA and IMS
+    // phones
+    protected static boolean getInEcmMode() {
+        return SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false);
+    }
+
     /**
      * @return {@code true} if we are in emergency call back mode. This is a period where the phone
      * should be using as little power as possible and be ready to receive an incoming call from the
      * emergency operator.
+     *
+     * This method is overridden for GSM phones to return false always
      */
     public boolean isInEcm() {
-        return false;
+        return mIsPhoneInEcmState;
+    }
+
+    public void setIsInEcm(boolean isInEcm) {
+        setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, String.valueOf(isInEcm));
+        mIsPhoneInEcmState = isInEcm;
     }
 
     private static int getVideoState(Call call) {
@@ -2188,6 +2294,21 @@
     }
 
     /**
+     * send secret dialer codes to launch arbitrary activities.
+     * an Intent is started with the android_secret_code://<code> URI.
+     *
+     * @param code stripped version of secret code without *#*# prefix and #*#* suffix
+     */
+    public void sendDialerSpecialCode(String code) {
+        if (!TextUtils.isEmpty(code)) {
+            Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
+                    Uri.parse("android_secret_code://" + code));
+            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            mContext.sendBroadcast(intent);
+        }
+    }
+
+    /**
      * Returns the CDMA ERI icon index to display
      */
     public int getCdmaEriIconIndex() {
@@ -2655,18 +2776,14 @@
      * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
      */
     public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
-        if(mDcTracker != null) {
-            mDcTracker.setApnsEnabledByCarrier(enabled);
-        }
+        mCarrierActionAgent.carrierActionSetMeteredApnsEnabled(enabled);
     }
 
     /**
      * Action set from carrier signalling broadcast receivers to enable/disable radio
      */
     public void carrierActionSetRadioEnabled(boolean enabled) {
-        if(mDcTracker != null) {
-            mDcTracker.carrierActionSetRadioEnabled(enabled);
-        }
+        mCarrierActionAgent.carrierActionSetRadioEnabled(enabled);
     }
 
     /**
@@ -3353,6 +3470,18 @@
         return null;
     }
 
+    public AppSmsManager getAppSmsManager() {
+        return mAppSmsManager;
+    }
+
+    /**
+     * Set SIM card power state. Request is equivalent to inserting or removing the card.
+     * @param powerUp True if powering up the SIM, otherwise powering down
+     **/
+    public void setSimPowerState(boolean powerUp) {
+        mCi.setSimCardPower(powerUp, null);
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Phone: subId=" + getSubId());
         pw.println(" mPhoneId=" + mPhoneId);
@@ -3425,6 +3554,28 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
+        if (mCarrierActionAgent != null) {
+            try {
+                mCarrierActionAgent.dump(fd, pw, args);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            pw.flush();
+            pw.println("++++++++++++++++++++++++++++++++");
+        }
+
+        if (mCarrierSignalAgent != null) {
+            try {
+                mCarrierSignalAgent.dump(fd, pw, args);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            pw.flush();
+            pw.println("++++++++++++++++++++++++++++++++");
+        }
+
         if (getCallTracker() != null) {
             try {
                 getCallTracker().dump(fd, pw, args);
@@ -3436,6 +3587,17 @@
             pw.println("++++++++++++++++++++++++++++++++");
         }
 
+        if (mSimActivationTracker != null) {
+            try {
+                mSimActivationTracker.dump(fd, pw, args);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            pw.flush();
+            pw.println("++++++++++++++++++++++++++++++++");
+        }
+
         if (mCi != null && mCi instanceof RIL) {
             try {
                 ((RIL)mCi).dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index aec3d8e..8ae7010 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -36,12 +36,14 @@
 
 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
 import com.android.internal.telephony.dataconnection.TelephonyNetworkFactory;
+import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
 import com.android.internal.telephony.sip.SipPhone;
 import com.android.internal.telephony.sip.SipPhoneFactory;
 import com.android.internal.telephony.uicc.IccCardProxy;
 import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.NotificationChannelController;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
@@ -78,6 +80,8 @@
     static private PhoneSwitcher sPhoneSwitcher;
     static private SubscriptionMonitor sSubscriptionMonitor;
     static private TelephonyNetworkFactory[] sTelephonyNetworkFactories;
+    static private ImsResolver sImsResolver;
+    static private NotificationChannelController sNotificationChannelController;
 
     static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>();
 
@@ -136,6 +140,13 @@
                    where as in single SIM mode only instance. isMultiSimEnabled() function checks
                    whether it is single SIM or multi SIM mode */
                 int numPhones = TelephonyManager.getDefault().getPhoneCount();
+                // Start ImsResolver and bind to ImsServices.
+                String defaultImsPackage = sContext.getResources().getString(
+                        com.android.internal.R.string.config_ims_package);
+                Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);
+                sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones);
+                sImsResolver.populateCacheAndStartBind();
+
                 int[] networkModes = new int[numPhones];
                 sPhones = new Phone[numPhones];
                 sCommandsInterfaces = new RIL[numPhones];
@@ -203,8 +214,9 @@
                 SubscriptionController.getInstance().updatePhonesAvailability(sPhones);
 
                 // Start monitoring after defaults have been made.
-                // Default phone must be ready before ImsPhone is created
-                // because ImsService might need it when it is being opened.
+                // Default phone must be ready before ImsPhone is created because ImsService might
+                // need it when it is being opened. This should initialize multiple ImsPhones for
+                // ImsResolver implementations of ImsService.
                 for (int i = 0; i < numPhones; i++) {
                     sPhones[i].startMonitoringImsService();
                 }
@@ -222,6 +234,8 @@
                 sProxyController = ProxyController.getInstance(context, sPhones,
                         sUiccController, sCommandsInterfaces, sPhoneSwitcher);
 
+                sNotificationChannelController = new NotificationChannelController(context);
+
                 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
                 for (int i = 0; i < numPhones; i++) {
                     sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
@@ -275,6 +289,10 @@
         }
     }
 
+    public static ImsResolver getImsResolver() {
+        return sImsResolver;
+    }
+
     /**
      * Makes a {@link SipPhone} object.
      * @param sipUri the local SIP URI the phone runs on
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index 652dac8..57fc43b 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -16,30 +16,18 @@
 
 package com.android.internal.telephony;
 
-import android.content.Context;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.telephony.CellInfo;
+import android.os.WorkSource;
+import android.os.ResultReceiver;
 import android.telephony.CellLocation;
 import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-
-import com.android.internal.telephony.imsphone.ImsPhone;
-import com.android.internal.telephony.RadioCapability;
-import com.android.internal.telephony.test.SimulatedRadioControl;
-import com.android.internal.telephony.uicc.IsimRecords;
-import com.android.internal.telephony.uicc.UiccCard;
-import com.android.internal.telephony.uicc.UsimServiceTable;
 
 import com.android.internal.telephony.PhoneConstants.*; // ????
 
 import java.util.List;
-import java.util.Locale;
 
 /**
  * Internal interface used to control the phone; SDK developers cannot
@@ -219,8 +207,9 @@
 
     /**
      * Get the current CellLocation.
+     * @param workSource calling WorkSource
      */
-    CellLocation getCellLocation();
+    CellLocation getCellLocation(WorkSource workSource);
 
     /**
      * Get the current DataState. No change notification exists at this
@@ -448,6 +437,15 @@
     boolean handlePinMmi(String dialString);
 
     /**
+     * Handles USSD commands
+     *
+     * @param ussdRequest the USSD command to be executed.
+     * @param wrappedCallback receives the callback result.
+     */
+    boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
+            throws CallStateException;
+
+    /**
      * Handles in-call MMI commands. While in a call, or while receiving a
      * call, use this to execute MMI commands.
      * see 3GPP 20.030, section 6.5.5.1 for specs on the allowed MMI commands.
@@ -655,8 +653,9 @@
      *
      * @param response callback message that is dispatched when the query
      * completes.
+     * @param workSource calling WorkSource
      */
-    void getNeighboringCids(Message response);
+    default void getNeighboringCids(Message response, WorkSource workSource){}
 
     /**
      * Mutes or unmutes the microphone for the active call. The microphone
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 02f15d9..2caf5e2 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -59,5 +59,9 @@
 
     public void notifyVoLteServiceStateChanged(Phone sender, VoLteServiceState lteState);
 
+    public void notifyVoiceActivationStateChanged(Phone sender, int activationState);
+
+    public void notifyDataActivationStateChanged(Phone sender, int activationState);
+
     public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData);
 }
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index a867d12..361b51a 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.uicc.UiccCardApplication;
 
 import static android.Manifest.permission.CALL_PRIVILEGED;
+import static android.Manifest.permission.READ_PHONE_NUMBERS;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
 import static android.Manifest.permission.READ_SMS;
@@ -434,7 +435,8 @@
     }
 
     /**
-     * Besides READ_PHONE_STATE, WRITE_SMS and READ_SMS also allow apps to get phone numbers.
+     * Besides READ_PHONE_STATE, READ_PHONE_NUMBERS, WRITE_SMS and READ_SMS also allow apps to get
+     * phone numbers.
      */
     private boolean checkReadPhoneNumber(String callingPackage, String message) {
         // Default SMS app can always read it.
@@ -445,18 +447,36 @@
         try {
             return checkReadPhoneState(callingPackage, message);
         } catch (SecurityException readPhoneStateSecurityException) {
-            try {
-                // Can be read with READ_SMS too.
-                mContext.enforceCallingOrSelfPermission(READ_SMS, message);
-                return mAppOps.noteOp(AppOpsManager.OP_READ_SMS,
-                        Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
-            } catch (SecurityException readSmsSecurityException) {
-                // Throw exception with message including both READ_PHONE_STATE and READ_SMS
-                // permissions
-                throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
-                        " nor current process has " + READ_PHONE_STATE + " or " + READ_SMS + ".");
-            }
         }
+        try {
+            // Can be read with READ_SMS too.
+            mContext.enforceCallingOrSelfPermission(READ_SMS, message);
+            int opCode = mAppOps.permissionToOpCode(READ_SMS);
+            if (opCode != AppOpsManager.OP_NONE) {
+                return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+                        == AppOpsManager.MODE_ALLOWED;
+            } else {
+                return true;
+            }
+        } catch (SecurityException readSmsSecurityException) {
+        }
+        try {
+            // Can be read with READ_PHONE_NUMBERS too.
+            mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, message);
+            int opCode = mAppOps.permissionToOpCode(READ_PHONE_NUMBERS);
+            if (opCode != AppOpsManager.OP_NONE) {
+                return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+                        == AppOpsManager.MODE_ALLOWED;
+            } else {
+                return true;
+            }
+        } catch (SecurityException readPhoneNumberSecurityException) {
+        }
+        // Throw exception with message including READ_PHONE_STATE, READ_SMS, and READ_PHONE_NUMBERS
+        // permissions
+        throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
+                " nor current process has " + READ_PHONE_STATE + ", " +
+                READ_SMS + ", or " + READ_PHONE_STATE + ".");
     }
 
     private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index 41cccd4..15dc842 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -23,9 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.MatchAllNetworkSpecifier;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.net.StringNetworkSpecifier;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -33,22 +36,16 @@
 import android.os.RegistrantList;
 import android.os.RemoteException;
 import android.telephony.Rlog;
-import android.text.TextUtils;
 import android.util.LocalLog;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.IOnSubscriptionsChangedListener;
-import com.android.internal.telephony.ITelephonyRegistry;
 import com.android.internal.telephony.dataconnection.DcRequest;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.IllegalArgumentException;
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -148,7 +145,7 @@
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        netCap.setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+        netCap.setNetworkSpecifier(new MatchAllNetworkSpecifier());
 
         NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
                 netCap, this);
@@ -368,14 +365,23 @@
     }
 
     private int phoneIdForRequest(NetworkRequest netRequest) {
-        String specifier = netRequest.networkCapabilities.getNetworkSpecifier();
+        NetworkSpecifier specifier = netRequest.networkCapabilities.getNetworkSpecifier();
         int subId;
 
-        if (TextUtils.isEmpty(specifier)) {
+        if (specifier == null) {
             subId = mDefaultDataSubscription;
+        } else if (specifier instanceof StringNetworkSpecifier) {
+            try {
+                subId = Integer.parseInt(((StringNetworkSpecifier) specifier).specifier);
+            } catch (NumberFormatException e) {
+                Rlog.e(LOG_TAG, "NumberFormatException on "
+                        + ((StringNetworkSpecifier) specifier).specifier);
+                subId = INVALID_SUBSCRIPTION_ID;
+            }
         } else {
-            subId = Integer.parseInt(specifier);
+            subId = INVALID_SUBSCRIPTION_ID;
         }
+
         int phoneId = INVALID_PHONE_INDEX;
         if (subId == INVALID_SUBSCRIPTION_ID) return phoneId;
 
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 2e50b2f..7d211fb 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -16,77 +16,90 @@
 
 package com.android.internal.telephony;
 
-import android.content.BroadcastReceiver;
+import static com.android.internal.telephony.RILConstants.*;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.display.DisplayManager;
+import android.hardware.radio.V1_0.Carrier;
+import android.hardware.radio.V1_0.CarrierRestrictions;
+import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
+import android.hardware.radio.V1_0.CdmaSmsAck;
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.hardware.radio.V1_0.CdmaSmsWriteArgs;
+import android.hardware.radio.V1_0.CellInfoCdma;
+import android.hardware.radio.V1_0.CellInfoGsm;
+import android.hardware.radio.V1_0.CellInfoLte;
+import android.hardware.radio.V1_0.CellInfoType;
+import android.hardware.radio.V1_0.CellInfoWcdma;
+import android.hardware.radio.V1_0.DataProfileInfo;
+import android.hardware.radio.V1_0.Dial;
+import android.hardware.radio.V1_0.GsmBroadcastSmsConfigInfo;
+import android.hardware.radio.V1_0.GsmSmsMessage;
+import android.hardware.radio.V1_0.HardwareConfigModem;
+import android.hardware.radio.V1_0.IRadio;
+import android.hardware.radio.V1_0.IccIo;
+import android.hardware.radio.V1_0.ImsSmsMessage;
+import android.hardware.radio.V1_0.LceDataInfo;
+import android.hardware.radio.V1_0.MvnoType;
+import android.hardware.radio.V1_0.NvWriteItem;
+import android.hardware.radio.V1_0.RadioError;
+import android.hardware.radio.V1_0.RadioIndicationType;
+import android.hardware.radio.V1_0.RadioResponseInfo;
+import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.V1_0.ResetNvType;
+import android.hardware.radio.V1_0.SelectUiccSub;
+import android.hardware.radio.V1_0.SetupDataCallResult;
+import android.hardware.radio.V1_0.SimApdu;
+import android.hardware.radio.V1_0.SmsWriteArgs;
+import android.hardware.radio.V1_0.UusInfo;
+import android.hardware.radio.deprecated.V1_0.IOemHook;
 import android.net.ConnectivityManager;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
 import android.os.AsyncResult;
-import android.os.BatteryManager;
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
+import android.os.HwBinder;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.WorkSource;
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.CellInfo;
+import android.telephony.ClientRequestStats;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
-import android.telephony.PcoData;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.RadioAccessFamily;
 import android.telephony.Rlog;
 import android.telephony.SignalStrength;
 import android.telephony.SmsManager;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyHistogram;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.SparseArray;
-import android.view.Display;
 
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.TelephonyProto.TelephonySettings;
-import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
 import com.android.internal.telephony.dataconnection.DataCallResponse;
 import com.android.internal.telephony.dataconnection.DataProfile;
-import com.android.internal.telephony.dataconnection.DcFailCause;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import com.android.internal.telephony.gsm.SsData;
-import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus;
-import com.android.internal.telephony.uicc.IccCardStatus;
-import com.android.internal.telephony.uicc.IccIoResult;
-import com.android.internal.telephony.uicc.IccRefreshResponse;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
 import com.android.internal.telephony.uicc.IccUtils;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
-
-import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
-import static com.android.internal.telephony.RILConstants.*;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * {@hide}
@@ -102,15 +115,15 @@
     private static RILRequest sPool = null;
     private static int sPoolSize = 0;
     private static final int MAX_POOL_SIZE = 4;
-    private Context mContext;
 
     //***** Instance Variables
     int mSerial;
     int mRequest;
     Message mResult;
-    Parcel mParcel;
     RILRequest mNext;
     int mWakeLockType;
+    WorkSource mWorkSource;
+    String mClientId;
     // time in ms when RIL request was made
     long mStartTimeMs;
 
@@ -121,7 +134,7 @@
      * @param result sent when operation completes
      * @return a RILRequest instance from the pool.
      */
-    static RILRequest obtain(int request, Message result) {
+    private static RILRequest obtain(int request, Message result) {
         RILRequest rr = null;
 
         synchronized(sPoolSync) {
@@ -141,17 +154,36 @@
 
         rr.mRequest = request;
         rr.mResult = result;
-        rr.mParcel = Parcel.obtain();
 
         rr.mWakeLockType = RIL.INVALID_WAKELOCK;
+        rr.mWorkSource = null;
         rr.mStartTimeMs = SystemClock.elapsedRealtime();
         if (result != null && result.getTarget() == null) {
             throw new NullPointerException("Message target must not be null");
         }
 
-        // first elements in any RIL Parcel
-        rr.mParcel.writeInt(request);
-        rr.mParcel.writeInt(rr.mSerial);
+        return rr;
+    }
+
+
+    /**
+     * Retrieves a new RILRequest instance from the pool and sets the clientId
+     *
+     * @param request RIL_REQUEST_*
+     * @param result sent when operation completes
+     * @param workSource WorkSource to track the client
+     * @return a RILRequest instance from the pool.
+     */
+    static RILRequest obtain(int request, Message result, WorkSource workSource) {
+        RILRequest rr = null;
+
+        rr = obtain(request, result);
+        if(workSource != null) {
+            rr.mWorkSource = workSource;
+            rr.mClientId = String.valueOf(workSource.get(0)) + ":" + workSource.getName(0);
+        } else {
+            Rlog.e(LOG_TAG, "null workSource " + request);
+        }
 
         return rr;
     }
@@ -224,11 +256,6 @@
             AsyncResult.forMessage(mResult, ret, ex);
             mResult.sendToTarget();
         }
-
-        if (mParcel != null) {
-            mParcel.recycle();
-            mParcel = null;
-        }
     }
 }
 
@@ -244,9 +271,6 @@
     static final String RILJ_ACK_WAKELOCK_NAME = "RILJ_ACK_WL";
     static final boolean RILJ_LOGD = true;
     static final boolean RILJ_LOGV = false; // STOPSHIP if true
-    static final int RADIO_SCREEN_UNSET = -1;
-    static final int RADIO_SCREEN_OFF = 0;
-    static final int RADIO_SCREEN_ON = 1;
     static final int RIL_HISTOGRAM_BUCKET_COUNT = 5;
 
     /**
@@ -264,18 +288,10 @@
     public static final int INVALID_WAKELOCK = -1;
     public static final int FOR_WAKELOCK = 0;
     public static final int FOR_ACK_WAKELOCK = 1;
+    private final ClientWakelockTracker mClientWakelockTracker = new ClientWakelockTracker();
 
     //***** Instance Variables
 
-    LocalSocket mSocket;
-    HandlerThread mSenderThread;
-    RILSender mSender;
-    Thread mReceiverThread;
-    RILReceiver mReceiver;
-    Display mDefaultDisplay;
-    int mDefaultDisplayState = Display.STATE_UNKNOWN;
-    int mRadioScreenState = RADIO_SCREEN_UNSET;
-    boolean mIsDevicePlugged = false;
     final WakeLock mWakeLock;           // Wake lock associated with request/response
     final WakeLock mAckWakeLock;        // Wake lock associated with ack sent
     final int mWakeLockTimeout;         // Timeout associated with request/response
@@ -297,69 +313,39 @@
     // When we are testing emergency calls
     AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
 
-    private Integer mInstanceId;
+    final Integer mPhoneId;
 
+    /* default work source which will blame phone process */
+    private WorkSource mRILDefaultWorkSource;
+
+    /* Worksource containing all applications causing wakelock to be held */
+    private WorkSource mActiveWakelockWorkSource;
+
+    /** Telephony metrics instance for logging metrics event */
     private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
 
-    //***** Events
+    boolean mIsMobileNetworkSupported;
+    RadioResponse mRadioResponse;
+    RadioIndication mRadioIndication;
+    volatile IRadio mRadioProxy = null;
+    OemHookResponse mOemHookResponse;
+    OemHookIndication mOemHookIndication;
+    volatile IOemHook mOemHookProxy = null;
+    final AtomicLong mRadioProxyCookie = new AtomicLong(0);
+    final RadioProxyDeathRecipient mRadioProxyDeathRecipient;
+    final RilHandler mRilHandler;
 
-    static final int EVENT_SEND                 = 1;
+    //***** Events
     static final int EVENT_WAKE_LOCK_TIMEOUT    = 2;
-    static final int EVENT_SEND_ACK             = 3;
     static final int EVENT_ACK_WAKE_LOCK_TIMEOUT    = 4;
     static final int EVENT_BLOCKING_RESPONSE_TIMEOUT = 5;
+    static final int EVENT_RADIO_PROXY_DEAD     = 6;
 
     //***** Constants
 
-    // match with constant in ril.cpp
-    static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
-    static final int RESPONSE_SOLICITED = 0;
-    static final int RESPONSE_UNSOLICITED = 1;
-    static final int RESPONSE_SOLICITED_ACK = 2;
-    static final int RESPONSE_SOLICITED_ACK_EXP = 3;
-    static final int RESPONSE_UNSOLICITED_ACK_EXP = 4;
+    static final String[] HIDL_SERVICE_NAME = {"slot1", "slot2", "slot3"};
 
-    static final String[] SOCKET_NAME_RIL = {"rild", "rild2", "rild3"};
-
-    static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
-
-    // The number of the required config values for broadcast SMS stored in the C struct
-    // RIL_CDMA_BroadcastServiceInfo
-    private static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3;
-
-    private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31;
-
-    private final DisplayManager.DisplayListener mDisplayListener =
-            new DisplayManager.DisplayListener() {
-        @Override
-        public void onDisplayAdded(int displayId) { }
-
-        @Override
-        public void onDisplayRemoved(int displayId) { }
-
-        @Override
-        public void onDisplayChanged(int displayId) {
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                final int oldState = mDefaultDisplayState;
-                mDefaultDisplayState = mDefaultDisplay.getState();
-                if (mDefaultDisplayState != oldState) {
-                    updateScreenState();
-                }
-            }
-        }
-    };
-
-    private final BroadcastReceiver mBatteryStateListener = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            boolean oldState = mIsDevicePlugged;
-            // 0 means it's on battery
-            mIsDevicePlugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
-            if (mIsDevicePlugged != oldState) {
-                updateScreenState();
-            }
-        }
-    };
+    static final int IRADIO_GET_SERVICE_DELAY_MILLIS = 4 * 1000;
 
     public static List<TelephonyHistogram> getTelephonyRILTimingHistograms() {
         List<TelephonyHistogram> list;
@@ -373,102 +359,13 @@
         return list;
     }
 
-    class RILSender extends Handler implements Runnable {
-        public RILSender(Looper looper) {
-            super(looper);
-        }
-
-        // Only allocated once
-        byte[] dataLength = new byte[4];
-
-        //***** Runnable implementation
-        @Override
-        public void
-        run() {
-            //setup if needed
-        }
-
-
+    class RilHandler extends Handler {
         //***** Handler implementation
         @Override public void
         handleMessage(Message msg) {
-            RILRequest rr = (RILRequest)(msg.obj);
-            RILRequest req = null;
+            RILRequest rr;
 
             switch (msg.what) {
-                case EVENT_SEND:
-                case EVENT_SEND_ACK:
-                    try {
-                        LocalSocket s;
-
-                        s = mSocket;
-
-                        if (s == null) {
-                            rr.onError(RADIO_NOT_AVAILABLE, null);
-                            decrementWakeLock(rr);
-                            rr.release();
-                            return;
-                        }
-
-                        // Acks should not be stored in list before sending
-                        if (msg.what != EVENT_SEND_ACK) {
-                            synchronized (mRequestList) {
-                                rr.mStartTimeMs = SystemClock.elapsedRealtime();
-                                mRequestList.append(rr.mSerial, rr);
-                            }
-                        }
-
-                        byte[] data;
-
-                        data = rr.mParcel.marshall();
-                        rr.mParcel.recycle();
-                        rr.mParcel = null;
-
-                        if (data.length > RIL_MAX_COMMAND_BYTES) {
-                            throw new RuntimeException(
-                                    "Parcel larger than max bytes allowed! "
-                                                          + data.length);
-                        }
-
-                        // parcel length in big endian
-                        dataLength[0] = dataLength[1] = 0;
-                        dataLength[2] = (byte)((data.length >> 8) & 0xff);
-                        dataLength[3] = (byte)((data.length) & 0xff);
-
-                        //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");
-
-                        s.getOutputStream().write(dataLength);
-                        s.getOutputStream().write(data);
-                        if (msg.what == EVENT_SEND_ACK) {
-                            rr.release();
-                            return;
-                        }
-                    } catch (IOException ex) {
-                        Rlog.e(RILJ_LOG_TAG, "IOException", ex);
-                        req = findAndRemoveRequestFromList(rr.mSerial);
-                        // make sure this request has not already been handled,
-                        // eg, if RILReceiver cleared the list.
-                        if (req != null) {
-                            rr.onError(RADIO_NOT_AVAILABLE, null);
-                            decrementWakeLock(rr);
-                            rr.release();
-                            return;
-                        }
-                    } catch (RuntimeException exc) {
-                        Rlog.e(RILJ_LOG_TAG, "Uncaught exception ", exc);
-                        req = findAndRemoveRequestFromList(rr.mSerial);
-                        // make sure this request has not already been handled,
-                        // eg, if RILReceiver cleared the list.
-                        if (req != null) {
-                            rr.onError(GENERIC_FAILURE, null);
-                            decrementWakeLock(rr);
-                            rr.release();
-                            return;
-                        }
-                    }
-
-                    break;
-
                 case EVENT_WAKE_LOCK_TIMEOUT:
                     // Haven't heard back from the last request.  Assume we're
                     // not getting a response and  release the wake lock.
@@ -518,12 +415,25 @@
                         Object timeoutResponse = getResponseForTimedOutRILRequest(rr);
                         AsyncResult.forMessage( rr.mResult, timeoutResponse, null);
                         rr.mResult.sendToTarget();
-                        mMetrics.writeOnRilTimeoutResponse(mInstanceId, rr.mSerial, rr.mRequest);
+                        mMetrics.writeOnRilTimeoutResponse(mPhoneId, rr.mSerial, rr.mRequest);
                     }
 
                     decrementWakeLock(rr);
                     rr.release();
                     break;
+
+                case EVENT_RADIO_PROXY_DEAD:
+                    riljLog("handleMessage: EVENT_RADIO_PROXY_DEAD cookie = " + msg.obj +
+                            " mRadioProxyCookie = " + mRadioProxyCookie.get());
+                    if ((long) msg.obj == mRadioProxyCookie.get()) {
+                        resetProxyAndRequestList();
+
+                        // todo: rild should be back up since message was sent with a delay. this is
+                        // a hack.
+                        getRadioProxy(null);
+                        getOemHookProxy(null);
+                    }
+                    break;
             }
         }
     }
@@ -551,187 +461,129 @@
         return timeoutResponse;
     }
 
-    /**
-     * Reads in a single RIL message off the wire. A RIL message consists
-     * of a 4-byte little-endian length and a subsequent series of bytes.
-     * The final message (length header omitted) is read into
-     * <code>buffer</code> and the length of the final message (less header)
-     * is returned. A return value of -1 indicates end-of-stream.
-     *
-     * @param is non-null; Stream to read from
-     * @param buffer Buffer to fill in. Must be as large as maximum
-     * message size, or an ArrayOutOfBounds exception will be thrown.
-     * @return Length of message less header, or -1 on end of stream.
-     * @throws IOException
-     */
-    private static int readRilMessage(InputStream is, byte[] buffer)
-            throws IOException {
-        int countRead;
-        int offset;
-        int remaining;
-        int messageLength;
-
-        // First, read in the length of the message
-        offset = 0;
-        remaining = 4;
-        do {
-            countRead = is.read(buffer, offset, remaining);
-
-            if (countRead < 0 ) {
-                Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length");
-                return -1;
-            }
-
-            offset += countRead;
-            remaining -= countRead;
-        } while (remaining > 0);
-
-        messageLength = ((buffer[0] & 0xff) << 24)
-                | ((buffer[1] & 0xff) << 16)
-                | ((buffer[2] & 0xff) << 8)
-                | (buffer[3] & 0xff);
-
-        // Then, re-use the buffer and read in the message itself
-        offset = 0;
-        remaining = messageLength;
-        do {
-            countRead = is.read(buffer, offset, remaining);
-
-            if (countRead < 0 ) {
-                Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message.  messageLength=" + messageLength
-                        + " remaining=" + remaining);
-                return -1;
-            }
-
-            offset += countRead;
-            remaining -= countRead;
-        } while (remaining > 0);
-
-        return messageLength;
-    }
-
-    class RILReceiver implements Runnable {
-        byte[] buffer;
-
-        RILReceiver() {
-            buffer = new byte[RIL_MAX_COMMAND_BYTES];
-        }
-
+    final class RadioProxyDeathRecipient implements HwBinder.DeathRecipient {
         @Override
-        public void
-        run() {
-            int retryCount = 0;
-            String rilSocket = "rild";
-
-            try {for (;;) {
-                LocalSocket s = null;
-                LocalSocketAddress l;
-
-                if (mInstanceId == null || mInstanceId == 0 ) {
-                    rilSocket = SOCKET_NAME_RIL[0];
-                } else {
-                    rilSocket = SOCKET_NAME_RIL[mInstanceId];
-                }
-
-                try {
-                    s = new LocalSocket();
-                    l = new LocalSocketAddress(rilSocket,
-                            LocalSocketAddress.Namespace.RESERVED);
-                    s.connect(l);
-                } catch (IOException ex){
-                    try {
-                        if (s != null) {
-                            s.close();
-                        }
-                    } catch (IOException ex2) {
-                        //ignore failure to close after failure to connect
-                    }
-
-                    // don't print an error message after the the first time
-                    // or after the 8th time
-
-                    if (retryCount == 8) {
-                        Rlog.e (RILJ_LOG_TAG,
-                            "Couldn't find '" + rilSocket
-                            + "' socket after " + retryCount
-                            + " times, continuing to retry silently");
-                    } else if (retryCount >= 0 && retryCount < 8) {
-                        Rlog.i (RILJ_LOG_TAG,
-                            "Couldn't find '" + rilSocket
-                            + "' socket; retrying after timeout");
-                    }
-
-                    try {
-                        Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
-                    } catch (InterruptedException er) {
-                    }
-
-                    retryCount++;
-                    continue;
-                }
-
-                retryCount = 0;
-
-                mSocket = s;
-                Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Connected to '"
-                        + rilSocket + "' socket");
-
-                int length = 0;
-                try {
-                    InputStream is = mSocket.getInputStream();
-
-                    for (;;) {
-                        Parcel p;
-
-                        length = readRilMessage(is, buffer);
-
-                        if (length < 0) {
-                            // End-of-stream reached
-                            break;
-                        }
-
-                        p = Parcel.obtain();
-                        p.unmarshall(buffer, 0, length);
-                        p.setDataPosition(0);
-
-                        //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");
-
-                        processResponse(p);
-                        p.recycle();
-                    }
-                } catch (java.io.IOException ex) {
-                    Rlog.i(RILJ_LOG_TAG, "'" + rilSocket + "' socket closed",
-                          ex);
-                } catch (Throwable tr) {
-                    Rlog.e(RILJ_LOG_TAG, "Uncaught exception read length=" + length +
-                        "Exception:" + tr.toString());
-                }
-
-                Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Disconnected from '" + rilSocket
-                      + "' socket");
-
-                setRadioState (RadioState.RADIO_UNAVAILABLE);
-
-                try {
-                    mSocket.close();
-                } catch (IOException ex) {
-                }
-
-                mSocket = null;
-                RILRequest.resetSerial();
-
-                // Clear request list on close
-                clearRequestList(RADIO_NOT_AVAILABLE, false);
-            }} catch (Throwable tr) {
-                Rlog.e(RILJ_LOG_TAG,"Uncaught exception", tr);
-            }
-
-            /* We're disconnected so we don't know the ril version */
-            notifyRegistrantsRilConnectionChanged(-1);
+        public void serviceDied(long cookie) {
+            // Deal with service going away
+            riljLog("serviceDied");
+            // todo: temp hack to send delayed message so that rild is back up by then
+            //mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, cookie));
+            mRilHandler.sendMessageDelayed(
+                    mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, cookie),
+                    IRADIO_GET_SERVICE_DELAY_MILLIS);
         }
     }
 
+    private void resetProxyAndRequestList() {
+        mRadioProxy = null;
+        mOemHookProxy = null;
 
+        // increment the cookie so that death notification can be ignored
+        mRadioProxyCookie.incrementAndGet();
+
+        setRadioState(RadioState.RADIO_UNAVAILABLE);
+
+        RILRequest.resetSerial();
+        // Clear request list on close
+        clearRequestList(RADIO_NOT_AVAILABLE, false);
+
+        // todo: need to get service right away so setResponseFunctions() can be called for
+        // unsolicited indications. getService() is not a blocking call, so it doesn't help to call
+        // it here. Current hack is to call getService() on death notification after a delay.
+    }
+
+    private IRadio getRadioProxy(Message result) {
+        if (!mIsMobileNetworkSupported) {
+            if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only");
+            if (result != null) {
+                AsyncResult.forMessage(result, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                result.sendToTarget();
+            }
+            return null;
+        }
+
+        if (mRadioProxy != null) {
+            return mRadioProxy;
+        }
+
+        try {
+            mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
+            if (mRadioProxy != null) {
+                mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
+                        mRadioProxyCookie.incrementAndGet());
+                mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
+            } else {
+                riljLoge("getRadioProxy: mRadioProxy == null");
+            }
+        } catch (RemoteException | RuntimeException e) {
+            mRadioProxy = null;
+            riljLoge("RadioProxy getService/setResponseFunctions: " + e);
+        }
+
+        if (mRadioProxy == null) {
+            if (result != null) {
+                AsyncResult.forMessage(result, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                result.sendToTarget();
+            }
+
+            // if service is not up, treat it like death notification to try to get service again
+            mRilHandler.sendMessageDelayed(
+                    mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+                            mRadioProxyCookie.incrementAndGet()),
+                    IRADIO_GET_SERVICE_DELAY_MILLIS);
+        }
+
+        return mRadioProxy;
+    }
+
+    private IOemHook getOemHookProxy(Message result) {
+        if (!mIsMobileNetworkSupported) {
+            if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only");
+            if (result != null) {
+                AsyncResult.forMessage(result, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                result.sendToTarget();
+            }
+            return null;
+        }
+
+        if (mOemHookProxy != null) {
+            return mOemHookProxy;
+        }
+
+        try {
+            mOemHookProxy = IOemHook.getService(
+                    HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
+            if (mOemHookProxy != null) {
+                // not calling linkToDeath() as ril service runs in the same process and death
+                // notification for that should be sufficient
+                mOemHookProxy.setResponseFunctions(mOemHookResponse, mOemHookIndication);
+            } else {
+                riljLoge("getOemHookProxy: mOemHookProxy == null");
+            }
+        } catch (RemoteException | RuntimeException e) {
+            mOemHookProxy = null;
+            riljLoge("OemHookProxy getService/setResponseFunctions: " + e);
+        }
+
+        if (mOemHookProxy == null) {
+            if (result != null) {
+                AsyncResult.forMessage(result, null,
+                        CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+                result.sendToTarget();
+            }
+
+            // if service is not up, treat it like death notification to try to get service again
+            mRilHandler.sendMessageDelayed(
+                    mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+                            mRadioProxyCookie.incrementAndGet()),
+                    IRADIO_GET_SERVICE_DELAY_MILLIS);
+        }
+
+        return mOemHookProxy;
+    }
 
     //***** Constructors
 
@@ -743,15 +595,26 @@
             int cdmaSubscription, Integer instanceId) {
         super(context);
         if (RILJ_LOGD) {
-            riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
-                    " cdmaSubscription=" + cdmaSubscription + ")");
+            riljLog("RIL: init preferredNetworkType=" + preferredNetworkType
+                    + " cdmaSubscription=" + cdmaSubscription + ")");
         }
 
         mContext = context;
         mCdmaSubscription  = cdmaSubscription;
         mPreferredNetworkType = preferredNetworkType;
         mPhoneType = RILConstants.NO_PHONE;
-        mInstanceId = instanceId;
+        mPhoneId = instanceId;
+
+        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+        mRadioResponse = new RadioResponse(this);
+        mRadioIndication = new RadioIndication(this);
+        mOemHookResponse = new OemHookResponse(this);
+        mOemHookIndication = new OemHookIndication(this);
+        mRilHandler = new RilHandler();
+        mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG);
@@ -763,60 +626,16 @@
         mAckWakeLockTimeout = SystemProperties.getInt(
                 TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS);
         mWakeLockCount = 0;
-
-        mSenderThread = new HandlerThread("RILSender" + mInstanceId);
-        mSenderThread.start();
-
-        Looper looper = mSenderThread.getLooper();
-        mSender = new RILSender(looper);
-
-        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
-            riljLog("Not starting RILReceiver: wifi-only");
-        } else {
-            riljLog("Starting RILReceiver" + mInstanceId);
-            mReceiver = new RILReceiver();
-            mReceiverThread = new Thread(mReceiver, "RILReceiver" + mInstanceId);
-            mReceiverThread.start();
-
-            DisplayManager dm = (DisplayManager)context.getSystemService(
-                    Context.DISPLAY_SERVICE);
-            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
-            dm.registerDisplayListener(mDisplayListener, null);
-            mDefaultDisplayState = mDefaultDisplay.getState();
-
-            IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
-            Intent batteryStatus = context.registerReceiver(mBatteryStateListener, filter);
-            if (batteryStatus != null) {
-                // 0 means it's on battery
-                mIsDevicePlugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
-            }
-        }
+        mRILDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid,
+                context.getPackageName());
 
         TelephonyDevController tdc = TelephonyDevController.getInstance();
         tdc.registerRIL(this);
-    }
 
-    //***** CommandsInterface implementation
-
-    @Override
-    public void getVoiceRadioTechnology(Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_VOICE_RADIO_TECH, result);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-        send(rr);
-    }
-
-
-    public void getImsRegistrationState(Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_REGISTRATION_STATE, result);
-
-        if (RILJ_LOGD) {
-            riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-        }
-        send(rr);
+        // set radio callback; needed to set RadioIndication callback (should be done after
+        // wakelock stuff is initialized above as callbacks are received on separate binder threads)
+        getRadioProxy(null);
+        getOemHookProxy(null);
     }
 
     @Override public void
@@ -831,46 +650,52 @@
         }
     }
 
+    private void addRequest(RILRequest rr) {
+        acquireWakeLock(rr, FOR_WAKELOCK);
+        synchronized (mRequestList) {
+            rr.mStartTimeMs = SystemClock.elapsedRealtime();
+            mRequestList.append(rr.mSerial, rr);
+        }
+    }
+
+    private RILRequest obtainRequest(int request, Message result, WorkSource workSource) {
+        RILRequest rr = RILRequest.obtain(request, result, workSource);
+        addRequest(rr);
+        return rr;
+    }
+
+    private void handleRadioProxyExceptionForRR(RILRequest rr, String caller, Exception e) {
+        riljLoge(caller + ": " + e);
+        resetProxyAndRequestList();
+
+        // service most likely died, handle exception like death notification to try to get service
+        // again
+        mRilHandler.sendMessageDelayed(
+                mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+                        mRadioProxyCookie.incrementAndGet()),
+                IRADIO_GET_SERVICE_DELAY_MILLIS);
+    }
+
+    private String convertNullToEmptyString(String string) {
+        return string != null ? string : "";
+    }
+
     @Override
     public void
     getIccCardStatus(Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
-        send(rr);
-    }
-
-    public void setUiccSubscription(int slotId, int appIndex, int subId,
-            int subStatus, Message result) {
-        //Note: This RIL request is also valid for SIM and RUIM (ICC card)
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
-                + " slot: " + slotId + " appIndex: " + appIndex
-                + " subId: " + subId + " subStatus: " + subStatus);
-
-        rr.mParcel.writeInt(slotId);
-        rr.mParcel.writeInt(appIndex);
-        rr.mParcel.writeInt(subId);
-        rr.mParcel.writeInt(subStatus);
-
-        send(rr);
-    }
-
-    // FIXME This API should take an AID and slot ID
-    public void setDataAllowed(boolean allowed, Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ALLOW_DATA, result);
-        if (RILJ_LOGD) {
-            riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) +
-                    " allowed: " + allowed);
+            try {
+                radioProxy.getIccCardStatus(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getIccCardStatus", e);
+            }
         }
-
-        rr.mParcel.writeInt(1);
-        rr.mParcel.writeInt(allowed ? 1 : 0);
-        send(rr);
     }
 
     @Override public void
@@ -880,38 +705,52 @@
 
     @Override public void
     supplyIccPinForApp(String pin, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                        + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(2);
-        rr.mParcel.writeString(pin);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.supplyIccPinForApp(rr.mSerial,
+                        convertNullToEmptyString(pin),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "supplyIccPinForApp", e);
+            }
+        }
     }
 
-    @Override public void
-    supplyIccPuk(String puk, String newPin, Message result) {
+    @Override
+    public void supplyIccPuk(String puk, String newPin, Message result) {
         supplyIccPukForApp(puk, newPin, null, result);
     }
 
-    @Override public void
-    supplyIccPukForApp(String puk, String newPin, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result);
+    @Override
+    public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                        + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(3);
-        rr.mParcel.writeString(puk);
-        rr.mParcel.writeString(newPin);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.supplyIccPukForApp(rr.mSerial,
+                        convertNullToEmptyString(puk),
+                        convertNullToEmptyString(newPin),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "supplyIccPukForApp", e);
+            }
+        }
     }
 
     @Override public void
@@ -921,17 +760,24 @@
 
     @Override public void
     supplyIccPin2ForApp(String pin, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN2, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                        + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(2);
-        rr.mParcel.writeString(pin);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.supplyIccPin2ForApp(rr.mSerial,
+                        convertNullToEmptyString(pin),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "supplyIccPin2ForApp", e);
+            }
+        }
     }
 
     @Override public void
@@ -941,18 +787,25 @@
 
     @Override public void
     supplyIccPuk2ForApp(String puk, String newPin2, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK2, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                        + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(3);
-        rr.mParcel.writeString(puk);
-        rr.mParcel.writeString(newPin2);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.supplyIccPuk2ForApp(rr.mSerial,
+                        convertNullToEmptyString(puk),
+                        convertNullToEmptyString(newPin2),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "supplyIccPuk2ForApp", e);
+            }
+        }
     }
 
     @Override public void
@@ -962,18 +815,25 @@
 
     @Override public void
     changeIccPinForApp(String oldPin, String newPin, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " oldPin = "
+                        + oldPin + " newPin = " + newPin + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(3);
-        rr.mParcel.writeString(oldPin);
-        rr.mParcel.writeString(newPin);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.changeIccPinForApp(rr.mSerial,
+                        convertNullToEmptyString(oldPin),
+                        convertNullToEmptyString(newPin),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "changeIccPinForApp", e);
+            }
+        }
     }
 
     @Override public void
@@ -983,284 +843,2826 @@
 
     @Override public void
     changeIccPin2ForApp(String oldPin2, String newPin2, String aid, Message result) {
-        //Note: This RIL request has not been renamed to ICC,
-        //       but this request is also valid for SIM and RUIM
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result);
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN2, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " oldPin = "
+                        + oldPin2 + " newPin = " + newPin2 + " aid = " + aid);
+            }
 
-        rr.mParcel.writeInt(3);
-        rr.mParcel.writeString(oldPin2);
-        rr.mParcel.writeString(newPin2);
-        rr.mParcel.writeString(aid);
-
-        send(rr);
+            try {
+                radioProxy.changeIccPin2ForApp(rr.mSerial,
+                        convertNullToEmptyString(oldPin2),
+                        convertNullToEmptyString(newPin2),
+                        convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "changeIccPin2ForApp", e);
+            }
+        }
     }
 
     @Override
-    public void
-    changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result);
+    public void supplyNetworkDepersonalization(String netpin, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " netpin = "
+                        + netpin);
+            }
 
-        rr.mParcel.writeInt(3);
-        rr.mParcel.writeString(facility);
-        rr.mParcel.writeString(oldPwd);
-        rr.mParcel.writeString(newPwd);
-
-        send(rr);
+            try {
+                radioProxy.supplyNetworkDepersonalization(rr.mSerial,
+                        convertNullToEmptyString(netpin));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "supplyNetworkDepersonalization", e);
+            }
+        }
     }
 
     @Override
-    public void
-    supplyNetworkDepersonalization(String netpin, Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result);
+    public void getCurrentCalls(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            }
 
-        rr.mParcel.writeInt(1);
-        rr.mParcel.writeString(netpin);
-
-        send(rr);
+            try {
+                radioProxy.getCurrentCalls(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getCurrentCalls", e);
+            }
+        }
     }
 
     @Override
-    public void
-    getCurrentCalls (Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-        send(rr);
-    }
-
-    @Override
-    @Deprecated public void
-    getPDPContextList(Message result) {
-        getDataCallList(result);
-    }
-
-    @Override
-    public void
-    getDataCallList(Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_DATA_CALL_LIST, result);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-        send(rr);
-    }
-
-    @Override
-    public void
-    dial (String address, int clirMode, Message result) {
+    public void dial(String address, int clirMode, Message result) {
         dial(address, clirMode, null, result);
     }
 
     @Override
-    public void
-    dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
+    public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
+                    mRILDefaultWorkSource);
 
-        rr.mParcel.writeString(address);
-        rr.mParcel.writeInt(clirMode);
+            Dial dialInfo = new Dial();
+            dialInfo.address = convertNullToEmptyString(address);
+            dialInfo.clir = clirMode;
+            if (uusInfo != null) {
+                UusInfo info = new UusInfo();
+                info.uusType = uusInfo.getType();
+                info.uusDcs = uusInfo.getDcs();
+                info.uusData = new String(uusInfo.getUserData());
+                dialInfo.uusInfo.add(info);
+            }
 
-        if (uusInfo == null) {
-            rr.mParcel.writeInt(0); // UUS information is absent
-        } else {
-            rr.mParcel.writeInt(1); // UUS information is present
-            rr.mParcel.writeInt(uusInfo.getType());
-            rr.mParcel.writeInt(uusInfo.getDcs());
-            rr.mParcel.writeByteArray(uusInfo.getUserData());
+            if (RILJ_LOGD) {
+                // Do not log function arg for privacy
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            }
+
+            try {
+                radioProxy.dial(rr.mSerial, dialInfo);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "dial", e);
+            }
         }
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
-        send(rr);
     }
 
     @Override
-    public void
-    getIMSI(Message result) {
+    public void getIMSI(Message result) {
         getIMSIForApp(null, result);
     }
 
     @Override
-    public void
-    getIMSIForApp(String aid, Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
+    public void getIMSIForApp(String aid, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result,
+                    mRILDefaultWorkSource);
 
-        rr.mParcel.writeInt(1);
-        rr.mParcel.writeString(aid);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() +
-                              "> getIMSI: " + requestToString(rr.mRequest)
-                              + " aid: " + aid);
-
-        send(rr);
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString()
+                        + ">  " + requestToString(rr.mRequest) + " aid = " + aid);
+            }
+            try {
+                radioProxy.getImsiForApp(rr.mSerial, convertNullToEmptyString(aid));
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getIMSIForApp", e);
+            }
+        }
     }
 
     @Override
-    public void
-    getIMEI(Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result);
+    public void hangupConnection(int gsmIndex, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " gsmIndex = "
+                        + gsmIndex);
+            }
 
-        send(rr);
+            try {
+                radioProxy.hangup(rr.mSerial, gsmIndex);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "hangupConnection", e);
+            }
+        }
     }
 
     @Override
-    public void
-    getIMEISV(Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result);
+    public void hangupWaitingOrBackground(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
-        send(rr);
-    }
-
-
-    @Override
-    public void
-    hangupConnection (int gsmIndex, Message result) {
-        if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex);
-
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result);
-
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " +
-                gsmIndex);
-
-        rr.mParcel.writeInt(1);
-        rr.mParcel.writeInt(gsmIndex);
-
-        send(rr);
+            try {
+                radioProxy.hangupWaitingOrBackground(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "hangupWaitingOrBackground", e);
+            }
+        }
     }
 
     @Override
-    public void
-    hangupWaitingOrBackground (Message result) {
-        RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
-                                        result);
+    public void hangupForegroundResumeBackground(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
-        send(rr);
+            try {
+                radioProxy.hangupForegroundResumeBackground(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "hangupForegroundResumeBackground", e);
+            }
+        }
     }
 
     @Override
-    public void
-    hangupForegroundResumeBackground (Message result) {
-        RILRequest rr
-                = RILRequest.obtain(
-                        RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
-                                        result);
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+    public void switchWaitingOrHoldingAndActive(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result,
+                    mRILDefaultWorkSource);
 
-        send(rr);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.switchWaitingOrHoldingAndActive(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "switchWaitingOrHoldingAndActive", e);
+            }
+        }
     }
 
     @Override
-    public void
-    switchWaitingOrHoldingAndActive (Message result) {
-        RILRequest rr
-                = RILRequest.obtain(
-                        RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE,
-                                        result);
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+    public void conference(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_CONFERENCE, result,
+                    mRILDefaultWorkSource);
 
-        send(rr);
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.conference(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "conference", e);
+            }
+        }
     }
 
     @Override
-    public void
-    conference (Message result) {
-        RILRequest rr
-                = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result);
+    public void rejectCall(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_UDUB, result,
+                    mRILDefaultWorkSource);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
-        send(rr);
+            try {
+                radioProxy.rejectCall(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "rejectCall", e);
+            }
+        }
     }
 
+    @Override
+    public void getLastCallFailCause(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.getLastCallFailCause(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getLastCallFailCause", e);
+            }
+        }
+    }
+
+    @Override
+    public void getSignalStrength(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_SIGNAL_STRENGTH, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.getSignalStrength(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getSignalStrength", e);
+            }
+        }
+    }
+
+    @Override
+    public void getVoiceRegistrationState(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_REGISTRATION_STATE, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.getVoiceRegistrationState(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getVoiceRegistrationState", e);
+            }
+        }
+    }
+
+    @Override
+    public void getDataRegistrationState(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_DATA_REGISTRATION_STATE, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.getDataRegistrationState(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getDataRegistrationState", e);
+            }
+        }
+    }
+
+    @Override
+    public void getOperator(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_OPERATOR, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+            try {
+                radioProxy.getOperator(rr.mSerial);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "getOperator", e);
+            }
+        }
+    }
+
+    @Override
+    public void setRadioPower(boolean on, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            RILRequest rr = obtainRequest(RIL_REQUEST_RADIO_POWER, result,
+                    mRILDefaultWorkSource);
+
+            if (RILJ_LOGD) {
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+                        + " on = " + on);
+            }
+
+            try {
+                radioProxy.setRadioPower(rr.mSerial, on);
+            } catch (RemoteException | RuntimeException e) {
+                handleRadioProxyExceptionForRR(rr, "setRadioPower", e);
+            }
+        }
+    }
+
+    @Override
+    public void sendDtmf(char c, Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+