Merge "Handle removal of time_zones_by_country.xml"
diff --git a/Android.mk b/Android.mk
index 73d578c..c5668fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,9 +25,10 @@
 	$(call all-logtags-files-under, src/java) \
 	$(call all-proto-files-under, proto)
 
-LOCAL_JAVA_LIBRARIES := voip-common ims-common
-LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.0-java-static \
+LOCAL_JAVA_LIBRARIES := voip-common ims-common services
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.1-java-static \
     android.hardware.radio.deprecated-V1.0-java-static
+
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := telephony-common
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
diff --git a/src/java/android/provider/Telephony.java b/src/java/android/provider/Telephony.java
deleted file mode 100644
index afeca37..0000000
--- a/src/java/android/provider/Telephony.java
+++ /dev/null
@@ -1,3245 +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.app.job.JobService;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.sqlite.SqliteWrapper;
-import android.net.Uri;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
-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, access to the APN list, including the MMSC to use, and the service state.
- *
- * <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
-        };
-    }
-
-    /**
-     * Constants for interfacing with the ServiceStateProvider and the different fields of the
-     * {@link ServiceState} class accessible through the provider.
-     */
-    public static final class ServiceStateTable {
-
-        /**
-         * Not instantiable.
-         * @hide
-         */
-        private ServiceStateTable() {}
-
-        /**
-         * The authority string for the ServiceStateProvider
-         */
-        public static final String AUTHORITY = "service-state";
-
-        /**
-         * The {@code content://} style URL for the ServiceStateProvider
-         */
-        public static final Uri CONTENT_URI = Uri.parse("content://service-state/");
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on a specific field in the
-         * ServiceState provider.
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
-         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
-         *
-         * @param subId the subId to receive updates on
-         * @param field the ServiceState field to receive updates on
-         * @return the Uri used to observe {@link ServiceState} changes
-         */
-        public static Uri getUriForSubIdAndField(int subId, String field) {
-            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId))
-                    .appendEncodedPath(field).build();
-        }
-
-        /**
-         * Generates a content {@link Uri} used to receive updates on every field in the
-         * ServiceState provider.
-         * <p>
-         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
-         * {@link ServiceState} while your app is running.  You can also use a {@link JobService} to
-         * ensure your app is notified of changes to the {@link Uri} even when it is not running.
-         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
-         * updates to the {@link Uri}.
-         *
-         * @param subId the subId to receive updates on
-         * @return the Uri used to observe {@link ServiceState} changes
-         */
-        public static Uri getUriForSubId(int subId) {
-            return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)).build();
-        }
-
-        /**
-         * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
-         *
-         * @param state the ServiceState to convert into ContentValues
-         * @return the convertedContentValues instance
-         * @hide
-         */
-        public static ContentValues getContentValuesForServiceState(ServiceState state) {
-            ContentValues values = new ContentValues();
-            values.put(VOICE_REG_STATE, state.getVoiceRegState());
-            values.put(DATA_REG_STATE, state.getDataRegState());
-            values.put(VOICE_ROAMING_TYPE, state.getVoiceRoamingType());
-            values.put(DATA_ROAMING_TYPE, state.getDataRoamingType());
-            values.put(VOICE_OPERATOR_ALPHA_LONG, state.getVoiceOperatorAlphaLong());
-            values.put(VOICE_OPERATOR_ALPHA_SHORT, state.getVoiceOperatorAlphaShort());
-            values.put(VOICE_OPERATOR_NUMERIC, state.getVoiceOperatorNumeric());
-            values.put(DATA_OPERATOR_ALPHA_LONG, state.getDataOperatorAlphaLong());
-            values.put(DATA_OPERATOR_ALPHA_SHORT, state.getDataOperatorAlphaShort());
-            values.put(DATA_OPERATOR_NUMERIC, state.getDataOperatorNumeric());
-            values.put(IS_MANUAL_NETWORK_SELECTION, state.getIsManualSelection());
-            values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology());
-            values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology());
-            values.put(CSS_INDICATOR, state.getCssIndicator());
-            values.put(NETWORK_ID, state.getNetworkId());
-            values.put(SYSTEM_ID, state.getSystemId());
-            values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator());
-            values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator());
-            values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
-            values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
-            values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
-            values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
-            values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
-            return values;
-        }
-
-        /**
-         * An integer value indicating the current voice service state.
-         * <p>
-         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
-         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
-         * {@link ServiceState#STATE_POWER_OFF}.
-         * <p>
-         * This is the same as {@link ServiceState#getState()}.
-         */
-        public static final String VOICE_REG_STATE = "voice_reg_state";
-
-        /**
-         * An integer value indicating the current data service state.
-         * <p>
-         * Valid values: {@link ServiceState#STATE_IN_SERVICE},
-         * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
-         * {@link ServiceState#STATE_POWER_OFF}.
-         * <p>
-         * This is the same as {@link ServiceState#getDataRegState()}.
-         * @hide
-         */
-        public static final String DATA_REG_STATE = "data_reg_state";
-
-        /**
-         * An integer value indicating the current voice roaming type.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceRoamingType()}.
-         * @hide
-         */
-        public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
-
-        /**
-         * An integer value indicating the current data roaming type.
-         * <p>
-         * This is the same as {@link ServiceState#getDataRoamingType()}.
-         * @hide
-         */
-        public static final String DATA_ROAMING_TYPE = "data_roaming_type";
-
-        /**
-         * The current registered voice network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}.
-         * @hide
-         */
-        public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
-
-        /**
-         * The current registered operator name in short alphanumeric format.
-         * <p>
-         * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
-         * network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}.
-         * @hide
-         */
-        public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
-
-
-        /**
-         * The current registered operator numeric id.
-         * <p>
-         * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
-         * network code.
-         * <p>
-         * This is the same as {@link ServiceState#getOperatorNumeric()}.
-         */
-        public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
-
-        /**
-         * The current registered data network operator name in long alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
-
-        /**
-         * The current registered data network operator name in short alphanumeric format.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
-
-        /**
-         * The current registered data network operator numeric id.
-         * <p>
-         * This is the same as {@link ServiceState#getDataOperatorNumeric()}.
-         * @hide
-         */
-        public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
-
-        /**
-         * The current network selection mode.
-         * <p>
-         * This is the same as {@link ServiceState#getIsManualSelection()}.
-         */
-        public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
-
-        /**
-         * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
-         * @hide
-         */
-        public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
-
-        /**
-         * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
-         * @hide
-         */
-        public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
-
-        /**
-         * This is the same as {@link ServiceState#getCssIndicator()}.
-         * @hide
-         */
-        public static final String CSS_INDICATOR = "css_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getNetworkId()}.
-         * @hide
-         */
-        public static final String NETWORK_ID = "network_id";
-
-        /**
-         * This is the same as {@link ServiceState#getSystemId()}.
-         * @hide
-         */
-        public static final String SYSTEM_ID = "system_id";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
-         * @hide
-         */
-        public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
-         * @hide
-         */
-        public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
-                "cdma_default_roaming_indicator";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
-         * @hide
-         */
-        public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
-
-        /**
-         * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
-         * @hide
-         */
-        public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
-
-        /**
-         * This is the same as {@link ServiceState#isEmergencyOnly()}.
-         * @hide
-         */
-        public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
-
-        /**
-         * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
-         * @hide
-         */
-        public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
-                "is_data_roaming_from_registration";
-
-        /**
-         * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
-         * @hide
-         */
-        public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
-    }
-}
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 e31755a..0000000
--- a/src/java/android/telephony/SmsManager.java
+++ /dev/null
@@ -1,1671 +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.annotation.SystemApi;
-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 /* persistMessage*/);
-    }
-
-    private void sendTextMessageInternal(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.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
-                    destinationAddress,
-                    scAddress, text, sentIntent, deliveryIntent,
-                    persistMessage);
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Send a text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Requires Permission:
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
-     * privileges.
-     * </p>
-     *
-     * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
-     * @hide
-     */
-    @SystemApi
-    public void sendTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                false /* persistMessage */);
-    }
-
-    /**
-     * 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 /* persistMessage*/);
-    }
-
-    private void sendMultipartTextMessageInternal(
-            String destinationAddress, String scAddress, List<String> parts,
-            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
-            boolean persistMessage) {
-        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, persistMessage);
-            } 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>Requires Permission:
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
-     * privileges.
-     * </p>
-     *
-     * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
-     * @hide
-     **/
-    @SystemApi
-    public void sendMultipartTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, List<String> parts,
-            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
-        sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, false /* persistMessage*/);
-    }
-
-    /**
-     * 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 ba4deae..0000000
--- a/src/java/android/telephony/SmsMessage.java
+++ /dev/null
@@ -1,891 +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.hardware.radio.V1_0.CdmaSmsMessage;
-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(byte[] pdu) {
-        // received SMS in 3GPP format
-        SmsMessageBase wrappedMessage =
-                com.android.internal.telephony.gsm.SmsMessage.newFromCMT(pdu);
-
-        if (wrappedMessage != null) {
-            return new SmsMessage(wrappedMessage);
-        } else {
-            Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
-            return null;
-        }
-    }
-
-    /** @hide */
-    public static SmsMessage newCdmaSmsFromRil(CdmaSmsMessage msg) {
-        // received SMS in 3GPP2 format
-        SmsMessageBase wrappedMessage =
-                com.android.internal.telephony.cdma.SmsMessage.newFromRil(msg);
-
-        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/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index 8865901..5e09c35 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -71,6 +71,8 @@
     protected RegistrantList mPhoneRadioCapabilityChangedRegistrants =
             new RegistrantList();
     protected RegistrantList mPcoDataRegistrants = new RegistrantList();
+    protected RegistrantList mCarrierInfoForImsiEncryptionRegistrants = new RegistrantList();
+    protected RegistrantList mRilNetworkScanResultRegistrants = new RegistrantList();
 
 
     protected Registrant mGsmSmsRegistrant;
@@ -729,6 +731,17 @@
         mHardwareConfigChangeRegistrants.remove(h);
     }
 
+    @Override
+    public void registerForNetworkScanResult(Handler h, int what, Object obj) {
+        Registrant r = new Registrant(h, what, obj);
+        mRilNetworkScanResultRegistrants.add(r);
+    }
+
+    @Override
+    public void unregisterForNetworkScanResult(Handler h) {
+        mRilNetworkScanResultRegistrants.remove(h);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -905,4 +918,14 @@
     public void unregisterForPcoData(Handler h) {
         mPcoDataRegistrants.remove(h);
     }
+
+    @Override
+    public void registerForCarrierInfoForImsiEncryption(Handler h, int what, Object obj) {
+        mCarrierInfoForImsiEncryptionRegistrants.add(new Registrant(h, what, obj));
+    }
+
+    @Override
+    public void unregisterForCarrierInfoForImsiEncryption(Handler h) {
+        mCarrierInfoForImsiEncryptionRegistrants.remove(h);
+    }
 }
diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java
index cac701a..8429146 100644
--- a/src/java/com/android/internal/telephony/CallStateException.java
+++ b/src/java/com/android/internal/telephony/CallStateException.java
@@ -26,7 +26,7 @@
     /** The error code is not valid (Not received a disconnect cause) */
     public static final int ERROR_INVALID = -1;
 
-    public static final int ERROR_DISCONNECTED = 1;
+    public static final int ERROR_OUT_OF_SERVICE = 1;
     public static final int ERROR_POWER_OFF = 2;
 
     public
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
index be30739..6d2daf0 100644
--- a/src/java/com/android/internal/telephony/CarrierActionAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -19,15 +19,18 @@
 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;
@@ -65,25 +68,46 @@
     /** 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 (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(
-                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) {
+                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");
     }
 
@@ -109,6 +133,9 @@
                 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);
@@ -196,6 +223,11 @@
         list.remove(h);
     }
 
+    @VisibleForTesting
+    public ContentObserver getContentObserver() {
+        return mSettingsObserver;
+    }
+
     private void log(String s) {
         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
     }
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index 0605cbe..4d6d464 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -88,9 +88,10 @@
      * This is a list of supported signals from CarrierSignalAgent
      */
     private final Set<String> mCarrierSignalList = new HashSet<>(Arrays.asList(
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE.toLowerCase(),
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED.toLowerCase(),
-            TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED.toLowerCase()));
+            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);
 
@@ -99,6 +100,12 @@
             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();
             }
         }
@@ -163,7 +170,6 @@
                         }
                         String[] signals = splitStr[1].split(CARRIER_SIGNAL_DELIMITER);
                         for (String s : signals) {
-                            s = s.toLowerCase();
                             if (!mCarrierSignalList.contains(s)) {
                                 loge("Invalid signal name: " + s);
                                 continue;
@@ -191,8 +197,8 @@
      * Check if there are registered carrier broadcast receivers to handle the passing intent
      */
     public boolean hasRegisteredReceivers(String action) {
-        return mCachedWakeSignalConfigs.containsKey(action.toLowerCase())
-                || mCachedNoWakeSignalConfigs.containsKey(action.toLowerCase());
+        return mCachedWakeSignalConfigs.containsKey(action)
+                || mCachedNoWakeSignalConfigs.containsKey(action);
     }
 
     /**
@@ -254,14 +260,14 @@
         List<ComponentName> receiverList;
 
         synchronized (mCachedWakeSignalConfigs) {
-            receiverList = mCachedWakeSignalConfigs.get(intent.getAction().toLowerCase());
+            receiverList = mCachedWakeSignalConfigs.get(intent.getAction());
             if (!ArrayUtils.isEmpty(receiverList)) {
                 broadcast(intent, receiverList, WAKE);
             }
         }
 
         synchronized (mCachedNoWakeSignalConfigs) {
-            receiverList = mCachedNoWakeSignalConfigs.get(intent.getAction().toLowerCase());
+            receiverList = mCachedNoWakeSignalConfigs.get(intent.getAction());
             if (!ArrayUtils.isEmpty(receiverList)) {
                 broadcast(intent, receiverList, NO_WAKE);
             }
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 106ec54..a5e4c7b 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -27,6 +27,7 @@
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 import com.android.internal.telephony.uicc.IccCardStatus;
 
+import java.security.PublicKey;
 import java.util.List;
 
 /**
@@ -1283,12 +1284,29 @@
     /**
      * Queries the currently available networks
      *
-     * ((AsyncResult)response.obj).result  is a List of NetworkInfo objects
+     * ((AsyncResult)response.obj).result is a List of NetworkInfo objects
      */
     void getAvailableNetworks(Message response);
 
-    void getBasebandVersion (Message response);
+    /**
+     * Starts a radio network scan
+     *
+     * ((AsyncResult)response.obj).result is a NetworkScanResult object
+     */
+    void startNetworkScan(Message response);
 
+    /**
+     * Stops the ongoing network scan
+     *
+     * ((AsyncResult)response.obj).result is a NetworkScanResult object
+     *
+     */
+    void stopNetworkScan(Message response);
+
+    /**
+     * Gets the baseband version
+     */
+    void getBasebandVersion(Message response);
 
     /**
      * (AsyncResult)response.obj).result will be an Integer representing
@@ -1433,6 +1451,18 @@
 
     void invokeOemRilRequestRaw(byte[] data, Message response);
 
+    /**
+     * Sends carrier specific information to the vendor ril that can be used to
+     * encrypt the IMSI and IMPI.
+     *
+     * @param publicKey the public key of the carrier used to encrypt IMSI/IMPI.
+     * @param keyIdentifier the key identifier is optional information that is carrier
+     *        specific.
+     * @param response callback message
+     */
+    void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+                                         Message response);
+
     void invokeOemRilRequestStrings(String[] strings, Message response);
 
     /**
@@ -2065,10 +2095,45 @@
     /**
      * Set SIM card power up or down
      *
-     * @param powerUp True if powering up the sim card
+     * @param state  State of SIM (power down, power up, pass through)
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_DOWN}
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_UP}
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_UP_PASS_THROUGH}
      * @param result callback message contains the information of SUCCESS/FAILURE
      */
-    void setSimCardPower(boolean powerUp, Message result);
+    void setSimCardPower(int state, Message result);
+
+    /**
+     * Register for unsolicited Carrier Public Key.
+     *
+     * @param h Handler for notificaiton message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForCarrierInfoForImsiEncryption(Handler h, int what, Object obj);
+
+    /**
+     * DeRegister for unsolicited Carrier Public Key.
+     *
+     * @param h Handler for notificaiton message.
+     */
+    void unregisterForCarrierInfoForImsiEncryption(Handler h);
+
+    /**
+     * Register for unsolicited Network Scan result.
+     *
+     * @param h Handler for notificaiton message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    void registerForNetworkScanResult(Handler h, int what, Object obj);
+
+    /**
+     * DeRegister for unsolicited Network Scan result.
+     *
+     * @param h Handler for notificaiton message.
+     */
+    void unregisterForNetworkScanResult(Handler h);
 
     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 8a77465..dc53172 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -101,6 +101,8 @@
         public void onCallPullFailed(Connection externalConnection);
         public void onHandoverToWifiFailed();
         public void onConnectionEvent(String event, Bundle extras);
+        public void onRttModifyRequestReceived();
+        public void onRttModifyResponseReceived(int status);
     }
 
     /**
@@ -136,6 +138,10 @@
         public void onHandoverToWifiFailed() {}
         @Override
         public void onConnectionEvent(String event, Bundle extras) {}
+        @Override
+        public void onRttModifyRequestReceived() {}
+        @Override
+        public void onRttModifyResponseReceived(int status) {}
     }
 
     public static final int AUDIO_QUALITY_STANDARD = 1;
@@ -627,6 +633,7 @@
         mOrigConnection = c.getOrigConnection();
         mPostDialString = c.mPostDialString;
         mNextPostDialChar = c.mNextPostDialChar;
+        mPostDialState = c.mPostDialState;
     }
 
     /**
@@ -1006,6 +1013,18 @@
     public void pullExternalCall() {
     }
 
+    public void onRttModifyRequestReceived() {
+        for (Listener l : mListeners) {
+            l.onRttModifyRequestReceived();
+        }
+    }
+
+    public void onRttModifyResponseReceived(int status) {
+        for (Listener l : mListeners) {
+            l.onRttModifyResponseReceived(status);
+        }
+    }
+
     /**
      *
      */
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index d11a5c6..504bf1d 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -22,12 +22,14 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.CellInfo;
+import android.telephony.PreciseCallState;
 import android.telephony.Rlog;
-import android.telephony.VoLteServiceState;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.telephony.PreciseCallState;
+import android.telephony.VoLteServiceState;
+
+import com.android.internal.telephony.PhoneConstantConversions;
 
 import java.util.List;
 
@@ -57,7 +59,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
@@ -175,15 +178,14 @@
         try {
             if (mRegistry != null) {
                 mRegistry.notifyDataConnectionForSubscriber(subId,
-                    convertDataState(state),
-                    sender.isDataConnectivityPossible(apnType), reason,
-                    sender.getActiveApnHost(apnType),
-                    apnType,
-                    linkProperties,
-                    networkCapabilities,
-                    ((telephony!=null) ? telephony.getDataNetworkType(subId) :
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN),
-                    roaming);
+                    PhoneConstantConversions.convertDataState(state),
+                        sender.isDataAllowed(), reason,
+                        sender.getActiveApnHost(apnType),
+                        apnType,
+                        linkProperties,
+                        networkCapabilities,
+                        ((telephony != null) ? telephony.getDataNetworkType(subId) :
+                                TelephonyManager.NETWORK_TYPE_UNKNOWN), roaming);
             }
         } catch (RemoteException ex) {
             // system process is dead
@@ -316,70 +318,6 @@
     }
 
     /**
-     * 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;
-        }
-    }
-
-    /**
-     * 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;
-        }
-    }
-
-    /**
      * Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
      * for the public API.
      */
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 8de24e4..27cbd77 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -45,6 +45,7 @@
 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;
@@ -60,6 +61,7 @@
 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.util.Log;
@@ -128,6 +130,7 @@
     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
@@ -1125,6 +1128,18 @@
                 CallStateException.ERROR_POWER_OFF,
                 "cannot dial voice call in airplane mode");
         }
+        // Check for service before placing non emergency CS voice call.
+        // Allow dial only if either CS is camped on any RAT (or) PS is in LTE service.
+        if (mSST != null
+                && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
+                && !(mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
+                    && ServiceState.isLte(mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE */
+                && !VideoProfile.isVideo(videoState) /* voice call */
+                && !isEmergency /* non-emergency call */) {
+            throw new CallStateException(
+                CallStateException.ERROR_OUT_OF_SERVICE,
+                "cannot dial voice call in out of service");
+        }
         if (DBG) logd("Trying (non-IMS) CS call");
 
         if (isPhoneTypeGsm()) {
@@ -1174,6 +1189,12 @@
     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);
@@ -1186,8 +1207,8 @@
 
             // Only look at the Network portion for mmi
             String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
-            GsmMmiCode mmi =
-                    GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
+            GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
+                                                          mUiccApplication.get(), wrappedCallback);
             if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
 
             if (mmi == null) {
@@ -1236,6 +1257,17 @@
     }
 
     @Override
+    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
+        try {
+            dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
+            return true;
+         } catch (Exception e) {
+           logd("exception" + e);
+           return false;
+         }
+    }
+
+    @Override
     public void sendUssdResponse(String ussdMessge) {
         if (isPhoneTypeGsm()) {
             GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
@@ -1747,6 +1779,16 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+        mCi.startNetworkScan(response);
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+        mCi.stopNetworkScan(response);
+    }
+
+    @Override
     public void getNeighboringCids(Message response, WorkSource workSource) {
         if (isPhoneTypeGsm()) {
             mCi.getNeighboringCids(response, workSource);
@@ -1807,12 +1849,12 @@
 
     @Override
     public boolean getDataRoamingEnabled() {
-        return mDcTracker.getDataOnRoamingEnabled();
+        return mDcTracker.getDataRoamingEnabled();
     }
 
     @Override
     public void setDataRoamingEnabled(boolean enable) {
-        mDcTracker.setDataOnRoamingEnabled(enable);
+        mDcTracker.setDataRoamingEnabled(enable);
     }
 
     @Override
@@ -1877,9 +1919,21 @@
          * The exception is cancellation of an incoming USSD-REQUEST, which is
          * not on the list.
          */
+        logd("USSD Response:" + mmi);
         if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
                 ((GsmMmiCode)mmi).isSsInfo()))) {
-            mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+
+            ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
+            if (receiverCallback != null) {
+                UssdResponse response = new UssdResponse(mmi.getDialString(), mmi.getMessage());
+                Bundle returnData = new Bundle();
+                returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+                int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
+                    TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
+                receiverCallback.send(returnCode, returnData);
+            } else {
+                mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+            }
         }
     }
 
@@ -2604,7 +2658,7 @@
         if (isPhoneTypeGsm()) {
             return false;
         } else {
-            return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
+            return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 11225fc..0fc08c6 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -604,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
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/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 0b7fd44..8f2f048 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -59,7 +59,6 @@
 import com.android.internal.R;
 import com.android.internal.telephony.dataconnection.DcTracker;
 import com.android.internal.telephony.imsphone.ImsPhoneCall;
-import com.android.internal.telephony.ims.ImsResolver;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
 import com.android.internal.telephony.uicc.IccFileHandler;
@@ -534,15 +533,18 @@
 
         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). Also, when using new ImsResolver APIs, the service will be available soon,
             // so start trying to bind.
-            ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
             if (imsManager != null) {
                 // If it is dynamic binding, kick off ImsPhone creation now instead of waiting for
                 // the service to be available.
@@ -1822,6 +1824,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
@@ -2721,20 +2732,11 @@
     /**
      * Report on whether data connectivity is allowed.
      */
-    public boolean isDataConnectivityPossible() {
-        return isDataConnectivityPossible(PhoneConstants.APN_TYPE_DEFAULT);
+    public boolean isDataAllowed() {
+        return ((mDcTracker != null) && (mDcTracker.isDataAllowed(null)));
     }
 
     /**
-     * Report on whether data connectivity is allowed for an APN.
-     */
-    public boolean isDataConnectivityPossible(String apnType) {
-        return ((mDcTracker != null) &&
-                (mDcTracker.isDataPossible(apnType)));
-    }
-
-
-    /**
      * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
      */
     public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
@@ -3375,7 +3377,7 @@
                             ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY));
             if (wfcWiFiOnly) {
                 throw new CallStateException(
-                        CallStateException.ERROR_DISCONNECTED,
+                        CallStateException.ERROR_OUT_OF_SERVICE,
                         "WFC Wi-Fi Only Mode: IMS not registered");
             }
         }
@@ -3433,11 +3435,14 @@
     }
 
     /**
-     * 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
+     * Set SIM card power state.
+     * @param state State of SIM (power down, power up, pass through)
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_DOWN}
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_UP}
+     * - {@link android.telephony.TelephonyManager#CARD_POWER_UP_PASS_THROUGH}
      **/
-    public void setSimPowerState(boolean powerUp) {
-        mCi.setSimCardPower(powerUp, null);
+    public void setSimPowerState(int state) {
+        mCi.setSimCardPower(state, null);
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -3474,7 +3479,6 @@
         pw.println(" getPhoneType()=" + getPhoneType());
         pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount());
         pw.println(" getActiveApnTypes()=" + getActiveApnTypes());
-        pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible());
         pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning());
         pw.flush();
         pw.println("++++++++++++++++++++++++++++++++");
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index d0f3dbb..849cf99 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -16,31 +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.os.ResultReceiver;
 import android.os.WorkSource;
-import android.telephony.CellInfo;
-import android.telephony.CellLocation;
 import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
+import android.telephony.CellLocation;
 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
@@ -450,6 +437,14 @@
     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);
+
+    /**
      * 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.
@@ -648,6 +643,30 @@
     void getAvailableNetworks(Message response);
 
     /**
+     * Start a network scan. This method is asynchronous; .
+     * On completion, <code>response.obj</code> is set to an AsyncResult with
+     * one of the following members:.<p>
+     * <ul>
+     * <li><code>response.obj.result</code> will be a <code>NetworkScanResult</code> object, or</li>
+     * <li><code>response.obj.exception</code> will be set with an exception
+     * on failure.</li>
+     * </ul>
+     */
+    void startNetworkScan(Message response);
+
+    /**
+     * Stop ongoing network scan. This method is asynchronous; .
+     * On completion, <code>response.obj</code> is set to an AsyncResult with
+     * one of the following members:.<p>
+     * <ul>
+     * <li><code>response.obj.result</code> will be a <code>NetworkScanResult</code> object, or</li>
+     * <li><code>response.obj.exception</code> will be set with an exception
+     * on failure.</li>
+     * </ul>
+     */
+    void stopNetworkScan(Message response);
+
+    /**
      * Query neighboring cell IDs.  <code>response</code> is dispatched when
      * this is complete.  <code>response.obj</code> will be an AsyncResult,
      * and <code>response.obj.exception</code> will be non-null on failure.
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index d9411b4..ee0f31d 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -69,13 +69,18 @@
 import android.telephony.ClientRequestStats;
 import android.telephony.ModemActivityInfo;
 import android.telephony.NeighboringCellInfo;
+import android.telephony.NetworkScanRequest;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.RadioAccessFamily;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
 import android.telephony.Rlog;
 import android.telephony.SignalStrength;
 import android.telephony.SmsManager;
 import android.telephony.TelephonyHistogram;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.telephony.TelephonyProto.SmsSession;
@@ -92,6 +97,7 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.security.PublicKey;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -1772,6 +1778,98 @@
     }
 
     @Override
+    public void startNetworkScan(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            android.hardware.radio.V1_1.IRadio radioProxy11 =
+                    android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+            if (radioProxy11 == null) {
+                if (result != null) {
+                    AsyncResult.forMessage(result, null,
+                            CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                    result.sendToTarget();
+                }
+            } else {
+                NetworkScanRequest nsr = (NetworkScanRequest) result.obj;
+                android.hardware.radio.V1_1.NetworkScanRequest request =
+                        new android.hardware.radio.V1_1.NetworkScanRequest();
+                request.type = nsr.scanType;
+                request.interval = 60;
+                for (RadioAccessSpecifier ras : nsr.specifiers) {
+                    android.hardware.radio.V1_1.RadioAccessSpecifier s =
+                            new android.hardware.radio.V1_1.RadioAccessSpecifier();
+                    s.radioAccessNetwork = ras.radioAccessNetwork;
+                    List<Integer> bands = null;
+                    switch (ras.radioAccessNetwork) {
+                        case RadioAccessNetworks.GERAN:
+                            bands = s.geranBands;
+                            break;
+                        case RadioAccessNetworks.UTRAN:
+                            bands = s.utranBands;
+                            break;
+                        case RadioAccessNetworks.EUTRAN:
+                            bands = s.eutranBands;
+                            break;
+                        default:
+                            Log.wtf(RILJ_LOG_TAG, "radioAccessNetwork " + ras.radioAccessNetwork
+                                    + " not supported!");
+                            return;
+                    }
+                    for (int band : ras.bands) {
+                        bands.add(band);
+                    }
+                    for (int channel : ras.channels) {
+                        s.channels.add(channel);
+                    }
+                    request.specifiers.add(s);
+                }
+
+                RILRequest rr = obtainRequest(RIL_REQUEST_START_NETWORK_SCAN, result,
+                        mRILDefaultWorkSource);
+
+                if (RILJ_LOGD) {
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+                }
+
+                try {
+                    radioProxy11.startNetworkScan(rr.mSerial, request);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "startNetworkScan", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void stopNetworkScan(Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            android.hardware.radio.V1_1.IRadio radioProxy11 =
+                    android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+            if (radioProxy11 == null) {
+                if (result != null) {
+                    AsyncResult.forMessage(result, null,
+                            CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                    result.sendToTarget();
+                }
+            } else {
+                RILRequest rr = obtainRequest(RIL_REQUEST_STOP_NETWORK_SCAN, result,
+                        mRILDefaultWorkSource);
+
+                if (RILJ_LOGD) {
+                    riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+                }
+
+                try {
+                    radioProxy11.stopNetworkScan(rr.mSerial);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "stopNetworkScan", e);
+                }
+            }
+        }
+    }
+
+    @Override
     public void startDtmf(char c, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
@@ -3498,7 +3596,7 @@
                 for (int i = 0; i < carriers.size(); i++) {
                     logStr = logStr + carriers.get(i) + " ";
                 }
-                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + "carriers = "
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " carriers = "
                         + logStr);
             }
 
@@ -3604,20 +3702,73 @@
     }
 
     @Override
-    public void setSimCardPower(boolean powerUp, Message result) {
+    public void setSimCardPower(int state, Message result) {
         IRadio radioProxy = getRadioProxy(result);
         if (radioProxy != null) {
             RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIM_CARD_POWER, result,
                     mRILDefaultWorkSource);
 
             if (RILJ_LOGD) {
-                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + powerUp);
+                riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + state);
             }
+            android.hardware.radio.V1_1.IRadio radioProxy11 =
+                    android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+            if (radioProxy11 == null) {
+                try {
+                    switch (state) {
+                        case TelephonyManager.CARD_POWER_DOWN: {
+                            radioProxy.setSimCardPower(rr.mSerial, false);
+                            break;
+                        }
+                        case TelephonyManager.CARD_POWER_UP: {
+                            radioProxy.setSimCardPower(rr.mSerial, true);
+                            break;
+                        }
+                        default: {
+                            if (result != null) {
+                                AsyncResult.forMessage(result, null,
+                                        CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                                result.sendToTarget();
+                            }
+                        }
+                    }
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+                }
+            } else {
+                try {
+                    radioProxy11.setSimCardPower_1_1(rr.mSerial, state);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+                }
+            }
+        }
+    }
 
-            try {
-                radioProxy.setSimCardPower(rr.mSerial, powerUp);
-            } catch (RemoteException | RuntimeException e) {
-                handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+    @Override
+    public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+                                                Message result) {
+        IRadio radioProxy = getRadioProxy(result);
+        if (radioProxy != null) {
+            android.hardware.radio.V1_1.IRadio radioProxy11 =
+                    android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+            if (radioProxy11 == null) {
+                if (result != null) {
+                    AsyncResult.forMessage(result, null,
+                            CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+                    result.sendToTarget();
+                }
+            } else {
+                RILRequest rr = obtainRequest(RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, result,
+                        mRILDefaultWorkSource);
+                if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+                try {
+                    radioProxy11.setCarrierInfoForImsiEncryption(
+                            rr.mSerial, publicKeyToArrayList(publicKey), keyIdentifier);
+                } catch (RemoteException | RuntimeException e) {
+                    handleRadioProxyExceptionForRR(rr, "setCarrierInfoForImsiEncryption", e);
+                }
             }
         }
     }
@@ -4180,6 +4331,9 @@
         mMetrics.writeRilSrvcc(mPhoneId, state);
     }
 
+    void writeMetricsModemRestartEvent(String reason) {
+        mMetrics.writeModemRestartEvent(mPhoneId, reason);
+    }
 
     /**
      * Notify all registrants that the ril has connected or disconnected.
@@ -4523,6 +4677,8 @@
                 return "RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER";
             case RIL_RESPONSE_ACKNOWLEDGEMENT:
                 return "RIL_RESPONSE_ACKNOWLEDGEMENT";
+            case RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION:
+                return "RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION";
             default: return "<unknown request>";
         }
     }
@@ -4621,6 +4777,10 @@
                 return "UNSOL_LCE_INFO_RECV";
             case RIL_UNSOL_PCO_DATA:
                 return "UNSOL_PCO_DATA";
+            case RIL_UNSOL_MODEM_RESTART:
+                return "UNSOL_MODEM_RESTART";
+            case RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION:
+                return "RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION";
             default:
                 return "<unknown response>";
         }
@@ -4709,6 +4869,19 @@
         return arrayList;
     }
 
+    /**
+     * Method to serialize the Public Key into ArrayList of bytes
+     * @param publicKey publicKey to be converted to ArrayList of bytes.
+     **/
+    public static ArrayList<Byte> publicKeyToArrayList(PublicKey publicKey) {
+        byte[] key = publicKey.getEncoded();
+        ArrayList<Byte> arrayList = new ArrayList<>(key.length);
+        for (byte b : key) {
+            arrayList.add(b);
+        }
+        return arrayList;
+    }
+
     public static byte[] arrayListToPrimitiveArray(ArrayList<Byte> bytes) {
         byte[] ret = new byte[bytes.size()];
         for (int i = 0; i < ret.length; i++) {
@@ -4811,7 +4984,7 @@
                     p.writeInt(cellInfoGsm.cellIdentityGsm.lac);
                     p.writeInt(cellInfoGsm.cellIdentityGsm.cid);
                     p.writeInt(cellInfoGsm.cellIdentityGsm.arfcn);
-                    p.writeInt(cellInfoGsm.cellIdentityGsm.bsic);
+                    p.writeInt(Byte.toUnsignedInt(cellInfoGsm.cellIdentityGsm.bsic));
                     p.writeInt(cellInfoGsm.signalStrengthGsm.signalStrength);
                     p.writeInt(cellInfoGsm.signalStrengthGsm.bitErrorRate);
                     p.writeInt(cellInfoGsm.signalStrengthGsm.timingAdvance);
@@ -4893,5 +5066,4 @@
                 signalStrength.tdScdma.rscp,
                 false /* gsmFlag - don't care; will be changed by SST */);
     }
-
 }
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 00abe2d..8c09b4b 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -16,42 +16,8 @@
 
 package com.android.internal.telephony;
 
-import android.hardware.radio.V1_0.CdmaCallWaiting;
-import android.hardware.radio.V1_0.CdmaInformationRecord;
-import android.hardware.radio.V1_0.CdmaLineControlInfoRecord;
-import android.hardware.radio.V1_0.CdmaNumberInfoRecord;
-import android.hardware.radio.V1_0.CdmaRedirectingNumberInfoRecord;
-import android.hardware.radio.V1_0.CdmaSignalInfoRecord;
-import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.hardware.radio.V1_0.CdmaT53AudioControlInfoRecord;
-import android.hardware.radio.V1_0.CfData;
-import android.hardware.radio.V1_0.IRadioIndication;
-import android.hardware.radio.V1_0.LceDataInfo;
-import android.hardware.radio.V1_0.PcoDataInfo;
-import android.hardware.radio.V1_0.SetupDataCallResult;
-import android.hardware.radio.V1_0.SimRefreshResult;
-import android.hardware.radio.V1_0.SsInfoData;
-import android.hardware.radio.V1_0.StkCcUnsolSsResult;
-import android.hardware.radio.V1_0.SuppSvcNotification;
-import android.os.AsyncResult;
-import android.os.SystemProperties;
-import android.telephony.CellInfo;
-import android.telephony.PcoData;
-import android.telephony.SignalStrength;
-import android.telephony.SmsMessage;
-
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
-import com.android.internal.telephony.cdma.CdmaInformationRecords;
-import com.android.internal.telephony.dataconnection.DataCallResponse;
-import com.android.internal.telephony.gsm.SsData;
-import com.android.internal.telephony.gsm.SuppServiceNotification;
-import com.android.internal.telephony.uicc.IccRefreshResponse;
-import com.android.internal.telephony.uicc.IccUtils;
-
-import java.util.ArrayList;
-
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_CALL_WAITING;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_INFO_REC;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_OTA_PROVISION_STATUS;
@@ -63,6 +29,8 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD;
@@ -96,6 +64,42 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOl_CDMA_PRL_CHANGED;
 
+import android.hardware.radio.V1_0.CdmaCallWaiting;
+import android.hardware.radio.V1_0.CdmaInformationRecord;
+import android.hardware.radio.V1_0.CdmaLineControlInfoRecord;
+import android.hardware.radio.V1_0.CdmaNumberInfoRecord;
+import android.hardware.radio.V1_0.CdmaRedirectingNumberInfoRecord;
+import android.hardware.radio.V1_0.CdmaSignalInfoRecord;
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.hardware.radio.V1_0.CdmaT53AudioControlInfoRecord;
+import android.hardware.radio.V1_0.CfData;
+import android.hardware.radio.V1_0.LceDataInfo;
+import android.hardware.radio.V1_0.PcoDataInfo;
+import android.hardware.radio.V1_0.SetupDataCallResult;
+import android.hardware.radio.V1_0.SimRefreshResult;
+import android.hardware.radio.V1_0.SsInfoData;
+import android.hardware.radio.V1_0.StkCcUnsolSsResult;
+import android.hardware.radio.V1_0.SuppSvcNotification;
+import android.hardware.radio.V1_1.IRadioIndication;
+import android.os.AsyncResult;
+import android.os.SystemProperties;
+import android.telephony.CellInfo;
+import android.telephony.PcoData;
+import android.telephony.SignalStrength;
+import android.telephony.SmsMessage;
+
+import com.android.internal.telephony.TelephonyProto.SmsSession;
+import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
+import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.cdma.SmsMessageConverter;
+import com.android.internal.telephony.dataconnection.DataCallResponse;
+import com.android.internal.telephony.gsm.SsData;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.uicc.IccRefreshResponse;
+import com.android.internal.telephony.uicc.IccUtils;
+
+import java.util.ArrayList;
+
 public class RadioIndication extends IRadioIndication.Stub {
     RIL mRil;
 
@@ -364,7 +368,7 @@
 
         // todo: conversion from CdmaSmsMessage to SmsMessage should be contained in this class so
         // that usage of auto-generated HAL classes is limited to this file
-        SmsMessage sms = SmsMessage.newCdmaSmsFromRil(msg);
+        SmsMessage sms = SmsMessageConverter.newSmsMessageFromCdmaSmsMessage(msg);
         if (mRil.mCdmaSmsRegistrant != null) {
             mRil.mCdmaSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
         }
@@ -629,6 +633,12 @@
         mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult (null, response, null));
     }
 
+    /** Incremental network scan results */
+    public void networkScanResult(int indicationType,
+                                  android.hardware.radio.V1_1.NetworkScanResult result) {
+        responseCellInfos(indicationType, result);
+    }
+
     public void imsNetworkStateChanged(int indicationType) {
         mRil.processIndication(indicationType);
 
@@ -773,6 +783,23 @@
 
     public void modemReset(int indicationType, String reason) {
         mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason);
+
+        mRil.writeMetricsModemRestartEvent(reason);
+    }
+
+    /**
+     * Indicates when the carrier info to encrypt IMSI is being requested
+     * @param indicationType RadioIndicationType
+     */
+    public void carrierInfoForImsiEncryption(int indicationType) {
+        mRil.processIndication(indicationType);
+
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null);
+
+        mRil.mCarrierInfoForImsiEncryptionRegistrants.notifyRegistrants(
+                new AsyncResult(null, null, null));
     }
 
     private CommandsInterface.RadioState getRadioStateFromInt(int stateInt) {
@@ -793,4 +820,15 @@
         }
         return state;
     }
+
+    private void responseCellInfos(int indicationType,
+                                   android.hardware.radio.V1_1.NetworkScanResult result) {
+        mRil.processIndication(indicationType);
+
+        NetworkScanResult nsr = null;
+        ArrayList<CellInfo> infos = RIL.convertHalCellInfoList(result.networkInfos);
+        nsr = new NetworkScanResult(result.status, result.error, infos);
+        if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr);
+        mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
+    }
 }
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 8e3fa76..914a60a 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -24,7 +24,6 @@
 import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
 import android.hardware.radio.V1_0.DataRegStateResult;
 import android.hardware.radio.V1_0.GsmBroadcastSmsConfigInfo;
-import android.hardware.radio.V1_0.IRadioResponse;
 import android.hardware.radio.V1_0.LastCallFailCauseInfo;
 import android.hardware.radio.V1_0.LceDataInfo;
 import android.hardware.radio.V1_0.LceStatusInfo;
@@ -34,6 +33,7 @@
 import android.hardware.radio.V1_0.SendSmsResult;
 import android.hardware.radio.V1_0.SetupDataCallResult;
 import android.hardware.radio.V1_0.VoiceRegStateResult;
+import android.hardware.radio.V1_1.IRadioResponse;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemClock;
@@ -494,6 +494,22 @@
     }
 
     /**
+     *
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void startNetworkScanResponse(RadioResponseInfo responseInfo) {
+        responseScanStatus(responseInfo);
+    }
+
+    /**
+     *
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void stopNetworkScanResponse(RadioResponseInfo responseInfo) {
+        responseScanStatus(responseInfo);
+    }
+
+    /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
     public void startDtmfResponse(RadioResponseInfo responseInfo) {
@@ -1177,6 +1193,13 @@
     /**
      * @param responseInfo Response info struct containing response type, serial no. and error
      */
+    public void setCarrierInfoForImsiEncryptionResponse(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
     public void setIndicationFilterResponse(RadioResponseInfo responseInfo) {
         responseVoid(responseInfo);
     }
@@ -1188,6 +1211,13 @@
         responseVoid(responseInfo);
     }
 
+    /**
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     */
+    public void setSimCardPowerResponse_1_1(RadioResponseInfo responseInfo) {
+        responseVoid(responseInfo);
+    }
+
     private void responseIccCardStatus(RadioResponseInfo responseInfo, CardStatus cardStatus) {
         RILRequest rr = mRil.processResponse(responseInfo);
 
@@ -1517,6 +1547,16 @@
         }
     }
 
+    private void responseScanStatus(RadioResponseInfo responseInfo) {
+        RILRequest rr = mRil.processResponse(responseInfo);
+
+        if (rr != null) {
+            NetworkScanResult nsr = new NetworkScanResult(0, responseInfo.error, null);
+            sendMessageResponse(rr.mResult, nsr);
+            mRil.processResponseDone(rr, responseInfo, nsr);
+        }
+    }
+
     private void responseDataCallList(RadioResponseInfo responseInfo,
                                       ArrayList<SetupDataCallResult> dataCallResultList) {
         RILRequest rr = mRil.processResponse(responseInfo);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 4e27e3a..d5f6997 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -17,7 +17,7 @@
 package com.android.internal.telephony;
 
 import static android.provider.Telephony.ServiceStateTable.getContentValuesForServiceState;
-import static android.provider.Telephony.ServiceStateTable.getUriForSubId;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
 
 import static com.android.internal.telephony.CarrierActionAgent.CARRIER_ACTION_SET_RADIO_ENABLED;
 
@@ -128,16 +128,6 @@
     // TODO - this should not be public, right now used externally GsmConnetion.
     public RestrictedState mRestrictedState;
 
-    /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
-    static public final int OTASP_UNINITIALIZED = 0;
-    static public final int OTASP_UNKNOWN = 1;
-    static public final int OTASP_NEEDED = 2;
-    static public final int OTASP_NOT_NEEDED = 3;
-    /**
-     * OtaUtil has conflict enum 4: OtaUtils.OTASP_FAILURE_SPC_RETRIES
-     */
-    static public final int OTASP_SIM_UNPROVISIONED = 5;
-
     /**
      * A unique identifier to track requests associated with a poll
      * and ignore stale responses.  The value is a count-down of
@@ -491,7 +481,7 @@
     public static final String UNACTIVATED_MIN2_VALUE = "000000";
     public static final String UNACTIVATED_MIN_VALUE = "1111110111";
     // Current Otasp value
-    private int mCurrentOtaspMode = OTASP_UNINITIALIZED;
+    private int mCurrentOtaspMode = TelephonyManager.OTASP_UNINITIALIZED;
     /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
     public static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
     private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
@@ -594,7 +584,7 @@
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         context.registerReceiver(mIntentReceiver, filter);
 
-        mPhone.notifyOtaspChanged(OTASP_UNINITIALIZED);
+        mPhone.notifyOtaspChanged(TelephonyManager.OTASP_UNINITIALIZED);
 
         updatePhoneType();
 
@@ -612,6 +602,23 @@
 
     @VisibleForTesting
     public void updatePhoneType() {
+        // If we are previously voice roaming, we need to notify that roaming status changed before
+        // we change back to non-roaming.
+        if (mSS != null && mSS.getVoiceRoaming()) {
+            mVoiceRoamingOffRegistrants.notifyRegistrants();
+        }
+
+        // If we are previously data roaming, we need to notify that roaming status changed before
+        // we change back to non-roaming.
+        if (mSS != null && mSS.getDataRoaming()) {
+            mDataRoamingOffRegistrants.notifyRegistrants();
+        }
+
+        // If we are previously in service, we need to notify that we are out of service now.
+        if (mSS != null && mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
+            mDetachedRegistrants.notifyRegistrants();
+        }
+
         mSS = new ServiceState();
         mNewSS = new ServiceState();
         mLastCellInfoListTime = 0;
@@ -683,11 +690,7 @@
 
         logPhoneTypeChange();
 
-        // Tell everybody that we've thrown away state and are starting over with
-        // empty, detached ServiceStates.
-        mVoiceRoamingOffRegistrants.notifyRegistrants();
-        mDataRoamingOffRegistrants.notifyRegistrants();
-        mDetachedRegistrants.notifyRegistrants();
+        // Tell everybody that the registration state and RAT have changed.
         notifyDataRegStateRilRadioTechnologyChanged();
     }
 
@@ -1541,27 +1544,27 @@
         // if sim is not loaded, return otasp uninitialized
         if(!mPhone.getIccRecordsLoaded()) {
             if(DBG) log("getOtasp: otasp uninitialized due to sim not loaded");
-            return OTASP_UNINITIALIZED;
+            return TelephonyManager.OTASP_UNINITIALIZED;
         }
         // if voice tech is Gsm, return otasp not needed
         if(mPhone.isPhoneTypeGsm()) {
             if(DBG) log("getOtasp: otasp not needed for GSM");
-            return OTASP_NOT_NEEDED;
+            return TelephonyManager.OTASP_NOT_NEEDED;
         }
         // for ruim, min is null means require otasp.
         if (mIsSubscriptionFromRuim && mMin == null) {
-            return OTASP_NEEDED;
+            return TelephonyManager.OTASP_NEEDED;
         }
         if (mMin == null || (mMin.length() < 6)) {
             if (DBG) log("getOtasp: bad mMin='" + mMin + "'");
-            provisioningState = OTASP_UNKNOWN;
+            provisioningState = TelephonyManager.OTASP_UNKNOWN;
         } else {
             if ((mMin.equals(UNACTIVATED_MIN_VALUE)
                     || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
                     || SystemProperties.getBoolean("test_cdma_setup", false)) {
-                provisioningState = OTASP_NEEDED;
+                provisioningState = TelephonyManager.OTASP_NEEDED;
             } else {
-                provisioningState = OTASP_NOT_NEEDED;
+                provisioningState = TelephonyManager.OTASP_NOT_NEEDED;
             }
         }
         if (DBG) log("getOtasp: state=" + provisioningState);
@@ -1657,12 +1660,27 @@
                 if (mIsSubscriptionFromRuim) {
                     mNewSS.setVoiceRoaming(isRoamingBetweenOperators(mNewSS.getVoiceRoaming(), mNewSS));
                 }
-                // For CDMA, voice and data should have the same roaming status
-                final boolean isVoiceInService =
-                        (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
-                final int dataRegType = mNewSS.getRilDataRadioTechnology();
-                if (isVoiceInService && ServiceState.isCdma(dataRegType)) {
-                    mNewSS.setDataRoaming(mNewSS.getVoiceRoaming());
+                /**
+                 * For CDMA, voice and data should have the same roaming status.
+                 * If voice is not in service, use TSB58 roaming indicator to set
+                 * data roaming status. If TSB58 roaming indicator is not in the
+                 * carrier-specified list of ERIs for home system then set roaming.
+                 */
+                final int dataRat = mNewSS.getRilDataRadioTechnology();
+                if (ServiceState.isCdma(dataRat)) {
+                    final boolean isVoiceInService =
+                            (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+                    if (isVoiceInService) {
+                        mNewSS.setDataRoaming(mNewSS.getVoiceRoaming());
+                    } else {
+                        /**
+                         * As per VoiceRegStateResult from radio types.hal the TSB58
+                         * Roaming Indicator shall be sent if device is registered
+                         * on a CDMA or EVDO system.
+                         */
+                        mNewSS.setDataRoaming(
+                                !isRoamIndForHomeSystem(Integer.toString(mRoamingIndicator)));
+                    }
                 }
 
                 // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
@@ -2542,11 +2560,11 @@
                 setSignalStrengthDefaultValues();
                 mGotCountryCode = false;
                 mNitzUpdatedTime = false;
-                // don't poll for state when the radio is off
-                // EXCEPT, if the poll was modemTrigged (they sent us new radio data)
-                // or we're on IWLAN
-                if (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
-                        != mSS.getRilDataRadioTechnology()) {
+                // don't poll when device is shutting down or the poll was not modemTrigged
+                // (they sent us new radio data) and current network is not IWLAN
+                if (mDeviceShuttingDown ||
+                        (!modemTriggered && ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                        != mSS.getRilDataRadioTechnology())) {
                     pollStateDone();
                     break;
                 }
@@ -2859,8 +2877,9 @@
             mPhone.notifyServiceStateChanged(mSS);
 
             // insert into ServiceStateProvider. This will trigger apps to wake through JobScheduler
-            mPhone.getContext().getContentResolver().insert(getUriForSubId(mPhone.getSubId()),
-                    getContentValuesForServiceState(mSS));
+            mPhone.getContext().getContentResolver()
+                    .insert(getUriForSubscriptionId(mPhone.getSubId()),
+                            getContentValuesForServiceState(mSS));
 
             TelephonyMetrics.getInstance().writeServiceStateChanged(mPhone.getPhoneId(), mSS);
         }
@@ -4293,10 +4312,15 @@
      */
     protected boolean onSignalStrengthResult(AsyncResult ar) {
         boolean isGsm = false;
-        //override isGsm for CDMA LTE
-        if (mPhone.isPhoneTypeGsm() ||
-                (mPhone.isPhoneTypeCdmaLte() &&
-                        ServiceState.isLte(mSS.getRilDataRadioTechnology()))) {
+        int dataRat = mSS.getRilDataRadioTechnology();
+        int voiceRat = mSS.getRilVoiceRadioTechnology();
+
+        // Override isGsm based on currently camped data and voice RATs
+        // Set isGsm to true if the RAT belongs to GSM family and not IWLAN
+        if ((dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                && ServiceState.isGsm(dataRat))
+                || (voiceRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                && ServiceState.isGsm(voiceRat))) {
             isGsm = true;
         }
 
diff --git a/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
deleted file mode 100644
index 439eaea..0000000
--- a/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import android.telephony.Rlog;
-import android.os.Build;
-import android.util.SparseIntArray;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.telephony.SmsManager;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.XmlUtils;
-import com.android.internal.telephony.cdma.sms.UserData;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-public class Sms7BitEncodingTranslator {
-    private static final String TAG = "Sms7BitEncodingTranslator";
-    private static final boolean DBG = Build.IS_DEBUGGABLE ;
-    private static boolean mIs7BitTranslationTableLoaded = false;
-    private static SparseIntArray mTranslationTable = null;
-    private static SparseIntArray mTranslationTableCommon = null;
-    private static SparseIntArray mTranslationTableGSM = null;
-    private static SparseIntArray mTranslationTableCDMA = null;
-
-    // Parser variables
-    private static final String XML_START_TAG = "SmsEnforce7BitTranslationTable";
-    private static final String XML_TRANSLATION_TYPE_TAG = "TranslationType";
-    private static final String XML_CHARACTOR_TAG = "Character";
-    private static final String XML_FROM_TAG = "from";
-    private static final String XML_TO_TAG = "to";
-
-    /**
-     * Translates each message character that is not supported by GSM 7bit
-     * alphabet into a supported one
-     *
-     * @param message
-     *            message to be translated
-     * @param throwsException
-     *            if true and some error occurs during translation, an exception
-     *            is thrown; otherwise a null String is returned
-     * @return translated message or null if some error occur
-     */
-    public static String translate(CharSequence message) {
-        if (message == null) {
-            Rlog.w(TAG, "Null message can not be translated");
-            return null;
-        }
-
-        int size = message.length();
-        if (size <= 0) {
-            return "";
-        }
-
-        if (!mIs7BitTranslationTableLoaded) {
-            mTranslationTableCommon = new SparseIntArray();
-            mTranslationTableGSM = new SparseIntArray();
-            mTranslationTableCDMA = new SparseIntArray();
-            load7BitTranslationTableFromXml();
-            mIs7BitTranslationTableLoaded = true;
-        }
-
-        if ((mTranslationTableCommon != null && mTranslationTableCommon.size() > 0) ||
-                (mTranslationTableGSM != null && mTranslationTableGSM.size() > 0) ||
-                (mTranslationTableCDMA != null && mTranslationTableCDMA.size() > 0)) {
-            char[] output = new char[size];
-            boolean isCdmaFormat = useCdmaFormatForMoSms();
-            for (int i = 0; i < size; i++) {
-                output[i] = translateIfNeeded(message.charAt(i), isCdmaFormat);
-            }
-
-            return String.valueOf(output);
-        }
-
-        return null;
-    }
-
-    /**
-     * Translates a single character into its corresponding acceptable one, if
-     * needed, based on GSM 7-bit alphabet
-     *
-     * @param c
-     *            character to be translated
-     * @return original character, if it's present on GSM 7-bit alphabet; a
-     *         corresponding character, based on the translation table or white
-     *         space, if no mapping is found in the translation table for such
-     *         character
-     */
-    private static char translateIfNeeded(char c, boolean isCdmaFormat) {
-        if (noTranslationNeeded(c, isCdmaFormat)) {
-            if (DBG) {
-                Rlog.v(TAG, "No translation needed for " + Integer.toHexString(c));
-            }
-            return c;
-        }
-
-        /*
-         * Trying to translate unicode to Gsm 7-bit alphabet; If c is not
-         * present on translation table, c does not belong to Unicode Latin-1
-         * (Basic + Supplement), so we don't know how to translate it to a Gsm
-         * 7-bit character! We replace c for an empty space and advises the user
-         * about it.
-         */
-        int translation = -1;
-
-        if (mTranslationTableCommon != null) {
-            translation = mTranslationTableCommon.get(c, -1);
-        }
-
-        if (translation == -1) {
-            if (isCdmaFormat) {
-                if (mTranslationTableCDMA != null) {
-                    translation = mTranslationTableCDMA.get(c, -1);
-                }
-            } else {
-                if (mTranslationTableGSM != null) {
-                    translation = mTranslationTableGSM.get(c, -1);
-                }
-            }
-        }
-
-        if (translation != -1) {
-            if (DBG) {
-                Rlog.v(TAG, Integer.toHexString(c) + " (" + c + ")" + " translated to "
-                        + Integer.toHexString(translation) + " (" + (char) translation + ")");
-            }
-            return (char) translation;
-        } else {
-            if (DBG) {
-                Rlog.w(TAG, "No translation found for " + Integer.toHexString(c)
-                        + "! Replacing for empty space");
-            }
-            return ' ';
-        }
-    }
-
-    private static boolean noTranslationNeeded(char c, boolean isCdmaFormat) {
-        if (isCdmaFormat) {
-            return GsmAlphabet.isGsmSeptets(c) && UserData.charToAscii.get(c, -1) != -1;
-        }
-        else {
-            return GsmAlphabet.isGsmSeptets(c);
-        }
-    }
-
-    private static boolean useCdmaFormatForMoSms() {
-        if (!SmsManager.getDefault().isImsSmsSupported()) {
-            // use Voice technology to determine SMS format.
-            return TelephonyManager.getDefault().getCurrentPhoneType()
-                    == PhoneConstants.PHONE_TYPE_CDMA;
-        }
-        // IMS is registered with SMS support, check the SMS format supported
-        return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
-    }
-
-    /**
-     * Load the whole translation table file from the framework resource
-     * encoded in XML.
-     */
-    private static void load7BitTranslationTableFromXml() {
-        XmlResourceParser parser = null;
-        Resources r = Resources.getSystem();
-
-        if (parser == null) {
-            if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: open normal file");
-            parser = r.getXml(com.android.internal.R.xml.sms_7bit_translation_table);
-        }
-
-        try {
-            XmlUtils.beginDocument(parser, XML_START_TAG);
-            while (true)  {
-                XmlUtils.nextElement(parser);
-                String tag = parser.getName();
-                if (DBG) {
-                    Rlog.d(TAG, "tag: " + tag);
-                }
-                if (XML_TRANSLATION_TYPE_TAG.equals(tag)) {
-                    String type = parser.getAttributeValue(null, "Type");
-                    if (DBG) {
-                        Rlog.d(TAG, "type: " + type);
-                    }
-                    if (type.equals("common")) {
-                        mTranslationTable = mTranslationTableCommon;
-                    } else if (type.equals("gsm")) {
-                        mTranslationTable = mTranslationTableGSM;
-                    } else if (type.equals("cdma")) {
-                        mTranslationTable = mTranslationTableCDMA;
-                    } else {
-                        Rlog.e(TAG, "Error Parsing 7BitTranslationTable: found incorrect type" + type);
-                    }
-                } else if (XML_CHARACTOR_TAG.equals(tag) && mTranslationTable != null) {
-                    int from = parser.getAttributeUnsignedIntValue(null,
-                            XML_FROM_TAG, -1);
-                    int to = parser.getAttributeUnsignedIntValue(null,
-                            XML_TO_TAG, -1);
-                    if ((from != -1) && (to != -1)) {
-                        if (DBG) {
-                            Rlog.d(TAG, "Loading mapping " + Integer.toHexString(from)
-                                    .toUpperCase() + " -> " + Integer.toHexString(to)
-                                    .toUpperCase());
-                        }
-                        mTranslationTable.put (from, to);
-                    } else {
-                        Rlog.d(TAG, "Invalid translation table file format");
-                    }
-                } else {
-                    break;
-                }
-            }
-            if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: parsing successful, file loaded");
-        } catch (Exception e) {
-            Rlog.e(TAG, "Got exception while loading 7BitTranslationTable file.", e);
-        } finally {
-            if (parser instanceof XmlResourceParser) {
-                ((XmlResourceParser)parser).close();
-            }
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/SmsAddress.java b/src/java/com/android/internal/telephony/SmsAddress.java
deleted file mode 100644
index b3892cb..0000000
--- a/src/java/com/android/internal/telephony/SmsAddress.java
+++ /dev/null
@@ -1,65 +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 com.android.internal.telephony;
-
-public abstract class SmsAddress {
-    // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118
-    // and C.S0005-D table 2.7.1.3.2.4-2
-    public static final int TON_UNKNOWN = 0;
-    public static final int TON_INTERNATIONAL = 1;
-    public static final int TON_NATIONAL = 2;
-    public static final int TON_NETWORK = 3;
-    public static final int TON_SUBSCRIBER = 4;
-    public static final int TON_ALPHANUMERIC = 5;
-    public static final int TON_ABBREVIATED = 6;
-
-    public int ton;
-    public String address;
-    public byte[] origBytes;
-
-    /**
-     * Returns the address of the SMS message in String form or null if unavailable
-     */
-    public String getAddressString() {
-        return address;
-    }
-
-    /**
-     * Returns true if this is an alphanumeric address
-     */
-    public boolean isAlphanumeric() {
-        return ton == TON_ALPHANUMERIC;
-    }
-
-    /**
-     * Returns true if this is a network address
-     */
-    public boolean isNetworkSpecific() {
-        return ton == TON_NETWORK;
-    }
-
-    public boolean couldBeEmailGateway() {
-        // Some carriers seems to send email gateway messages in this form:
-        // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5
-        // PID: 0x00, Data coding scheme 0x03
-        // So we just attempt to treat any message from an address length <= 4
-        // as an email gateway
-
-        return address.length() <= 4;
-    }
-
-}
diff --git a/src/java/com/android/internal/telephony/SmsApplication.java b/src/java/com/android/internal/telephony/SmsApplication.java
deleted file mode 100644
index 0d1f205..0000000
--- a/src/java/com/android/internal/telephony/SmsApplication.java
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Copyright (C) 2013 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.Manifest.permission;
-import android.app.AppOpsManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Debug;
-import android.os.Process;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Telephony;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
-import android.telephony.SmsManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Class for managing the primary application that we will deliver SMS/MMS messages to
- *
- * {@hide}
- */
-public final class SmsApplication {
-    static final String LOG_TAG = "SmsApplication";
-    private static final String PHONE_PACKAGE_NAME = "com.android.phone";
-    private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
-    private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
-    private static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
-
-    private static final String SCHEME_SMS = "sms";
-    private static final String SCHEME_SMSTO = "smsto";
-    private static final String SCHEME_MMS = "mms";
-    private static final String SCHEME_MMSTO = "mmsto";
-    private static final boolean DEBUG_MULTIUSER = false;
-
-    private static SmsPackageMonitor sSmsPackageMonitor = null;
-
-    public static class SmsApplicationData {
-        /**
-         * Name of this SMS app for display.
-         */
-        private String mApplicationName;
-
-        /**
-         * Package name for this SMS app.
-         */
-        public String mPackageName;
-
-        /**
-         * The class name of the SMS_DELIVER_ACTION receiver in this app.
-         */
-        private String mSmsReceiverClass;
-
-        /**
-         * The class name of the WAP_PUSH_DELIVER_ACTION receiver in this app.
-         */
-        private String mMmsReceiverClass;
-
-        /**
-         * The class name of the ACTION_RESPOND_VIA_MESSAGE intent in this app.
-         */
-        private String mRespondViaMessageClass;
-
-        /**
-         * The class name of the ACTION_SENDTO intent in this app.
-         */
-        private String mSendToClass;
-
-        /**
-         * The class name of the ACTION_DEFAULT_SMS_PACKAGE_CHANGED receiver in this app.
-         */
-        private String mSmsAppChangedReceiverClass;
-
-        /**
-         * The class name of the ACTION_EXTERNAL_PROVIDER_CHANGE receiver in this app.
-         */
-        private String mProviderChangedReceiverClass;
-
-        /**
-         * The class name of the SIM_FULL_ACTION receiver in this app.
-         */
-        private String mSimFullReceiverClass;
-
-        /**
-         * The user-id for this application
-         */
-        private int mUid;
-
-        /**
-         * Returns true if this SmsApplicationData is complete (all intents handled).
-         * @return
-         */
-        public boolean isComplete() {
-            return (mSmsReceiverClass != null && mMmsReceiverClass != null
-                    && mRespondViaMessageClass != null && mSendToClass != null);
-        }
-
-        public SmsApplicationData(String packageName, int uid) {
-            mPackageName = packageName;
-            mUid = uid;
-        }
-
-        public String getApplicationName(Context context) {
-            if (mApplicationName == null) {
-                PackageManager pm = context.getPackageManager();
-                ApplicationInfo appInfo;
-                try {
-                    appInfo = pm.getApplicationInfoAsUser(mPackageName, 0,
-                            UserHandle.getUserId(mUid));
-                } catch (NameNotFoundException e) {
-                    return null;
-                }
-                if (appInfo != null) {
-                    CharSequence label  = pm.getApplicationLabel(appInfo);
-                    mApplicationName = (label == null) ? null : label.toString();
-                }
-            }
-            return mApplicationName;
-        }
-
-        @Override
-        public String toString() {
-            return " mPackageName: " + mPackageName
-                    + " mSmsReceiverClass: " + mSmsReceiverClass
-                    + " mMmsReceiverClass: " + mMmsReceiverClass
-                    + " mRespondViaMessageClass: " + mRespondViaMessageClass
-                    + " mSendToClass: " + mSendToClass
-                    + " mSmsAppChangedClass: " + mSmsAppChangedReceiverClass
-                    + " mProviderChangedReceiverClass: " + mProviderChangedReceiverClass
-                    + " mSimFullReceiverClass: " + mSimFullReceiverClass
-                    + " mUid: " + mUid;
-        }
-    }
-
-    /**
-     * Returns the userId of the Context object, if called from a system app,
-     * otherwise it returns the caller's userId
-     * @param context The context object passed in by the caller.
-     * @return
-     */
-    private static int getIncomingUserId(Context context) {
-        int contextUserId = context.getUserId();
-        final int callingUid = Binder.getCallingUid();
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
-                    + android.os.Process.myUid() + "\n\t" + Debug.getCallers(4));
-        }
-        if (UserHandle.getAppId(callingUid)
-                < android.os.Process.FIRST_APPLICATION_UID) {
-            return contextUserId;
-        } else {
-            return UserHandle.getUserId(callingUid);
-        }
-    }
-
-    /**
-     * Returns the list of available SMS apps defined as apps that are registered for both the
-     * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast
-     * receivers are enabled)
-     *
-     * Requirements to be an SMS application:
-     * Implement SMS_DELIVER_ACTION broadcast receiver.
-     * Require BROADCAST_SMS permission.
-     *
-     * Implement WAP_PUSH_DELIVER_ACTION broadcast receiver.
-     * Require BROADCAST_WAP_PUSH permission.
-     *
-     * Implement RESPOND_VIA_MESSAGE intent.
-     * Support smsto Uri scheme.
-     * Require SEND_RESPOND_VIA_MESSAGE permission.
-     *
-     * Implement ACTION_SENDTO intent.
-     * Support smsto Uri scheme.
-     */
-    public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            return getApplicationCollectionInternal(context, userId);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private static Collection<SmsApplicationData> getApplicationCollectionInternal(
-            Context context, int userId) {
-        PackageManager packageManager = context.getPackageManager();
-
-        // Get the list of apps registered for SMS
-        Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
-        List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
-                userId);
-
-        HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
-
-        // Add one entry to the map for every sms receiver (ignoring duplicate sms receivers)
-        for (ResolveInfo resolveInfo : smsReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            if (!permission.BROADCAST_SMS.equals(activityInfo.permission)) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            if (!receivers.containsKey(packageName)) {
-                final SmsApplicationData smsApplicationData = new SmsApplicationData(packageName,
-                        activityInfo.applicationInfo.uid);
-                smsApplicationData.mSmsReceiverClass = activityInfo.name;
-                receivers.put(packageName, smsApplicationData);
-            }
-        }
-
-        // Update any existing entries with mms receiver class
-        intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
-        intent.setDataAndType(null, "application/vnd.wap.mms-message");
-        List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
-                userId);
-        for (ResolveInfo resolveInfo : mmsReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            if (!permission.BROADCAST_WAP_PUSH.equals(activityInfo.permission)) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (smsApplicationData != null) {
-                smsApplicationData.mMmsReceiverClass = activityInfo.name;
-            }
-        }
-
-        // Update any existing entries with respond via message intent class.
-        intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
-                Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
-                userId);
-        for (ResolveInfo resolveInfo : respondServices) {
-            final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            if (serviceInfo == null) {
-                continue;
-            }
-            if (!permission.SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) {
-                continue;
-            }
-            final String packageName = serviceInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (smsApplicationData != null) {
-                smsApplicationData.mRespondViaMessageClass = serviceInfo.name;
-            }
-        }
-
-        // Update any existing entries with supports send to.
-        intent = new Intent(Intent.ACTION_SENDTO,
-                Uri.fromParts(SCHEME_SMSTO, "", null));
-        List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
-                userId);
-        for (ResolveInfo resolveInfo : sendToActivities) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (smsApplicationData != null) {
-                smsApplicationData.mSendToClass = activityInfo.name;
-            }
-        }
-
-        // Update any existing entries with the default sms changed handler.
-        intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
-        List<ResolveInfo> smsAppChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
-                    smsAppChangedReceivers);
-        }
-        for (ResolveInfo resolveInfo : smsAppChangedReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (DEBUG_MULTIUSER) {
-                Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
-                        packageName + " smsApplicationData: " + smsApplicationData +
-                        " activityInfo.name: " + activityInfo.name);
-            }
-            if (smsApplicationData != null) {
-                smsApplicationData.mSmsAppChangedReceiverClass = activityInfo.name;
-            }
-        }
-
-        // Update any existing entries with the external provider changed handler.
-        intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
-        List<ResolveInfo> providerChangedReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
-                    providerChangedReceivers);
-        }
-        for (ResolveInfo resolveInfo : providerChangedReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (DEBUG_MULTIUSER) {
-                Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
-                        packageName + " smsApplicationData: " + smsApplicationData +
-                        " activityInfo.name: " + activityInfo.name);
-            }
-            if (smsApplicationData != null) {
-                smsApplicationData.mProviderChangedReceiverClass = activityInfo.name;
-            }
-        }
-
-        // Update any existing entries with the sim full handler.
-        intent = new Intent(Intents.SIM_FULL_ACTION);
-        List<ResolveInfo> simFullReceivers =
-                packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
-                    + simFullReceivers);
-        }
-        for (ResolveInfo resolveInfo : simFullReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (DEBUG_MULTIUSER) {
-                Log.i(LOG_TAG, "getApplicationCollectionInternal packageName="
-                        + packageName + " smsApplicationData: " + smsApplicationData
-                        + " activityInfo.name: " + activityInfo.name);
-            }
-            if (smsApplicationData != null) {
-                smsApplicationData.mSimFullReceiverClass = activityInfo.name;
-            }
-        }
-
-        // Remove any entries for which we did not find all required intents.
-        for (ResolveInfo resolveInfo : smsReceivers) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            if (activityInfo == null) {
-                continue;
-            }
-            final String packageName = activityInfo.packageName;
-            final SmsApplicationData smsApplicationData = receivers.get(packageName);
-            if (smsApplicationData != null) {
-                if (!smsApplicationData.isComplete()) {
-                    receivers.remove(packageName);
-                }
-            }
-        }
-        return receivers.values();
-    }
-
-    /**
-     * Checks to see if we have a valid installed SMS application for the specified package name
-     * @return Data for the specified package name or null if there isn't one
-     */
-    private static SmsApplicationData getApplicationForPackage(
-            Collection<SmsApplicationData> applications, String packageName) {
-        if (packageName == null) {
-            return null;
-        }
-        // Is there an entry in the application list for the specified package?
-        for (SmsApplicationData application : applications) {
-            if (application.mPackageName.contentEquals(packageName)) {
-                return application;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Get the application we will use for delivering SMS/MMS messages.
-     *
-     * We return the preferred sms application with the following order of preference:
-     * (1) User selected SMS app (if selected, and if still valid)
-     * (2) Android Messaging (if installed)
-     * (3) The currently configured highest priority broadcast receiver
-     * (4) Null
-     */
-    private static SmsApplicationData getApplication(Context context, boolean updateIfNeeded,
-            int userId) {
-        TelephonyManager tm = (TelephonyManager)
-                context.getSystemService(Context.TELEPHONY_SERVICE);
-        if (!tm.isSmsCapable()) {
-            // No phone, no SMS
-            return null;
-        }
-
-        Collection<SmsApplicationData> applications = getApplicationCollectionInternal(context,
-                userId);
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplication userId=" + userId);
-        }
-        // Determine which application receives the broadcast
-        String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
-        }
-
-        SmsApplicationData applicationData = null;
-        if (defaultApplication != null) {
-            applicationData = getApplicationForPackage(applications, defaultApplication);
-        }
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplication appData=" + applicationData);
-        }
-        // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
-        // this if the caller asked us to.
-        if (updateIfNeeded && applicationData == null) {
-            // Try to find the default SMS package for this device
-            Resources r = context.getResources();
-            String defaultPackage =
-                    r.getString(com.android.internal.R.string.default_sms_application);
-            applicationData = getApplicationForPackage(applications, defaultPackage);
-
-            if (applicationData == null) {
-                // Are there any applications?
-                if (applications.size() != 0) {
-                    applicationData = (SmsApplicationData)applications.toArray()[0];
-                }
-            }
-
-            // If we found a new default app, update the setting
-            if (applicationData != null) {
-                setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
-            }
-        }
-
-        // If we found a package, make sure AppOps permissions are set up correctly
-        if (applicationData != null) {
-            AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-
-            // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we
-            // are checking is for our current uid. Doing this check from the unprivileged current
-            // SMS app allows us to tell the current SMS app that it is not in a good state and
-            // needs to ask to be the current SMS app again to work properly.
-            if (updateIfNeeded || applicationData.mUid == android.os.Process.myUid()) {
-                // Verify that the SMS app has permissions
-                int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
-                        applicationData.mPackageName);
-                if (mode != AppOpsManager.MODE_ALLOWED) {
-                    Rlog.e(LOG_TAG, applicationData.mPackageName + " lost OP_WRITE_SMS: " +
-                            (updateIfNeeded ? " (fixing)" : " (no permission to fix)"));
-                    if (updateIfNeeded) {
-                        appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
-                                applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
-                    } else {
-                        // We can not return a package if permissions are not set up correctly
-                        applicationData = null;
-                    }
-                }
-            }
-
-            // We can only verify the phone and BT app's permissions from a privileged caller
-            if (updateIfNeeded) {
-                // Ensure this component is still configured as the preferred activity. Usually the
-                // current SMS app will already be the preferred activity - but checking whether or
-                // not this is true is just as expensive as reconfiguring the preferred activity so
-                // we just reconfigure every time.
-                PackageManager packageManager = context.getPackageManager();
-                configurePreferredActivity(packageManager, new ComponentName(
-                        applicationData.mPackageName, applicationData.mSendToClass),
-                        userId);
-                // Assign permission to special system apps
-                assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                        PHONE_PACKAGE_NAME);
-                assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                        BLUETOOTH_PACKAGE_NAME);
-                assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                        MMS_SERVICE_PACKAGE_NAME);
-                assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                        TELEPHONY_PROVIDER_PACKAGE_NAME);
-                // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
-                // apps, all of them should be able to write to telephony provider.
-                // This is to allow the proxy package permission check in telephony provider
-                // to pass.
-                assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
-            }
-        }
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "getApplication returning appData=" + applicationData);
-        }
-        return applicationData;
-    }
-
-    /**
-     * Sets the specified package as the default SMS/MMS application. The caller of this method
-     * needs to have permission to set AppOps and write to secure settings.
-     */
-    public static void setDefaultApplication(String packageName, Context context) {
-        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
-        if (!tm.isSmsCapable()) {
-            // No phone, no SMS
-            return;
-        }
-
-        final int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            setDefaultApplicationInternal(packageName, context, userId);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private static void setDefaultApplicationInternal(String packageName, Context context,
-            int userId) {
-        // Get old package name
-        String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
-                Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-
-        if (DEBUG_MULTIUSER) {
-            Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
-                    " new=" + packageName);
-        }
-
-        if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
-            // No change
-            return;
-        }
-
-        // We only make the change if the new package is valid
-        PackageManager packageManager = context.getPackageManager();
-        Collection<SmsApplicationData> applications = getApplicationCollection(context);
-        SmsApplicationData oldAppData = oldPackageName != null ?
-                getApplicationForPackage(applications, oldPackageName) : null;
-        SmsApplicationData applicationData = getApplicationForPackage(applications, packageName);
-        if (applicationData != null) {
-            // Ignore OP_WRITE_SMS for the previously configured default SMS app.
-            AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-            if (oldPackageName != null) {
-                try {
-                    PackageInfo info = packageManager.getPackageInfo(oldPackageName,
-                            PackageManager.GET_UNINSTALLED_PACKAGES);
-                    appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
-                            oldPackageName, AppOpsManager.MODE_IGNORED);
-                } catch (NameNotFoundException e) {
-                    Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName);
-                }
-            }
-
-            // Update the secure setting.
-            Settings.Secure.putStringForUser(context.getContentResolver(),
-                    Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
-                    userId);
-
-            // Configure this as the preferred activity for SENDTO sms/mms intents
-            configurePreferredActivity(packageManager, new ComponentName(
-                    applicationData.mPackageName, applicationData.mSendToClass), userId);
-
-            // Allow OP_WRITE_SMS for the newly configured default SMS app.
-            appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
-                    applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
-
-            // Assign permission to special system apps
-            assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                    PHONE_PACKAGE_NAME);
-            assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                    BLUETOOTH_PACKAGE_NAME);
-            assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                    MMS_SERVICE_PACKAGE_NAME);
-            assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
-                    TELEPHONY_PROVIDER_PACKAGE_NAME);
-            // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
-            // apps, all of them should be able to write to telephony provider.
-            // This is to allow the proxy package permission check in telephony provider
-            // to pass.
-            assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
-
-            if (DEBUG_MULTIUSER) {
-                Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
-            }
-            if (oldAppData != null && oldAppData.mSmsAppChangedReceiverClass != null) {
-                // Notify the old sms app that it's no longer the default
-                final Intent oldAppIntent =
-                        new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
-                final ComponentName component = new ComponentName(oldAppData.mPackageName,
-                        oldAppData.mSmsAppChangedReceiverClass);
-                oldAppIntent.setComponent(component);
-                oldAppIntent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false);
-                if (DEBUG_MULTIUSER) {
-                    Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
-                }
-                context.sendBroadcast(oldAppIntent);
-            }
-            // Notify the new sms app that it's now the default (if the new sms app has a receiver
-            // to handle the changed default sms intent).
-            if (DEBUG_MULTIUSER) {
-                Log.i(LOG_TAG, "setDefaultApplicationInternal new applicationData=" +
-                        applicationData);
-            }
-            if (applicationData.mSmsAppChangedReceiverClass != null) {
-                final Intent intent =
-                        new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
-                final ComponentName component = new ComponentName(applicationData.mPackageName,
-                        applicationData.mSmsAppChangedReceiverClass);
-                intent.setComponent(component);
-                intent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, true);
-                if (DEBUG_MULTIUSER) {
-                    Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
-                }
-                context.sendBroadcast(intent);
-            }
-            MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
-                    applicationData.mPackageName);
-        }
-    }
-
-    /**
-     * Assign WRITE_SMS AppOps permission to some special system apps.
-     *
-     * @param context The context
-     * @param packageManager The package manager instance
-     * @param appOps The AppOps manager instance
-     * @param packageName The package name of the system app
-     */
-    private static void assignWriteSmsPermissionToSystemApp(Context context,
-            PackageManager packageManager, AppOpsManager appOps, String packageName) {
-        // First check package signature matches the caller's package signature.
-        // Since this class is only used internally by the system, this check makes sure
-        // the package signature matches system signature.
-        final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
-        if (result != PackageManager.SIGNATURE_MATCH) {
-            Rlog.e(LOG_TAG, packageName + " does not have system signature");
-            return;
-        }
-        try {
-            PackageInfo info = packageManager.getPackageInfo(packageName, 0);
-            int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
-                    packageName);
-            if (mode != AppOpsManager.MODE_ALLOWED) {
-                Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS:  (fixing)");
-                appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
-                        packageName, AppOpsManager.MODE_ALLOWED);
-            }
-        } catch (NameNotFoundException e) {
-            // No whitelisted system app on this device
-            Rlog.e(LOG_TAG, "Package not found: " + packageName);
-        }
-
-    }
-
-    private static void assignWriteSmsPermissionToSystemUid(AppOpsManager appOps, int uid) {
-        appOps.setUidMode(AppOpsManager.OP_WRITE_SMS, uid, AppOpsManager.MODE_ALLOWED);
-    }
-
-    /**
-     * Tracks package changes and ensures that the default SMS app is always configured to be the
-     * preferred activity for SENDTO sms/mms intents.
-     */
-    private static final class SmsPackageMonitor extends PackageMonitor {
-        final Context mContext;
-
-        public SmsPackageMonitor(Context context) {
-            super();
-            mContext = context;
-        }
-
-        @Override
-        public void onPackageDisappeared(String packageName, int reason) {
-            onPackageChanged();
-        }
-
-        @Override
-        public void onPackageAppeared(String packageName, int reason) {
-            onPackageChanged();
-        }
-
-        @Override
-        public void onPackageModified(String packageName) {
-            onPackageChanged();
-        }
-
-        private void onPackageChanged() {
-            PackageManager packageManager = mContext.getPackageManager();
-            Context userContext = mContext;
-            final int userId = getSendingUserId();
-            if (userId != UserHandle.USER_SYSTEM) {
-                try {
-                    userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
-                            new UserHandle(userId));
-                } catch (NameNotFoundException nnfe) {
-                    if (DEBUG_MULTIUSER) {
-                        Log.w(LOG_TAG, "Unable to create package context for user " + userId);
-                    }
-                }
-            }
-            // Ensure this component is still configured as the preferred activity
-            ComponentName componentName = getDefaultSendToApplication(userContext, true);
-            if (componentName != null) {
-                configurePreferredActivity(packageManager, componentName, userId);
-            }
-        }
-    }
-
-    public static void initSmsPackageMonitor(Context context) {
-        sSmsPackageMonitor = new SmsPackageMonitor(context);
-        sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
-    }
-
-    private static void configurePreferredActivity(PackageManager packageManager,
-            ComponentName componentName, int userId) {
-        // Add the four activity preferences we want to direct to this app.
-        replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMS);
-        replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMSTO);
-        replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMS);
-        replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMSTO);
-    }
-
-    /**
-     * Updates the ACTION_SENDTO activity to the specified component for the specified scheme.
-     */
-    private static void replacePreferredActivity(PackageManager packageManager,
-            ComponentName componentName, int userId, String scheme) {
-        // Build the set of existing activities that handle this scheme
-        Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null));
-        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivitiesAsUser(
-                intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER,
-                userId);
-
-        // Build the set of ComponentNames for these activities
-        final int n = resolveInfoList.size();
-        ComponentName[] set = new ComponentName[n];
-        for (int i = 0; i < n; i++) {
-            ResolveInfo info = resolveInfoList.get(i);
-            set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
-        }
-
-        // Update the preferred SENDTO activity for the specified scheme
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_SENDTO);
-        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
-        intentFilter.addDataScheme(scheme);
-        packageManager.replacePreferredActivityAsUser(intentFilter,
-                IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL,
-                set, componentName, userId);
-    }
-
-    /**
-     * Returns SmsApplicationData for this package if this package is capable of being set as the
-     * default SMS application.
-     */
-    public static SmsApplicationData getSmsApplicationData(String packageName, Context context) {
-        Collection<SmsApplicationData> applications = getApplicationCollection(context);
-        return getApplicationForPackage(applications, packageName);
-    }
-
-    /**
-     * Gets the default SMS application
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to deliver SMS messages to
-     */
-    public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mSmsReceiverClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Gets the default MMS application
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to deliver MMS messages to
-     */
-    public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mMmsReceiverClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Gets the default Respond Via Message application
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to direct Respond Via Message intent to
-     */
-    public static ComponentName getDefaultRespondViaMessageApplication(Context context,
-            boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mRespondViaMessageClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Gets the default Send To (smsto) application.
-     * <p>
-     * Caller must pass in the correct user context if calling from a singleton service.
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to direct SEND_TO (smsto) intent to
-     */
-    public static ComponentName getDefaultSendToApplication(Context context,
-            boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mSendToClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Gets the default application that handles external changes to the SmsProvider and
-     * MmsProvider.
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to deliver change intents to
-     */
-    public static ComponentName getDefaultExternalTelephonyProviderChangedApplication(
-            Context context, boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null
-                    && smsApplicationData.mProviderChangedReceiverClass != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mProviderChangedReceiverClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Gets the default application that handles sim full event.
-     * @param context context from the calling app
-     * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @return component name of the app and class to deliver change intents to
-     */
-    public static ComponentName getDefaultSimFullApplication(
-            Context context, boolean updateIfNeeded) {
-        int userId = getIncomingUserId(context);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            ComponentName component = null;
-            SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
-            if (smsApplicationData != null
-                    && smsApplicationData.mSimFullReceiverClass != null) {
-                component = new ComponentName(smsApplicationData.mPackageName,
-                        smsApplicationData.mSimFullReceiverClass);
-            }
-            return component;
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Returns whether need to write the SMS message to SMS database for this package.
-     * <p>
-     * Caller must pass in the correct user context if calling from a singleton service.
-     */
-    public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
-        if (SmsManager.getDefault().getAutoPersisting()) {
-            return true;
-        }
-        return !isDefaultSmsApplication(context, packageName);
-    }
-
-    /**
-     * Check if a package is default sms app (or equivalent, like bluetooth)
-     *
-     * @param context context from the calling app
-     * @param packageName the name of the package to be checked
-     * @return true if the package is default sms app or bluetooth
-     */
-    public static boolean isDefaultSmsApplication(Context context, String packageName) {
-        if (packageName == null) {
-            return false;
-        }
-        final String defaultSmsPackage = getDefaultSmsApplicationPackageName(context);
-        if ((defaultSmsPackage != null && defaultSmsPackage.equals(packageName))
-                || BLUETOOTH_PACKAGE_NAME.equals(packageName)) {
-            return true;
-        }
-        return false;
-    }
-
-    private static String getDefaultSmsApplicationPackageName(Context context) {
-        final ComponentName component = getDefaultSmsApplication(context, false);
-        if (component != null) {
-            return component.getPackageName();
-        }
-        return null;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/SmsHeader.java b/src/java/com/android/internal/telephony/SmsHeader.java
deleted file mode 100644
index b519b70..0000000
--- a/src/java/com/android/internal/telephony/SmsHeader.java
+++ /dev/null
@@ -1,314 +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 com.android.internal.telephony;
-
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.util.HexDump;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import java.util.ArrayList;
-
-/**
- * SMS user data header, as specified in TS 23.040 9.2.3.24.
- */
-public class SmsHeader {
-
-    // TODO(cleanup): this data structure is generally referred to as
-    // the 'user data header' or UDH, and so the class name should
-    // change to reflect this...
-
-    /** SMS user data header information element identifiers.
-     * (see TS 23.040 9.2.3.24)
-     */
-    public static final int ELT_ID_CONCATENATED_8_BIT_REFERENCE       = 0x00;
-    public static final int ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION     = 0x01;
-    public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT  = 0x04;
-    public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT = 0x05;
-    public static final int ELT_ID_SMSC_CONTROL_PARAMS                = 0x06;
-    public static final int ELT_ID_UDH_SOURCE_INDICATION              = 0x07;
-    public static final int ELT_ID_CONCATENATED_16_BIT_REFERENCE      = 0x08;
-    public static final int ELT_ID_WIRELESS_CTRL_MSG_PROTOCOL         = 0x09;
-    public static final int ELT_ID_TEXT_FORMATTING                    = 0x0A;
-    public static final int ELT_ID_PREDEFINED_SOUND                   = 0x0B;
-    public static final int ELT_ID_USER_DEFINED_SOUND                 = 0x0C;
-    public static final int ELT_ID_PREDEFINED_ANIMATION               = 0x0D;
-    public static final int ELT_ID_LARGE_ANIMATION                    = 0x0E;
-    public static final int ELT_ID_SMALL_ANIMATION                    = 0x0F;
-    public static final int ELT_ID_LARGE_PICTURE                      = 0x10;
-    public static final int ELT_ID_SMALL_PICTURE                      = 0x11;
-    public static final int ELT_ID_VARIABLE_PICTURE                   = 0x12;
-    public static final int ELT_ID_USER_PROMPT_INDICATOR              = 0x13;
-    public static final int ELT_ID_EXTENDED_OBJECT                    = 0x14;
-    public static final int ELT_ID_REUSED_EXTENDED_OBJECT             = 0x15;
-    public static final int ELT_ID_COMPRESSION_CONTROL                = 0x16;
-    public static final int ELT_ID_OBJECT_DISTR_INDICATOR             = 0x17;
-    public static final int ELT_ID_STANDARD_WVG_OBJECT                = 0x18;
-    public static final int ELT_ID_CHARACTER_SIZE_WVG_OBJECT          = 0x19;
-    public static final int ELT_ID_EXTENDED_OBJECT_DATA_REQUEST_CMD   = 0x1A;
-    public static final int ELT_ID_RFC_822_EMAIL_HEADER               = 0x20;
-    public static final int ELT_ID_HYPERLINK_FORMAT_ELEMENT           = 0x21;
-    public static final int ELT_ID_REPLY_ADDRESS_ELEMENT              = 0x22;
-    public static final int ELT_ID_ENHANCED_VOICE_MAIL_INFORMATION    = 0x23;
-    public static final int ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT     = 0x24;
-    public static final int ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT    = 0x25;
-
-    public static final int PORT_WAP_PUSH = 2948;
-    public static final int PORT_WAP_WSP  = 9200;
-
-    public static class PortAddrs {
-        public int destPort;
-        public int origPort;
-        public boolean areEightBits;
-    }
-
-    public static class ConcatRef {
-        public int refNumber;
-        public int seqNumber;
-        public int msgCount;
-        public boolean isEightBits;
-    }
-
-    public static class SpecialSmsMsg {
-        public int msgIndType;
-        public int msgCount;
-    }
-
-    /**
-     * A header element that is not explicitly parsed, meaning not
-     * PortAddrs or ConcatRef or SpecialSmsMsg.
-     */
-    public static class MiscElt {
-        public int id;
-        public byte[] data;
-    }
-
-    public PortAddrs portAddrs;
-    public ConcatRef concatRef;
-    public ArrayList<SpecialSmsMsg> specialSmsMsgList = new ArrayList<SpecialSmsMsg>();
-    public ArrayList<MiscElt> miscEltList = new ArrayList<MiscElt>();
-
-    /** 7 bit national language locking shift table, or 0 for GSM default 7 bit alphabet. */
-    public int languageTable;
-
-    /** 7 bit national language single shift table, or 0 for GSM default 7 bit extension table. */
-    public int languageShiftTable;
-
-    public SmsHeader() {}
-
-    /**
-     * Create structured SmsHeader object from serialized byte array representation.
-     * (see TS 23.040 9.2.3.24)
-     * @param data is user data header bytes
-     * @return SmsHeader object
-     */
-    public static SmsHeader fromByteArray(byte[] data) {
-        ByteArrayInputStream inStream = new ByteArrayInputStream(data);
-        SmsHeader smsHeader = new SmsHeader();
-        while (inStream.available() > 0) {
-            /**
-             * NOTE: as defined in the spec, ConcatRef and PortAddr
-             * fields should not reoccur, but if they do the last
-             * occurrence is to be used.  Also, for ConcatRef
-             * elements, if the count is zero, sequence is zero, or
-             * sequence is larger than count, the entire element is to
-             * be ignored.
-             */
-            int id = inStream.read();
-            int length = inStream.read();
-            ConcatRef concatRef;
-            PortAddrs portAddrs;
-            switch (id) {
-            case ELT_ID_CONCATENATED_8_BIT_REFERENCE:
-                concatRef = new ConcatRef();
-                concatRef.refNumber = inStream.read();
-                concatRef.msgCount = inStream.read();
-                concatRef.seqNumber = inStream.read();
-                concatRef.isEightBits = true;
-                if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 &&
-                        concatRef.seqNumber <= concatRef.msgCount) {
-                    smsHeader.concatRef = concatRef;
-                }
-                break;
-            case ELT_ID_CONCATENATED_16_BIT_REFERENCE:
-                concatRef = new ConcatRef();
-                concatRef.refNumber = (inStream.read() << 8) | inStream.read();
-                concatRef.msgCount = inStream.read();
-                concatRef.seqNumber = inStream.read();
-                concatRef.isEightBits = false;
-                if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 &&
-                        concatRef.seqNumber <= concatRef.msgCount) {
-                    smsHeader.concatRef = concatRef;
-                }
-                break;
-            case ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT:
-                portAddrs = new PortAddrs();
-                portAddrs.destPort = inStream.read();
-                portAddrs.origPort = inStream.read();
-                portAddrs.areEightBits = true;
-                smsHeader.portAddrs = portAddrs;
-                break;
-            case ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT:
-                portAddrs = new PortAddrs();
-                portAddrs.destPort = (inStream.read() << 8) | inStream.read();
-                portAddrs.origPort = (inStream.read() << 8) | inStream.read();
-                portAddrs.areEightBits = false;
-                smsHeader.portAddrs = portAddrs;
-                break;
-            case ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT:
-                smsHeader.languageShiftTable = inStream.read();
-                break;
-            case ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT:
-                smsHeader.languageTable = inStream.read();
-                break;
-            case ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION:
-                SpecialSmsMsg specialSmsMsg = new SpecialSmsMsg();
-                specialSmsMsg.msgIndType = inStream.read();
-                specialSmsMsg.msgCount = inStream.read();
-                smsHeader.specialSmsMsgList.add(specialSmsMsg);
-                break;
-            default:
-                MiscElt miscElt = new MiscElt();
-                miscElt.id = id;
-                miscElt.data = new byte[length];
-                inStream.read(miscElt.data, 0, length);
-                smsHeader.miscEltList.add(miscElt);
-            }
-        }
-        return smsHeader;
-    }
-
-    /**
-     * Create serialized byte array representation from structured SmsHeader object.
-     * (see TS 23.040 9.2.3.24)
-     * @return Byte array representing the SmsHeader
-     */
-    public static byte[] toByteArray(SmsHeader smsHeader) {
-        if ((smsHeader.portAddrs == null) &&
-            (smsHeader.concatRef == null) &&
-            (smsHeader.specialSmsMsgList.isEmpty()) &&
-            (smsHeader.miscEltList.isEmpty()) &&
-            (smsHeader.languageShiftTable == 0) &&
-            (smsHeader.languageTable == 0)) {
-            return null;
-        }
-
-        ByteArrayOutputStream outStream =
-                new ByteArrayOutputStream(SmsConstants.MAX_USER_DATA_BYTES);
-        ConcatRef concatRef = smsHeader.concatRef;
-        if (concatRef != null) {
-            if (concatRef.isEightBits) {
-                outStream.write(ELT_ID_CONCATENATED_8_BIT_REFERENCE);
-                outStream.write(3);
-                outStream.write(concatRef.refNumber);
-            } else {
-                outStream.write(ELT_ID_CONCATENATED_16_BIT_REFERENCE);
-                outStream.write(4);
-                outStream.write(concatRef.refNumber >>> 8);
-                outStream.write(concatRef.refNumber & 0x00FF);
-            }
-            outStream.write(concatRef.msgCount);
-            outStream.write(concatRef.seqNumber);
-        }
-        PortAddrs portAddrs = smsHeader.portAddrs;
-        if (portAddrs != null) {
-            if (portAddrs.areEightBits) {
-                outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT);
-                outStream.write(2);
-                outStream.write(portAddrs.destPort);
-                outStream.write(portAddrs.origPort);
-            } else {
-                outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT);
-                outStream.write(4);
-                outStream.write(portAddrs.destPort >>> 8);
-                outStream.write(portAddrs.destPort & 0x00FF);
-                outStream.write(portAddrs.origPort >>> 8);
-                outStream.write(portAddrs.origPort & 0x00FF);
-            }
-        }
-        if (smsHeader.languageShiftTable != 0) {
-            outStream.write(ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT);
-            outStream.write(1);
-            outStream.write(smsHeader.languageShiftTable);
-        }
-        if (smsHeader.languageTable != 0) {
-            outStream.write(ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT);
-            outStream.write(1);
-            outStream.write(smsHeader.languageTable);
-        }
-        for (SpecialSmsMsg specialSmsMsg : smsHeader.specialSmsMsgList) {
-            outStream.write(ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION);
-            outStream.write(2);
-            outStream.write(specialSmsMsg.msgIndType & 0xFF);
-            outStream.write(specialSmsMsg.msgCount & 0xFF);
-        }
-        for (MiscElt miscElt : smsHeader.miscEltList) {
-            outStream.write(miscElt.id);
-            outStream.write(miscElt.data.length);
-            outStream.write(miscElt.data, 0, miscElt.data.length);
-        }
-        return outStream.toByteArray();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("UserDataHeader ");
-        builder.append("{ ConcatRef ");
-        if (concatRef == null) {
-            builder.append("unset");
-        } else {
-            builder.append("{ refNumber=" + concatRef.refNumber);
-            builder.append(", msgCount=" + concatRef.msgCount);
-            builder.append(", seqNumber=" + concatRef.seqNumber);
-            builder.append(", isEightBits=" + concatRef.isEightBits);
-            builder.append(" }");
-        }
-        builder.append(", PortAddrs ");
-        if (portAddrs == null) {
-            builder.append("unset");
-        } else {
-            builder.append("{ destPort=" + portAddrs.destPort);
-            builder.append(", origPort=" + portAddrs.origPort);
-            builder.append(", areEightBits=" + portAddrs.areEightBits);
-            builder.append(" }");
-        }
-        if (languageShiftTable != 0) {
-            builder.append(", languageShiftTable=" + languageShiftTable);
-        }
-        if (languageTable != 0) {
-            builder.append(", languageTable=" + languageTable);
-        }
-        for (SpecialSmsMsg specialSmsMsg : specialSmsMsgList) {
-            builder.append(", SpecialSmsMsg ");
-            builder.append("{ msgIndType=" + specialSmsMsg.msgIndType);
-            builder.append(", msgCount=" + specialSmsMsg.msgCount);
-            builder.append(" }");
-        }
-        for (MiscElt miscElt : miscEltList) {
-            builder.append(", MiscElt ");
-            builder.append("{ id=" + miscElt.id);
-            builder.append(", length=" + miscElt.data.length);
-            builder.append(", data=" + HexDump.toHexString(miscElt.data));
-            builder.append(" }");
-        }
-        builder.append(" }");
-        return builder.toString();
-    }
-
-}
diff --git a/src/java/com/android/internal/telephony/SmsMessageBase.java b/src/java/com/android/internal/telephony/SmsMessageBase.java
deleted file mode 100644
index e5821dc..0000000
--- a/src/java/com/android/internal/telephony/SmsMessageBase.java
+++ /dev/null
@@ -1,433 +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 com.android.internal.telephony;
-
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import java.text.BreakIterator;
-import java.util.Arrays;
-
-import android.provider.Telephony;
-import android.telephony.SmsMessage;
-import android.text.Emoji;
-
-/**
- * Base class declaring the specific methods and members for SmsMessage.
- * {@hide}
- */
-public abstract class SmsMessageBase {
-    /** {@hide} The address of the SMSC. May be null */
-    protected String mScAddress;
-
-    /** {@hide} The address of the sender */
-    protected SmsAddress mOriginatingAddress;
-
-    /** {@hide} The message body as a string. May be null if the message isn't text */
-    protected String mMessageBody;
-
-    /** {@hide} */
-    protected String mPseudoSubject;
-
-    /** {@hide} Non-null if this is an email gateway message */
-    protected String mEmailFrom;
-
-    /** {@hide} Non-null if this is an email gateway message */
-    protected String mEmailBody;
-
-    /** {@hide} */
-    protected boolean mIsEmail;
-
-    /** {@hide} Time when SC (service centre) received the message */
-    protected long mScTimeMillis;
-
-    /** {@hide} The raw PDU of the message */
-    protected byte[] mPdu;
-
-    /** {@hide} The raw bytes for the user data section of the message */
-    protected byte[] mUserData;
-
-    /** {@hide} */
-    protected SmsHeader mUserDataHeader;
-
-    // "Message Waiting Indication Group"
-    // 23.038 Section 4
-    /** {@hide} */
-    protected boolean mIsMwi;
-
-    /** {@hide} */
-    protected boolean mMwiSense;
-
-    /** {@hide} */
-    protected boolean mMwiDontStore;
-
-    /**
-     * Indicates status for messages stored on the ICC.
-     */
-    protected int mStatusOnIcc = -1;
-
-    /**
-     * Record index of message in the EF.
-     */
-    protected int mIndexOnIcc = -1;
-
-    /** TP-Message-Reference - Message Reference of sent message. @hide */
-    public int mMessageRef;
-
-    // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly.
-    public static abstract class SubmitPduBase  {
-        public byte[] encodedScAddress; // Null if not applicable.
-        public byte[] encodedMessage;
-
-        @Override
-        public String toString() {
-            return "SubmitPdu: encodedScAddress = "
-                    + Arrays.toString(encodedScAddress)
-                    + ", encodedMessage = "
-                    + Arrays.toString(encodedMessage);
-        }
-    }
-
-    /**
-     * Returns the address of the SMS service center that relayed this message
-     * or null if there is none.
-     */
-    public String getServiceCenterAddress() {
-        return mScAddress;
-    }
-
-    /**
-     * Returns the originating address (sender) of this SMS message in String
-     * form or null if unavailable
-     */
-    public String getOriginatingAddress() {
-        if (mOriginatingAddress == null) {
-            return null;
-        }
-
-        return mOriginatingAddress.getAddressString();
-    }
-
-    /**
-     * 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() {
-        if (mIsEmail) {
-            return mEmailFrom;
-        } else {
-            return getOriginatingAddress();
-        }
-    }
-
-    /**
-     * 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 mMessageBody;
-    }
-
-    /**
-     * Returns the class of this message.
-     */
-    public abstract SmsConstants.MessageClass getMessageClass();
-
-    /**
-     * 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() {
-        if (mIsEmail) {
-            return mEmailBody;
-        } else {
-            return getMessageBody();
-        }
-    }
-
-    /**
-     * Unofficial convention of a subject line enclosed in parens empty string
-     * if not present
-     */
-    public String getPseudoSubject() {
-        return mPseudoSubject == null ? "" : mPseudoSubject;
-    }
-
-    /**
-     * Returns the service centre timestamp in currentTimeMillis() format
-     */
-    public long getTimestampMillis() {
-        return mScTimeMillis;
-    }
-
-    /**
-     * 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 mIsEmail;
-    }
-
-    /**
-     * @return if isEmail() is true, body of the email sent through the gateway.
-     *         null otherwise
-     */
-    public String getEmailBody() {
-        return mEmailBody;
-    }
-
-    /**
-     * @return if isEmail() is true, email from address of email sent through
-     *         the gateway. null otherwise
-     */
-    public String getEmailFrom() {
-        return mEmailFrom;
-    }
-
-    /**
-     * Get protocol identifier.
-     */
-    public abstract int getProtocolIdentifier();
-
-    /**
-     * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
-     * SMS
-     */
-    public abstract boolean 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 abstract boolean isCphsMwiMessage();
-
-    /**
-     * returns true if this message is a CPHS voicemail / message waiting
-     * indicator (MWI) clear message
-     */
-    public abstract boolean isMWIClearMessage();
-
-    /**
-     * returns true if this message is a CPHS voicemail / message waiting
-     * indicator (MWI) set message
-     */
-    public abstract boolean isMWISetMessage();
-
-    /**
-     * returns true if this message is a "Message Waiting Indication Group:
-     * Discard Message" notification and should not be stored.
-     */
-    public abstract boolean isMwiDontStore();
-
-    /**
-     * returns the user data section minus the user data header if one was
-     * present.
-     */
-    public byte[] getUserData() {
-        return mUserData;
-    }
-
-    /**
-     * Returns an object representing the user data header
-     *
-     * {@hide}
-     */
-    public SmsHeader getUserDataHeader() {
-        return mUserDataHeader;
-    }
-
-    /**
-     * TODO(cleanup): The term PDU is used in a seemingly non-unique
-     * manner -- for example, what is the difference between this byte
-     * array and the contents of SubmitPdu objects.  Maybe a more
-     * illustrative term would be appropriate.
-     */
-
-    /**
-     * Returns the raw PDU for the message.
-     */
-    public byte[] getPdu() {
-        return mPdu;
-    }
-
-    /**
-     * 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.
-     *
-     * @return 0 indicates the previously sent message was received.
-     *         See TS 23.040, 9.9.2.3.15 for a description of other possible
-     *         values.
-     */
-    public abstract int getStatus();
-
-    /**
-     * Return true iff the message is a SMS-STATUS-REPORT message.
-     */
-    public abstract boolean isStatusReportMessage();
-
-    /**
-     * Returns true iff the <code>TP-Reply-Path</code> bit is set in
-     * this message.
-     */
-    public abstract boolean isReplyPathPresent();
-
-    /**
-     * 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 mStatusOnIcc;
-    }
-
-    /**
-     * 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 mIndexOnIcc;
-    }
-
-    protected void parseMessageBody() {
-        // originatingAddress could be null if this message is from a status
-        // report.
-        if (mOriginatingAddress != null && mOriginatingAddress.couldBeEmailGateway()) {
-            extractEmailAddressFromMessageBody();
-        }
-    }
-
-    /**
-     * Try to parse this message as an email gateway message
-     * There are two ways specified in TS 23.040 Section 3.8 :
-     *  - SMS message "may have its TP-PID set for Internet electronic mail - MT
-     * SMS format: [<from-address><space>]<message> - "Depending on the
-     * nature of the gateway, the destination/origination address is either
-     * derived from the content of the SMS TP-OA or TP-DA field, or the
-     * TP-OA/TP-DA field contains a generic gateway address and the to/from
-     * address is added at the beginning as shown above." (which is supported here)
-     * - Multiple addresses separated by commas, no spaces, Subject field delimited
-     * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
-     */
-    protected void extractEmailAddressFromMessageBody() {
-
-        /* Some carriers may use " /" delimiter as below
-         *
-         * 1. [x@y][ ]/[subject][ ]/[body]
-         * -or-
-         * 2. [x@y][ ]/[body]
-         */
-         String[] parts = mMessageBody.split("( /)|( )", 2);
-         if (parts.length < 2) return;
-         mEmailFrom = parts[0];
-         mEmailBody = parts[1];
-         mIsEmail = Telephony.Mms.isEmailAddress(mEmailFrom);
-    }
-
-    /**
-     * Find the next position to start a new fragment of a multipart SMS.
-     *
-     * @param currentPosition current start position of the fragment
-     * @param byteLimit maximum number of bytes in the fragment
-     * @param msgBody text of the SMS in UTF-16 encoding
-     * @return the position to start the next fragment
-     */
-    public static int findNextUnicodePosition(
-            int currentPosition, int byteLimit, CharSequence msgBody) {
-        int nextPos = Math.min(currentPosition + byteLimit / 2, msgBody.length());
-        // Check whether the fragment ends in a character boundary. Some characters take 4-bytes
-        // in UTF-16 encoding. Many carriers cannot handle
-        // a fragment correctly if it does not end at a character boundary.
-        if (nextPos < msgBody.length()) {
-            BreakIterator breakIterator = BreakIterator.getCharacterInstance();
-            breakIterator.setText(msgBody.toString());
-            if (!breakIterator.isBoundary(nextPos)) {
-                int breakPos = breakIterator.preceding(nextPos);
-                while (breakPos + 4 <= nextPos
-                        && Emoji.isRegionalIndicatorSymbol(
-                            Character.codePointAt(msgBody, breakPos))
-                        && Emoji.isRegionalIndicatorSymbol(
-                            Character.codePointAt(msgBody, breakPos + 2))) {
-                    // skip forward over flags (pairs of Regional Indicator Symbol)
-                    breakPos += 4;
-                }
-                if (breakPos > currentPosition) {
-                    nextPos = breakPos;
-                } else if (Character.isHighSurrogate(msgBody.charAt(nextPos - 1))) {
-                    // no character boundary in this fragment, try to at least land on a code point
-                    nextPos -= 1;
-                }
-            }
-        }
-        return nextPos;
-    }
-
-    /**
-     * Calculate the TextEncodingDetails of a message encoded in Unicode.
-     */
-    public static TextEncodingDetails calcUnicodeEncodingDetails(CharSequence msgBody) {
-        TextEncodingDetails ted = new TextEncodingDetails();
-        int octets = msgBody.length() * 2;
-        ted.codeUnitSize = SmsConstants.ENCODING_16BIT;
-        ted.codeUnitCount = msgBody.length();
-        if (octets > SmsConstants.MAX_USER_DATA_BYTES) {
-            // If EMS is not supported, break down EMS into single segment SMS
-            // and add page info " x/y".
-            // In the case of UCS2 encoding type, 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).
-            int maxUserDataBytesWithHeader = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
-            if (!SmsMessage.hasEmsSupport()) {
-                // make sure total number of segments is less than 10
-                if (octets <= 9 * (maxUserDataBytesWithHeader - 2)) {
-                    maxUserDataBytesWithHeader -= 2;
-                }
-            }
-
-            int pos = 0;  // Index in code units.
-            int msgCount = 0;
-            while (pos < msgBody.length()) {
-                int nextPos = findNextUnicodePosition(pos, maxUserDataBytesWithHeader,
-                        msgBody);
-                if (nextPos == msgBody.length()) {
-                    ted.codeUnitsRemaining = pos + maxUserDataBytesWithHeader / 2 -
-                            msgBody.length();
-                }
-                pos = nextPos;
-                msgCount++;
-            }
-            ted.msgCount = msgCount;
-        } else {
-            ted.msgCount = 1;
-            ted.codeUnitsRemaining = (SmsConstants.MAX_USER_DATA_BYTES - octets) / 2;
-        }
-
-        return ted;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
index ca1d9e0..2daf232 100644
--- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
+++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
@@ -16,15 +16,21 @@
 package com.android.internal.telephony;
 
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.provider.VoicemailContract;
+import android.telecom.PhoneAccountHandle;
 import android.telephony.SmsMessage;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.VisualVoicemailSms;
 import android.telephony.VisualVoicemailSmsFilterSettings;
 import android.util.ArrayMap;
 import android.util.Log;
+
 import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;
+
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
@@ -35,14 +41,18 @@
 
     private static final String TAG = "VvmSmsFilter";
 
-    private static final String SYSTEM_VVM_CLIENT_PACKAGE = "com.android.phone";
+    private static final String TELEPHONY_SERVICE_PACKAGE = "com.android.phone";
+
+    private static final ComponentName PSTN_CONNECTION_SERVICE_COMPONENT =
+            new ComponentName("com.android.phone",
+                    "com.android.services.telephony.TelephonyConnectionService");
 
     private static Map<String, List<Pattern>> sPatterns;
 
     /**
      * Attempt to parse the incoming SMS as a visual voicemail SMS. If the parsing succeeded, A
-     * {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} intent will be sent to the visual
-     * voicemail client, and the SMS should be dropped.
+     * {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} intent will be sent to telephony
+     * service, and the SMS will be dropped.
      *
      * <p>The accepted format for a visual voicemail SMS is a generalization of the OMTP format:
      *
@@ -50,8 +60,7 @@
      *
      * Additionally, if the SMS does not match the format, but matches the regex specified by the
      * carrier in {@link com.android.internal.R.array.config_vvmSmsFilterRegexes}, the SMS will
-     * still be dropped and a {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} with {@link
-     * VoicemailContract#EXTRA_VOICEMAIL_SMS_MESSAGE_BODY} will be sent.
+     * still be dropped and a {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} will be sent.
      *
      * @return true if the SMS has been parsed to be a visual voicemail SMS and should be dropped
      */
@@ -60,16 +69,19 @@
         TelephonyManager telephonyManager =
                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
 
-        // TODO: select client package.
-        String vvmClientPackage = SYSTEM_VVM_CLIENT_PACKAGE;
-
         VisualVoicemailSmsFilterSettings settings =
-                telephonyManager.getVisualVoicemailSmsFilterSettings(vvmClientPackage, subId);
+                telephonyManager.getActiveVisualVoicemailSmsFilterSettings(subId);
         if (settings == null) {
             return false;
         }
         // TODO: filter base on originating number and destination port.
 
+        PhoneAccountHandle phoneAccountHandle = phoneAccountHandleFromSubId(context, subId);
+        if (phoneAccountHandle == null) {
+            Log.e(TAG, "Unable to convert subId " + subId + " to PhoneAccountHandle");
+            return false;
+        }
+
         String messageBody = getFullMessage(pdus, format);
 
         if(messageBody == null){
@@ -80,7 +92,7 @@
             WrappedMessageData messageData = VisualVoicemailSmsParser
                 .parseAlternativeFormat(asciiMessage);
             if (messageData != null) {
-                sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData, null);
+                sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
             }
             // Confidence for what the message actually is is low. Don't remove the message and let
             // system decide. Usually because it is not parsable it will be dropped.
@@ -90,7 +102,7 @@
         WrappedMessageData messageData = VisualVoicemailSmsParser
             .parse(clientPrefix, messageBody);
         if (messageData != null) {
-            sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData, null);
+            sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
             return true;
         }
 
@@ -106,7 +118,7 @@
             if (pattern.matcher(messageBody).matches()) {
                 Log.w(TAG, "Incoming SMS matches pattern " + pattern + " but has illegal format, "
                     + "still dropping as VVM SMS");
-                sendVvmSmsBroadcast(context, vvmClientPackage, subId, null, messageBody);
+                sendVvmSmsBroadcast(context, phoneAccountHandle, null, messageBody);
                 return true;
             }
         }
@@ -133,19 +145,21 @@
         }
     }
 
-    private static void sendVvmSmsBroadcast(Context context, String vvmClientPackage, int subId,
+    private static void sendVvmSmsBroadcast(Context context, PhoneAccountHandle phoneAccountHandle,
         @Nullable WrappedMessageData messageData, @Nullable String messageBody) {
         Log.i(TAG, "VVM SMS received");
         Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
+        VisualVoicemailSms.Builder builder = new VisualVoicemailSms.Builder();
         if (messageData != null) {
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix);
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_FIELDS, messageData.fields);
+            builder.setPrefix(messageData.prefix);
+            builder.setFields(messageData.fields);
         }
         if (messageBody != null) {
-            intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_MESSAGE_BODY, messageBody);
+            builder.setMessageBody(messageBody);
         }
-        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId);
-        intent.setPackage(vvmClientPackage);
+        builder.setPhoneAccountHandle(phoneAccountHandle);
+        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS, builder.build());
+        intent.setPackage(TELEPHONY_SERVICE_PACKAGE);
         context.sendBroadcast(intent);
     }
 
@@ -177,4 +191,17 @@
         }
         return builder.toString();
     }
+
+    @Nullable
+    private static PhoneAccountHandle phoneAccountHandleFromSubId(Context context, int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            return null;
+        }
+        int phoneId = SubscriptionManager.getPhoneId(subId);
+        if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) {
+            return null;
+        }
+        return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT,
+                PhoneFactory.getPhone(phoneId).getFullIccSerialNumber());
+    }
 }
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
index b2893d0..ab76f98 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
@@ -28,6 +28,7 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ResultReceiver;
 import android.telephony.Rlog;
 
 import java.util.regex.Pattern;
@@ -207,6 +208,11 @@
         return false;
     }
 
+    @Override
+    public String getDialString() {
+        return null;
+    }
+
     /** Process a MMI PUK code */
     public void
     processCode() {
@@ -368,4 +374,8 @@
         mPhone.onMMIDone(this);
     }
 
+    @Override
+    public ResultReceiver getUssdCallbackReceiver() {
+        return null;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessage.java b/src/java/com/android/internal/telephony/cdma/SmsMessage.java
deleted file mode 100644
index 729062b..0000000
--- a/src/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ /dev/null
@@ -1,1058 +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 com.android.internal.telephony.cdma;
-
-import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.os.Parcel;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.Rlog;
-import android.util.Log;
-import android.text.TextUtils;
-import android.content.res.Resources;
-
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.cdma.sms.BearerData;
-import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
-import com.android.internal.telephony.cdma.sms.SmsEnvelope;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.HexDump;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * TODO(cleanup): these constants are disturbing... are they not just
- * different interpretations on one number?  And if we did not have
- * terrible class name overlap, they would not need to be directly
- * imported like this.  The class in this file could just as well be
- * named CdmaSmsMessage, could it not?
- */
-
-/**
- * TODO(cleanup): internally returning null in many places makes
- * debugging very hard (among many other reasons) and should be made
- * more meaningful (replaced with exceptions for example).  Null
- * returns should only occur at the very outside of the module/class
- * scope.
- */
-
-/**
- * A Short Message Service message.
- *
- */
-public class SmsMessage extends SmsMessageBase {
-    static final String LOG_TAG = "SmsMessage";
-    static private final String LOGGABLE_TAG = "CDMA:SMS";
-    private static final boolean VDBG = false;
-
-    private final static byte TELESERVICE_IDENTIFIER                    = 0x00;
-    private final static byte SERVICE_CATEGORY                          = 0x01;
-    private final static byte ORIGINATING_ADDRESS                       = 0x02;
-    private final static byte ORIGINATING_SUB_ADDRESS                   = 0x03;
-    private final static byte DESTINATION_ADDRESS                       = 0x04;
-    private final static byte DESTINATION_SUB_ADDRESS                   = 0x05;
-    private final static byte BEARER_REPLY_OPTION                       = 0x06;
-    private final static byte CAUSE_CODES                               = 0x07;
-    private final static byte BEARER_DATA                               = 0x08;
-
-    /**
-     *  Status of a previously submitted SMS.
-     *  This field applies to SMS Delivery Acknowledge messages. 0 indicates success;
-     *  Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0.
-     *  See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values.
-     */
-    private int status;
-
-    /** Specifies if a return of an acknowledgment is requested for send SMS */
-    private static final int RETURN_NO_ACK  = 0;
-    private static final int RETURN_ACK     = 1;
-
-    private SmsEnvelope mEnvelope;
-    private BearerData mBearerData;
-
-    public static class SubmitPdu extends SubmitPduBase {
-    }
-
-    /**
-     * Create an SmsMessage from a raw PDU.
-     * Note: In CDMA the PDU is just a byte representation of the received Sms.
-     */
-    public static SmsMessage createFromPdu(byte[] pdu) {
-        SmsMessage msg = new SmsMessage();
-
-        try {
-            msg.parsePdu(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
-            return null;
-        } catch (OutOfMemoryError e) {
-            Log.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e);
-            return null;
-        }
-    }
-
-    /**
-     *  Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
-     *  Note: Only primitive fields are set.
-     */
-    public static SmsMessage newFromRil(CdmaSmsMessage cdmaSmsMessage) {
-        // Note: Parcel.readByte actually reads one Int and masks to byte
-        SmsMessage msg = new SmsMessage();
-        SmsEnvelope env = new SmsEnvelope();
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
-        byte[] data;
-        byte count;
-        int countInt;
-        int addressDigitMode;
-
-        //currently not supported by the modem-lib: env.mMessageType
-        env.teleService = cdmaSmsMessage.teleserviceId;
-
-        if (cdmaSmsMessage.isServicePresent) {
-            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
-        }
-        else {
-            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
-                // assume type ACK
-                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
-            } else {
-                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
-            }
-        }
-        env.serviceCategory = cdmaSmsMessage.serviceCategory;
-
-        // address
-        addressDigitMode = cdmaSmsMessage.address.digitMode;
-        addr.digitMode = (byte) (0xFF & addressDigitMode);
-        addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
-        addr.ton = cdmaSmsMessage.address.numberType;
-        addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
-        count = (byte) cdmaSmsMessage.address.digits.size();
-        addr.numberOfDigits = count;
-        data = new byte[count];
-        for (int index=0; index < count; index++) {
-            data[index] = cdmaSmsMessage.address.digits.get(index);
-
-            // convert the value if it is 4-bit DTMF to 8 bit
-            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
-                data[index] = msg.convertDtmfToAscii(data[index]);
-            }
-        }
-
-        addr.origBytes = data;
-
-        subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
-        subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
-        count = (byte) cdmaSmsMessage.subAddress.digits.size();
-
-        if (count < 0) {
-            count = 0;
-        }
-
-        // p_cur->sSubAddress.digits[digitCount] :
-
-        data = new byte[count];
-
-        for (int index = 0; index < count; ++index) {
-            data[index] = cdmaSmsMessage.subAddress.digits.get(index);
-        }
-
-        subaddr.origBytes = data;
-
-        /* currently not supported by the modem-lib:
-            env.bearerReply
-            env.replySeqNo
-            env.errorClass
-            env.causeCode
-        */
-
-        // bearer data
-        countInt = cdmaSmsMessage.bearerData.size();
-        if (countInt < 0) {
-            countInt = 0;
-        }
-
-        data = new byte[countInt];
-        for (int index=0; index < countInt; index++) {
-            data[index] = cdmaSmsMessage.bearerData.get(index);
-        }
-        // BD gets further decoded when accessed in SMSDispatcher
-        env.bearerData = data;
-
-        // link the the filled objects to the SMS
-        env.origAddress = addr;
-        env.origSubaddress = subaddr;
-        msg.mOriginatingAddress = addr;
-        msg.mEnvelope = env;
-
-        // create byte stream representation for transportation through the layers.
-        msg.createPdu();
-
-        return msg;
-    }
-
-    /**
-     * Create an SmsMessage from an SMS EF record.
-     *
-     * @param index Index of SMS record. This should be index in ArrayList
-     *              returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1.
-     * @param data Record data.
-     * @return An SmsMessage representing the record.
-     *
-     * @hide
-     */
-    public static SmsMessage createFromEfRecord(int index, byte[] data) {
-        try {
-            SmsMessage msg = new SmsMessage();
-
-            msg.mIndexOnIcc = index;
-
-            // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
-            // or STORED_UNSENT
-            // See 3GPP2 C.S0023 3.4.27
-            if ((data[0] & 1) == 0) {
-                Rlog.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record");
-                return null;
-            } else {
-                msg.mStatusOnIcc = data[0] & 0x07;
-            }
-
-            // Second byte is the MSG_LEN, length of the message
-            // See 3GPP2 C.S0023 3.4.27
-            int size = data[1];
-
-            // Note: Data may include trailing FF's.  That's OK; message
-            // should still parse correctly.
-            byte[] pdu = new byte[size];
-            System.arraycopy(data, 2, pdu, 0, size);
-            // the message has to be parsed before it can be displayed
-            // see gsm.SmsMessage
-            msg.parsePduFromEfRecord(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
-            return null;
-        }
-
-    }
-
-    /**
-     * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
-    public static int getTPLayerLengthForPDU(String pdu) {
-        Rlog.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode.");
-        return 0;
-    }
-
-    /**
-     * TODO(cleanup): why do getSubmitPdu methods take an scAddr input
-     * and do nothing with it?  GSM allows us to specify a SC (eg,
-     * when responding to an SMS that explicitly requests the response
-     * is sent to a specific SC), or pass null to use the default
-     * value.  Is there no similar notion in CDMA? Or do we just not
-     * have it hooked up?
-     */
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message
-     *
-     * @param scAddr                Service Centre address.  Null means use default.
-     * @param destAddr              Address of the recipient.
-     * @param message               String representation of the message payload.
-     * @param statusReportRequested Indicates whether a report is requested for this message.
-     * @param smsHeader             Array containing the data for the User Data Header, preceded
-     *                              by the Element Identifiers.
-     * @return a <code>SubmitPdu</code> containing the encoded SC
-     *         address, if applicable, and the encoded message.
-     *         Returns null on encode error.
-     * @hide
-     */
-    public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
-            boolean statusReportRequested, SmsHeader smsHeader) {
-
-        /**
-         * TODO(cleanup): Do we really want silent failure like this?
-         * Would it not be much more reasonable to make sure we don't
-         * call this function if we really want nothing done?
-         */
-        if (message == null || destAddr == null) {
-            return null;
-        }
-
-        UserData uData = new UserData();
-        uData.payloadStr = message;
-        uData.userDataHeader = smsHeader;
-        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a data message to a destination address and port.
-     *
-     * @param scAddr Service Centre address. null == use default
-     * @param destAddr the address of the destination for the message
-     * @param destPort 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 scAddr, String destAddr, int destPort,
-            byte[] data, boolean statusReportRequested) {
-
-        /**
-         * TODO(cleanup): this is not a general-purpose SMS creation
-         * method, but rather something specialized to messages
-         * containing OCTET encoded (meaning non-human-readable) user
-         * data.  The name should reflect that, and not just overload.
-         */
-
-        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
-        portAddrs.destPort = destPort;
-        portAddrs.origPort = 0;
-        portAddrs.areEightBits = false;
-
-        SmsHeader smsHeader = new SmsHeader();
-        smsHeader.portAddrs = portAddrs;
-
-        UserData uData = new UserData();
-        uData.userDataHeader = smsHeader;
-        uData.msgEncoding = UserData.ENCODING_OCTET;
-        uData.msgEncodingSet = true;
-        uData.payload = data;
-
-        return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
-     *
-     * @param destAddr the address of the destination for the message
-     * @param userData the data for the message
-     * @param statusReportRequested Indicates whether a report is requested for this 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 destAddr, UserData userData,
-            boolean statusReportRequested) {
-        return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
-    }
-
-    /**
-     * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
-    @Override
-    public int getProtocolIdentifier() {
-        Rlog.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode.");
-        // (3GPP TS 23.040): "no interworking, but SME to SME protocol":
-        return 0;
-    }
-
-    /**
-     * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
-    @Override
-    public boolean isReplace() {
-        Rlog.w(LOG_TAG, "isReplace: is not supported in CDMA mode.");
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
-    @Override
-    public boolean isCphsMwiMessage() {
-        Rlog.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode.");
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isMWIClearMessage() {
-        return ((mBearerData != null) && (mBearerData.numberOfMessages == 0));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isMWISetMessage() {
-        return ((mBearerData != null) && (mBearerData.numberOfMessages > 0));
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isMwiDontStore() {
-        return ((mBearerData != null) &&
-                (mBearerData.numberOfMessages > 0) &&
-                (mBearerData.userData == null));
-    }
-
-    /**
-     * Returns the status for a previously submitted message.
-     * For not interfering with status codes from GSM, this status code is
-     * shifted to the bits 31-16.
-     */
-    @Override
-    public int getStatus() {
-        return (status << 16);
-    }
-
-    /** Return true iff the bearer data message type is DELIVERY_ACK. */
-    @Override
-    public boolean isStatusReportMessage() {
-        return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
-    }
-
-    /**
-     * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
-    @Override
-    public boolean isReplyPathPresent() {
-        Rlog.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode.");
-        return false;
-    }
-
-    /**
-     * Calculate the number of septets needed to encode the message.
-     *
-     * @param messageBody the message to encode
-     * @param use7bitOnly ignore (but still count) illegal characters if true
-     * @param isEntireMsg indicates if this is entire msg or a segment in multipart msg
-     * @return TextEncodingDetails
-     */
-    public static TextEncodingDetails calculateLength(CharSequence messageBody,
-            boolean use7bitOnly, boolean isEntireMsg) {
-        CharSequence newMsgBody = null;
-        Resources r = Resources.getSystem();
-        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
-            newMsgBody  = Sms7BitEncodingTranslator.translate(messageBody);
-        }
-        if (TextUtils.isEmpty(newMsgBody)) {
-            newMsgBody = messageBody;
-        }
-        return BearerData.calcTextEncodingDetails(newMsgBody, use7bitOnly, isEntireMsg);
-    }
-
-    /**
-     * Returns the teleservice type of the message.
-     * @return the teleservice:
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}
-    */
-    public int getTeleService() {
-        return mEnvelope.teleService;
-    }
-
-    /**
-     * Returns the message type of the message.
-     * @return the message type:
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_POINT_TO_POINT},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST},
-     *  {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE},
-    */
-    public int getMessageType() {
-        // NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs.
-        // Use the service category parameter to detect CMAS and other cell broadcast messages.
-        if (mEnvelope.serviceCategory != 0) {
-            return SmsEnvelope.MESSAGE_TYPE_BROADCAST;
-        } else {
-            return SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
-        }
-    }
-
-    /**
-     * Decodes pdu to an empty SMS object.
-     * In the CDMA case the pdu is just an internal byte stream representation
-     * of the SMS Java-object.
-     * @see #createPdu()
-     */
-    private void parsePdu(byte[] pdu) {
-        ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
-        DataInputStream dis = new DataInputStream(bais);
-        int length;
-        int bearerDataLength;
-        SmsEnvelope env = new SmsEnvelope();
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-
-        try {
-            env.messageType = dis.readInt();
-            env.teleService = dis.readInt();
-            env.serviceCategory = dis.readInt();
-
-            addr.digitMode = dis.readByte();
-            addr.numberMode = dis.readByte();
-            addr.ton = dis.readByte();
-            addr.numberPlan = dis.readByte();
-
-            length = dis.readUnsignedByte();
-            addr.numberOfDigits = length;
-
-            // sanity check on the length
-            if (length > pdu.length) {
-                throw new RuntimeException(
-                        "createFromPdu: Invalid pdu, addr.numberOfDigits " + length
-                        + " > pdu len " + pdu.length);
-            }
-            addr.origBytes = new byte[length];
-            dis.read(addr.origBytes, 0, length); // digits
-
-            env.bearerReply = dis.readInt();
-            // CauseCode values:
-            env.replySeqNo = dis.readByte();
-            env.errorClass = dis.readByte();
-            env.causeCode = dis.readByte();
-
-            //encoded BearerData:
-            bearerDataLength = dis.readInt();
-            // sanity check on the length
-            if (bearerDataLength > pdu.length) {
-                throw new RuntimeException(
-                        "createFromPdu: Invalid pdu, bearerDataLength " + bearerDataLength
-                        + " > pdu len " + pdu.length);
-            }
-            env.bearerData = new byte[bearerDataLength];
-            dis.read(env.bearerData, 0, bearerDataLength);
-            dis.close();
-        } catch (IOException ex) {
-            throw new RuntimeException(
-                    "createFromPdu: conversion from byte array to object failed: " + ex, ex);
-        } catch (Exception ex) {
-            Rlog.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex);
-        }
-
-        // link the filled objects to this SMS
-        mOriginatingAddress = addr;
-        env.origAddress = addr;
-        mEnvelope = env;
-        mPdu = pdu;
-
-        parseSms();
-    }
-
-    /**
-     * Decodes 3GPP2 sms stored in CSIM/RUIM cards As per 3GPP2 C.S0015-0
-     */
-    private void parsePduFromEfRecord(byte[] pdu) {
-        ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
-        DataInputStream dis = new DataInputStream(bais);
-        SmsEnvelope env = new SmsEnvelope();
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        CdmaSmsSubaddress subAddr = new CdmaSmsSubaddress();
-
-        try {
-            env.messageType = dis.readByte();
-
-            while (dis.available() > 0) {
-                int parameterId = dis.readByte();
-                int parameterLen = dis.readUnsignedByte();
-                byte[] parameterData = new byte[parameterLen];
-
-                switch (parameterId) {
-                    case TELESERVICE_IDENTIFIER:
-                        /*
-                         * 16 bit parameter that identifies which upper layer
-                         * service access point is sending or should receive
-                         * this message
-                         */
-                        env.teleService = dis.readUnsignedShort();
-                        Rlog.i(LOG_TAG, "teleservice = " + env.teleService);
-                        break;
-                    case SERVICE_CATEGORY:
-                        /*
-                         * 16 bit parameter that identifies type of service as
-                         * in 3GPP2 C.S0015-0 Table 3.4.3.2-1
-                         */
-                        env.serviceCategory = dis.readUnsignedShort();
-                        break;
-                    case ORIGINATING_ADDRESS:
-                    case DESTINATION_ADDRESS:
-                        dis.read(parameterData, 0, parameterLen);
-                        BitwiseInputStream addrBis = new BitwiseInputStream(parameterData);
-                        addr.digitMode = addrBis.read(1);
-                        addr.numberMode = addrBis.read(1);
-                        int numberType = 0;
-                        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-                            numberType = addrBis.read(3);
-                            addr.ton = numberType;
-
-                            if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK)
-                                addr.numberPlan = addrBis.read(4);
-                        }
-
-                        addr.numberOfDigits = addrBis.read(8);
-
-                        byte[] data = new byte[addr.numberOfDigits];
-                        byte b = 0x00;
-
-                        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
-                            /* As per 3GPP2 C.S0005-0 Table 2.7.1.3.2.4-4 */
-                            for (int index = 0; index < addr.numberOfDigits; index++) {
-                                b = (byte) (0xF & addrBis.read(4));
-                                // convert the value if it is 4-bit DTMF to 8
-                                // bit
-                                data[index] = convertDtmfToAscii(b);
-                            }
-                        } else if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-                            if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK) {
-                                for (int index = 0; index < addr.numberOfDigits; index++) {
-                                    b = (byte) (0xFF & addrBis.read(8));
-                                    data[index] = b;
-                                }
-
-                            } else if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK) {
-                                if (numberType == 2)
-                                    Rlog.e(LOG_TAG, "TODO: Originating Addr is email id");
-                                else
-                                    Rlog.e(LOG_TAG,
-                                          "TODO: Originating Addr is data network address");
-                            } else {
-                                Rlog.e(LOG_TAG, "Originating Addr is of incorrect type");
-                            }
-                        } else {
-                            Rlog.e(LOG_TAG, "Incorrect Digit mode");
-                        }
-                        addr.origBytes = data;
-                        Rlog.i(LOG_TAG, "Originating Addr=" + addr.toString());
-                        break;
-                    case ORIGINATING_SUB_ADDRESS:
-                    case DESTINATION_SUB_ADDRESS:
-                        dis.read(parameterData, 0, parameterLen);
-                        BitwiseInputStream subAddrBis = new BitwiseInputStream(parameterData);
-                        subAddr.type = subAddrBis.read(3);
-                        subAddr.odd = subAddrBis.readByteArray(1)[0];
-                        int subAddrLen = subAddrBis.read(8);
-                        byte[] subdata = new byte[subAddrLen];
-                        for (int index = 0; index < subAddrLen; index++) {
-                            b = (byte) (0xFF & subAddrBis.read(4));
-                            // convert the value if it is 4-bit DTMF to 8 bit
-                            subdata[index] = convertDtmfToAscii(b);
-                        }
-                        subAddr.origBytes = subdata;
-                        break;
-                    case BEARER_REPLY_OPTION:
-                        dis.read(parameterData, 0, parameterLen);
-                        BitwiseInputStream replyOptBis = new BitwiseInputStream(parameterData);
-                        env.bearerReply = replyOptBis.read(6);
-                        break;
-                    case CAUSE_CODES:
-                        dis.read(parameterData, 0, parameterLen);
-                        BitwiseInputStream ccBis = new BitwiseInputStream(parameterData);
-                        env.replySeqNo = ccBis.readByteArray(6)[0];
-                        env.errorClass = ccBis.readByteArray(2)[0];
-                        if (env.errorClass != 0x00)
-                            env.causeCode = ccBis.readByteArray(8)[0];
-                        break;
-                    case BEARER_DATA:
-                        dis.read(parameterData, 0, parameterLen);
-                        env.bearerData = parameterData;
-                        break;
-                    default:
-                        throw new Exception("unsupported parameterId (" + parameterId + ")");
-                }
-            }
-            bais.close();
-            dis.close();
-        } catch (Exception ex) {
-            Rlog.e(LOG_TAG, "parsePduFromEfRecord: conversion from pdu to SmsMessage failed" + ex);
-        }
-
-        // link the filled objects to this SMS
-        mOriginatingAddress = addr;
-        env.origAddress = addr;
-        env.origSubaddress = subAddr;
-        mEnvelope = env;
-        mPdu = pdu;
-
-        parseSms();
-    }
-
-    /**
-     * Parses a SMS message from its BearerData stream. (mobile-terminated only)
-     */
-    public void parseSms() {
-        // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
-        // It contains only an 8-bit number with the number of messages waiting
-        if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) {
-            mBearerData = new BearerData();
-            if (mEnvelope.bearerData != null) {
-                mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0];
-            }
-            if (VDBG) {
-                Rlog.d(LOG_TAG, "parseSms: get MWI " +
-                      Integer.toString(mBearerData.numberOfMessages));
-            }
-            return;
-        }
-        mBearerData = BearerData.decode(mEnvelope.bearerData);
-        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
-            Rlog.d(LOG_TAG, "MT raw BearerData = '" +
-                      HexDump.toHexString(mEnvelope.bearerData) + "'");
-            Rlog.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData);
-        }
-        mMessageRef = mBearerData.messageId;
-        if (mBearerData.userData != null) {
-            mUserData = mBearerData.userData.payload;
-            mUserDataHeader = mBearerData.userData.userDataHeader;
-            mMessageBody = mBearerData.userData.payloadStr;
-        }
-
-        if (mOriginatingAddress != null) {
-            mOriginatingAddress.address = new String(mOriginatingAddress.origBytes);
-            if (mOriginatingAddress.ton == CdmaSmsAddress.TON_INTERNATIONAL_OR_IP) {
-                if (mOriginatingAddress.address.charAt(0) != '+') {
-                    mOriginatingAddress.address = "+" + mOriginatingAddress.address;
-                }
-            }
-            if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: "
-                    + mOriginatingAddress.address);
-        }
-
-        if (mBearerData.msgCenterTimeStamp != null) {
-            mScTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true);
-        }
-
-        if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);
-
-        // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1)
-        if (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) {
-            // The BearerData MsgStatus subparameter should only be
-            // included for DELIVERY_ACK messages.  If it occurred for
-            // other messages, it would be unclear what the status
-            // being reported refers to.  The MsgStatus subparameter
-            // is primarily useful to indicate error conditions -- a
-            // message without this subparameter is assumed to
-            // indicate successful delivery (status == 0).
-            if (! mBearerData.messageStatusSet) {
-                Rlog.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" +
-                        (mUserData == null ? "also missing" : "does have") +
-                        " userData).");
-                status = 0;
-            } else {
-                status = mBearerData.errorClass << 8;
-                status |= mBearerData.messageStatus;
-            }
-        } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) {
-            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
-        }
-
-        if (mMessageBody != null) {
-            if (VDBG) Rlog.v(LOG_TAG, "SMS message body: '" + mMessageBody + "'");
-            parseMessageBody();
-        } else if ((mUserData != null) && VDBG) {
-            Rlog.v(LOG_TAG, "SMS payload: '" + IccUtils.bytesToHexString(mUserData) + "'");
-        }
-    }
-
-    /**
-     * Parses a broadcast SMS, possibly containing a CMAS alert.
-     */
-    public SmsCbMessage parseBroadcastSms() {
-        BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory);
-        if (bData == null) {
-            Rlog.w(LOG_TAG, "BearerData.decode() returned null");
-            return null;
-        }
-
-        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
-            Rlog.d(LOG_TAG, "MT raw BearerData = " + HexDump.toHexString(mEnvelope.bearerData));
-        }
-
-        String plmn = TelephonyManager.getDefault().getNetworkOperator();
-        SmsCbLocation location = new SmsCbLocation(plmn);
-
-        return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2,
-                SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location,
-                mEnvelope.serviceCategory, bData.getLanguage(), bData.userData.payloadStr,
-                bData.priority, null, bData.cmasWarningInfo);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public SmsConstants.MessageClass getMessageClass() {
-        if (BearerData.DISPLAY_MODE_IMMEDIATE == mBearerData.displayMode ) {
-            return SmsConstants.MessageClass.CLASS_0;
-        } else {
-            return SmsConstants.MessageClass.UNKNOWN;
-        }
-    }
-
-    /**
-     * Calculate the next message id, starting at 1 and iteratively
-     * incrementing within the range 1..65535 remembering the state
-     * via a persistent system property.  (See C.S0015-B, v2.0,
-     * 4.3.1.5) Since this routine is expected to be accessed via via
-     * binder-call, and hence should be thread-safe, it has been
-     * synchronized.
-     */
-    public synchronized static int getNextMessageId() {
-        // Testing and dialog with partners has indicated that
-        // msgId==0 is (sometimes?) treated specially by lower levels.
-        // Specifically, the ID is not preserved for delivery ACKs.
-        // Hence, avoid 0 -- constraining the range to 1..65535.
-        int msgId = SystemProperties.getInt(TelephonyProperties.PROPERTY_CDMA_MSG_ID, 1);
-        String nextMsgId = Integer.toString((msgId % 0xFFFF) + 1);
-        try{
-            SystemProperties.set(TelephonyProperties.PROPERTY_CDMA_MSG_ID, nextMsgId);
-            if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
-                Rlog.d(LOG_TAG, "next " + TelephonyProperties.PROPERTY_CDMA_MSG_ID + " = " + nextMsgId);
-                Rlog.d(LOG_TAG, "readback gets " +
-                        SystemProperties.get(TelephonyProperties.PROPERTY_CDMA_MSG_ID));
-            }
-        } catch(RuntimeException ex) {
-            Rlog.e(LOG_TAG, "set nextMessage ID failed: " + ex);
-        }
-        return msgId;
-    }
-
-    /**
-     * Creates BearerData and Envelope from parameters for a Submit SMS.
-     * @return byte stream for SubmitPdu.
-     */
-    private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
-            UserData userData) {
-
-        /**
-         * TODO(cleanup): give this function a more meaningful name.
-         */
-
-        /**
-         * TODO(cleanup): Make returning null from the getSubmitPdu
-         * variations meaningful -- clean up the error feedback
-         * mechanism, and avoid null pointer exceptions.
-         */
-
-        /**
-         * North America Plus Code :
-         * Convert + code to 011 and dial out for international SMS
-         */
-        CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
-                PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(destAddrStr));
-        if (destAddr == null) return null;
-
-        BearerData bearerData = new BearerData();
-        bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
-
-        bearerData.messageId = getNextMessageId();
-
-        bearerData.deliveryAckReq = statusReportRequested;
-        bearerData.userAckReq = false;
-        bearerData.readAckReq = false;
-        bearerData.reportReq = false;
-
-        bearerData.userData = userData;
-
-        byte[] encodedBearerData = BearerData.encode(bearerData);
-        if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
-            Rlog.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
-            Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
-        }
-        if (encodedBearerData == null) return null;
-
-        int teleservice = bearerData.hasUserDataHeader ?
-                SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
-
-        SmsEnvelope envelope = new SmsEnvelope();
-        envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
-        envelope.teleService = teleservice;
-        envelope.destAddress = destAddr;
-        envelope.bearerReply = RETURN_ACK;
-        envelope.bearerData = encodedBearerData;
-
-        /**
-         * TODO(cleanup): envelope looks to be a pointless class, get
-         * rid of it.  Also -- most of the envelope fields set here
-         * are ignored, why?
-         */
-
-        try {
-            /**
-             * TODO(cleanup): reference a spec and get rid of the ugly comments
-             */
-            ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
-            DataOutputStream dos = new DataOutputStream(baos);
-            dos.writeInt(envelope.teleService);
-            dos.writeInt(0); //servicePresent
-            dos.writeInt(0); //serviceCategory
-            dos.write(destAddr.digitMode);
-            dos.write(destAddr.numberMode);
-            dos.write(destAddr.ton); // number_type
-            dos.write(destAddr.numberPlan);
-            dos.write(destAddr.numberOfDigits);
-            dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
-            // Subaddress is not supported.
-            dos.write(0); //subaddressType
-            dos.write(0); //subaddr_odd
-            dos.write(0); //subaddr_nbr_of_digits
-            dos.write(encodedBearerData.length);
-            dos.write(encodedBearerData, 0, encodedBearerData.length);
-            dos.close();
-
-            SubmitPdu pdu = new SubmitPdu();
-            pdu.encodedMessage = baos.toByteArray();
-            pdu.encodedScAddress = null;
-            return pdu;
-        } catch(IOException ex) {
-            Rlog.e(LOG_TAG, "creating SubmitPdu failed: " + ex);
-        }
-        return null;
-    }
-
-    /**
-     * Creates byte array (pseudo pdu) from SMS object.
-     * Note: Do not call this method more than once per object!
-     */
-    private void createPdu() {
-        SmsEnvelope env = mEnvelope;
-        CdmaSmsAddress addr = env.origAddress;
-        ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
-        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
-
-        try {
-            dos.writeInt(env.messageType);
-            dos.writeInt(env.teleService);
-            dos.writeInt(env.serviceCategory);
-
-            dos.writeByte(addr.digitMode);
-            dos.writeByte(addr.numberMode);
-            dos.writeByte(addr.ton);
-            dos.writeByte(addr.numberPlan);
-            dos.writeByte(addr.numberOfDigits);
-            dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
-
-            dos.writeInt(env.bearerReply);
-            // CauseCode values:
-            dos.writeByte(env.replySeqNo);
-            dos.writeByte(env.errorClass);
-            dos.writeByte(env.causeCode);
-            //encoded BearerData:
-            dos.writeInt(env.bearerData.length);
-            dos.write(env.bearerData, 0, env.bearerData.length);
-            dos.close();
-
-            /**
-             * TODO(cleanup) -- The mPdu field is managed in
-             * a fragile manner, and it would be much nicer if
-             * accessing the serialized representation used a less
-             * fragile mechanism.  Maybe the getPdu method could
-             * generate a representation if there was not yet one?
-             */
-
-            mPdu = baos.toByteArray();
-        } catch (IOException ex) {
-            Rlog.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
-        }
-    }
-
-    /**
-     * Converts a 4-Bit DTMF encoded symbol from the calling address number to ASCII character
-     */
-    private byte convertDtmfToAscii(byte dtmfDigit) {
-        byte asciiDigit;
-
-        switch (dtmfDigit) {
-        case  0: asciiDigit = 68; break; // 'D'
-        case  1: asciiDigit = 49; break; // '1'
-        case  2: asciiDigit = 50; break; // '2'
-        case  3: asciiDigit = 51; break; // '3'
-        case  4: asciiDigit = 52; break; // '4'
-        case  5: asciiDigit = 53; break; // '5'
-        case  6: asciiDigit = 54; break; // '6'
-        case  7: asciiDigit = 55; break; // '7'
-        case  8: asciiDigit = 56; break; // '8'
-        case  9: asciiDigit = 57; break; // '9'
-        case 10: asciiDigit = 48; break; // '0'
-        case 11: asciiDigit = 42; break; // '*'
-        case 12: asciiDigit = 35; break; // '#'
-        case 13: asciiDigit = 65; break; // 'A'
-        case 14: asciiDigit = 66; break; // 'B'
-        case 15: asciiDigit = 67; break; // 'C'
-        default:
-            asciiDigit = 32; // Invalid DTMF code
-            break;
-        }
-
-        return asciiDigit;
-    }
-
-    /** This function  shall be called to get the number of voicemails.
-     * @hide
-     */
-    public int getNumOfVoicemails() {
-        return mBearerData.numberOfMessages;
-    }
-
-    /**
-     * Returns a byte array that can be use to uniquely identify a received SMS message.
-     * C.S0015-B  4.3.1.6 Unique Message Identification.
-     *
-     * @return byte array uniquely identifying the message.
-     * @hide
-     */
-    public byte[] getIncomingSmsFingerprint() {
-        ByteArrayOutputStream output = new ByteArrayOutputStream();
-
-        output.write(mEnvelope.serviceCategory);
-        output.write(mEnvelope.teleService);
-        output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
-        output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
-        output.write(mEnvelope.origSubaddress.origBytes, 0,
-                mEnvelope.origSubaddress.origBytes.length);
-
-        return output.toByteArray();
-    }
-
-    /**
-     * Returns the list of service category program data, if present.
-     * @return a list of CdmaSmsCbProgramData objects, or null if not present
-     * @hide
-     */
-    public ArrayList<CdmaSmsCbProgramData> getSmsCbProgramData() {
-        return mBearerData.serviceCategoryProgramData;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
new file mode 100644
index 0000000..4ac2dea
--- /dev/null
+++ b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma;
+
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.os.Parcel;
+import android.os.SystemProperties;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
+import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+import android.telephony.Rlog;
+import android.util.Log;
+import android.text.TextUtils;
+import android.content.res.Resources;
+
+import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.SmsConstants;
+import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.cdma.sms.BearerData;
+import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
+import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.util.BitwiseInputStream;
+import com.android.internal.util.HexDump;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * A Factory class to convert from RIL to Framework SMS
+ *
+ */
+public class SmsMessageConverter {
+    static final String LOG_TAG = "SmsMessageConverter";
+    static private final String LOGGABLE_TAG = "CDMA:SMS";
+    private static final boolean VDBG = false;
+
+    /**
+     *  Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
+     *  Note: Only primitive fields are set.
+     */
+    public static SmsMessage newCdmaSmsMessageFromRil(
+            CdmaSmsMessage cdmaSmsMessage) {
+        // Note: Parcel.readByte actually reads one Int and masks to byte
+        SmsEnvelope env = new SmsEnvelope();
+        CdmaSmsAddress addr = new CdmaSmsAddress();
+        CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
+        byte[] data;
+        byte count;
+        int countInt;
+        int addressDigitMode;
+
+        //currently not supported by the modem-lib: env.mMessageType
+        env.teleService = cdmaSmsMessage.teleserviceId;
+
+        if (cdmaSmsMessage.isServicePresent) {
+            env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
+        }
+        else {
+            if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
+                // assume type ACK
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
+            } else {
+                env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
+            }
+        }
+        env.serviceCategory = cdmaSmsMessage.serviceCategory;
+
+        // address
+        addressDigitMode = cdmaSmsMessage.address.digitMode;
+        addr.digitMode = (byte) (0xFF & addressDigitMode);
+        addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
+        addr.ton = cdmaSmsMessage.address.numberType;
+        addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
+        count = (byte) cdmaSmsMessage.address.digits.size();
+        addr.numberOfDigits = count;
+        data = new byte[count];
+        for (int index=0; index < count; index++) {
+            data[index] = cdmaSmsMessage.address.digits.get(index);
+
+            // convert the value if it is 4-bit DTMF to 8 bit
+            if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
+                data[index] = SmsMessage.convertDtmfToAscii(data[index]);
+            }
+        }
+
+        addr.origBytes = data;
+
+        subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
+        subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
+        count = (byte) cdmaSmsMessage.subAddress.digits.size();
+
+        if (count < 0) {
+            count = 0;
+        }
+
+        // p_cur->sSubAddress.digits[digitCount] :
+
+        data = new byte[count];
+
+        for (int index = 0; index < count; ++index) {
+            data[index] = cdmaSmsMessage.subAddress.digits.get(index);
+        }
+
+        subaddr.origBytes = data;
+
+        /* currently not supported by the modem-lib:
+            env.bearerReply
+            env.replySeqNo
+            env.errorClass
+            env.causeCode
+        */
+
+        // bearer data
+        countInt = cdmaSmsMessage.bearerData.size();
+        if (countInt < 0) {
+            countInt = 0;
+        }
+
+        data = new byte[countInt];
+        for (int index=0; index < countInt; index++) {
+            data[index] = cdmaSmsMessage.bearerData.get(index);
+        }
+        // BD gets further decoded when accessed in SMSDispatcher
+        env.bearerData = data;
+
+        // link the the filled objects to the SMS
+        env.origAddress = addr;
+        env.origSubaddress = subaddr;
+
+        SmsMessage msg = new SmsMessage(addr, env);
+
+        return msg;
+    }
+
+    public static android.telephony.SmsMessage newSmsMessageFromCdmaSmsMessage(
+            CdmaSmsMessage msg) {
+        return new android.telephony.SmsMessage((SmsMessageBase)newCdmaSmsMessageFromRil(msg));
+    }
+}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
deleted file mode 100644
index 1de72db..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ /dev/null
@@ -1,2000 +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 com.android.internal.telephony.cdma.sms;
-
-import android.content.res.Resources;
-import android.telephony.SmsCbCmasInfo;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.cdma.CdmaSmsCbProgramResults;
-import android.text.format.Time;
-import android.telephony.Rlog;
-
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.BitwiseOutputStream;
-
-import java.util.ArrayList;
-import java.util.TimeZone;
-
-/**
- * An object to encode and decode CDMA SMS bearer data.
- */
-public final class BearerData {
-    private final static String LOG_TAG = "BearerData";
-
-    /**
-     * Bearer Data Subparameter Identifiers
-     * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
-     * NOTE: Commented subparameter types are not implemented.
-     */
-    private final static byte SUBPARAM_MESSAGE_IDENTIFIER               = 0x00;
-    private final static byte SUBPARAM_USER_DATA                        = 0x01;
-    private final static byte SUBPARAM_USER_RESPONSE_CODE               = 0x02;
-    private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP        = 0x03;
-    private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE         = 0x04;
-    private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE         = 0x05;
-    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE  = 0x06;
-    private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE  = 0x07;
-    private final static byte SUBPARAM_PRIORITY_INDICATOR               = 0x08;
-    private final static byte SUBPARAM_PRIVACY_INDICATOR                = 0x09;
-    private final static byte SUBPARAM_REPLY_OPTION                     = 0x0A;
-    private final static byte SUBPARAM_NUMBER_OF_MESSAGES               = 0x0B;
-    private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY        = 0x0C;
-    private final static byte SUBPARAM_LANGUAGE_INDICATOR               = 0x0D;
-    private final static byte SUBPARAM_CALLBACK_NUMBER                  = 0x0E;
-    private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE             = 0x0F;
-    //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA      = 0x10;
-    private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX            = 0x11;
-    private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA    = 0x12;
-    private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13;
-    private final static byte SUBPARAM_MESSAGE_STATUS                   = 0x14;
-    //private final static byte SUBPARAM_TP_FAILURE_CAUSE                 = 0x15;
-    //private final static byte SUBPARAM_ENHANCED_VMN                     = 0x16;
-    //private final static byte SUBPARAM_ENHANCED_VMN_ACK                 = 0x17;
-
-    // All other values after this are reserved.
-    private final static byte SUBPARAM_ID_LAST_DEFINED                    = 0x17;
-
-    /**
-     * Supported message types for CDMA SMS messages
-     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
-     */
-    public static final int MESSAGE_TYPE_DELIVER        = 0x01;
-    public static final int MESSAGE_TYPE_SUBMIT         = 0x02;
-    public static final int MESSAGE_TYPE_CANCELLATION   = 0x03;
-    public static final int MESSAGE_TYPE_DELIVERY_ACK   = 0x04;
-    public static final int MESSAGE_TYPE_USER_ACK       = 0x05;
-    public static final int MESSAGE_TYPE_READ_ACK       = 0x06;
-    public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
-    public static final int MESSAGE_TYPE_SUBMIT_REPORT  = 0x08;
-
-    public int messageType;
-
-    /**
-     * 16-bit value indicating the message ID, which increments modulo 65536.
-     * (Special rules apply for WAP-messages.)
-     * (See 3GPP2 C.S0015-B, v2, 4.5.1)
-     */
-    public int messageId;
-
-    /**
-     * Supported priority modes for CDMA SMS messages
-     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
-     */
-    public static final int PRIORITY_NORMAL        = 0x0;
-    public static final int PRIORITY_INTERACTIVE   = 0x1;
-    public static final int PRIORITY_URGENT        = 0x2;
-    public static final int PRIORITY_EMERGENCY     = 0x3;
-
-    public boolean priorityIndicatorSet = false;
-    public int priority = PRIORITY_NORMAL;
-
-    /**
-     * Supported privacy modes for CDMA SMS messages
-     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
-     */
-    public static final int PRIVACY_NOT_RESTRICTED = 0x0;
-    public static final int PRIVACY_RESTRICTED     = 0x1;
-    public static final int PRIVACY_CONFIDENTIAL   = 0x2;
-    public static final int PRIVACY_SECRET         = 0x3;
-
-    public boolean privacyIndicatorSet = false;
-    public int privacy = PRIVACY_NOT_RESTRICTED;
-
-    /**
-     * Supported alert priority modes for CDMA SMS messages
-     * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
-     */
-    public static final int ALERT_DEFAULT          = 0x0;
-    public static final int ALERT_LOW_PRIO         = 0x1;
-    public static final int ALERT_MEDIUM_PRIO      = 0x2;
-    public static final int ALERT_HIGH_PRIO        = 0x3;
-
-    public boolean alertIndicatorSet = false;
-    public int alert = ALERT_DEFAULT;
-
-    /**
-     * Supported display modes for CDMA SMS messages.  Display mode is
-     * a 2-bit value used to indicate to the mobile station when to
-     * display the received message.  (See 3GPP2 C.S0015-B, v2,
-     * 4.5.16)
-     */
-    public static final int DISPLAY_MODE_IMMEDIATE      = 0x0;
-    public static final int DISPLAY_MODE_DEFAULT        = 0x1;
-    public static final int DISPLAY_MODE_USER           = 0x2;
-
-    public boolean displayModeSet = false;
-    public int displayMode = DISPLAY_MODE_DEFAULT;
-
-    /**
-     * Language Indicator values.  NOTE: the spec (3GPP2 C.S0015-B,
-     * v2, 4.5.14) is ambiguous as to the meaning of this field, as it
-     * refers to C.R1001-D but that reference has been crossed out.
-     * It would seem reasonable to assume the values from C.R1001-F
-     * (table 9.2-1) are to be used instead.
-     */
-    public static final int LANGUAGE_UNKNOWN  = 0x00;
-    public static final int LANGUAGE_ENGLISH  = 0x01;
-    public static final int LANGUAGE_FRENCH   = 0x02;
-    public static final int LANGUAGE_SPANISH  = 0x03;
-    public static final int LANGUAGE_JAPANESE = 0x04;
-    public static final int LANGUAGE_KOREAN   = 0x05;
-    public static final int LANGUAGE_CHINESE  = 0x06;
-    public static final int LANGUAGE_HEBREW   = 0x07;
-
-    public boolean languageIndicatorSet = false;
-    public int language = LANGUAGE_UNKNOWN;
-
-    /**
-     * SMS Message Status Codes.  The first component of the Message
-     * status indicates if an error has occurred and whether the error
-     * is considered permanent or temporary.  The second component of
-     * the Message status indicates the cause of the error (if any).
-     * (See 3GPP2 C.S0015-B, v2.0, 4.5.21)
-     */
-    /* no-error codes */
-    public static final int ERROR_NONE                   = 0x00;
-    public static final int STATUS_ACCEPTED              = 0x00;
-    public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01;
-    public static final int STATUS_DELIVERED             = 0x02;
-    public static final int STATUS_CANCELLED             = 0x03;
-    /* temporary-error and permanent-error codes */
-    public static final int ERROR_TEMPORARY              = 0x02;
-    public static final int STATUS_NETWORK_CONGESTION    = 0x04;
-    public static final int STATUS_NETWORK_ERROR         = 0x05;
-    public static final int STATUS_UNKNOWN_ERROR         = 0x1F;
-    /* permanent-error codes */
-    public static final int ERROR_PERMANENT              = 0x03;
-    public static final int STATUS_CANCEL_FAILED         = 0x06;
-    public static final int STATUS_BLOCKED_DESTINATION   = 0x07;
-    public static final int STATUS_TEXT_TOO_LONG         = 0x08;
-    public static final int STATUS_DUPLICATE_MESSAGE     = 0x09;
-    public static final int STATUS_INVALID_DESTINATION   = 0x0A;
-    public static final int STATUS_MESSAGE_EXPIRED       = 0x0D;
-    /* undefined-status codes */
-    public static final int ERROR_UNDEFINED              = 0xFF;
-    public static final int STATUS_UNDEFINED             = 0xFF;
-
-    public boolean messageStatusSet = false;
-    public int errorClass = ERROR_UNDEFINED;
-    public int messageStatus = STATUS_UNDEFINED;
-
-    /**
-     * 1-bit value that indicates whether a User Data Header (UDH) is present.
-     * (See 3GPP2 C.S0015-B, v2, 4.5.1)
-     *
-     * NOTE: during encoding, this value will be set based on the
-     * presence of a UDH in the structured data, any existing setting
-     * will be overwritten.
-     */
-    public boolean hasUserDataHeader;
-
-    /**
-     * provides the information for the user data
-     * (e.g. padding bits, user data, user data header, etc)
-     * (See 3GPP2 C.S.0015-B, v2, 4.5.2)
-     */
-    public UserData userData;
-
-    /**
-     * The User Response Code subparameter is used in the SMS User
-     * Acknowledgment Message to respond to previously received short
-     * messages. This message center-specific element carries the
-     * identifier of a predefined response. (See 3GPP2 C.S.0015-B, v2,
-     * 4.5.3)
-     */
-    public boolean userResponseCodeSet = false;
-    public int userResponseCode;
-
-    /**
-     * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
-     */
-    public static class TimeStamp extends Time {
-
-        public TimeStamp() {
-            super(TimeZone.getDefault().getID());   // 3GPP2 timestamps use the local timezone
-        }
-
-        public static TimeStamp fromByteArray(byte[] data) {
-            TimeStamp ts = new TimeStamp();
-            // C.S0015-B v2.0, 4.5.4: range is 1996-2095
-            int year = IccUtils.cdmaBcdByteToInt(data[0]);
-            if (year > 99 || year < 0) return null;
-            ts.year = year >= 96 ? year + 1900 : year + 2000;
-            int month = IccUtils.cdmaBcdByteToInt(data[1]);
-            if (month < 1 || month > 12) return null;
-            ts.month = month - 1;
-            int day = IccUtils.cdmaBcdByteToInt(data[2]);
-            if (day < 1 || day > 31) return null;
-            ts.monthDay = day;
-            int hour = IccUtils.cdmaBcdByteToInt(data[3]);
-            if (hour < 0 || hour > 23) return null;
-            ts.hour = hour;
-            int minute = IccUtils.cdmaBcdByteToInt(data[4]);
-            if (minute < 0 || minute > 59) return null;
-            ts.minute = minute;
-            int second = IccUtils.cdmaBcdByteToInt(data[5]);
-            if (second < 0 || second > 59) return null;
-            ts.second = second;
-            return ts;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("TimeStamp ");
-            builder.append("{ year=" + year);
-            builder.append(", month=" + month);
-            builder.append(", day=" + monthDay);
-            builder.append(", hour=" + hour);
-            builder.append(", minute=" + minute);
-            builder.append(", second=" + second);
-            builder.append(" }");
-            return builder.toString();
-        }
-    }
-
-    public TimeStamp msgCenterTimeStamp;
-    public TimeStamp validityPeriodAbsolute;
-    public TimeStamp deferredDeliveryTimeAbsolute;
-
-    /**
-     * Relative time is specified as one byte, the value of which
-     * falls into a series of ranges, as specified below.  The idea is
-     * that shorter time intervals allow greater precision -- the
-     * value means minutes from zero until the MINS_LIMIT (inclusive),
-     * upon which it means hours until the HOURS_LIMIT, and so
-     * forth. (See 3GPP2 C.S0015-B, v2, 4.5.6-1)
-     */
-    public static final int RELATIVE_TIME_MINS_LIMIT      = 143;
-    public static final int RELATIVE_TIME_HOURS_LIMIT     = 167;
-    public static final int RELATIVE_TIME_DAYS_LIMIT      = 196;
-    public static final int RELATIVE_TIME_WEEKS_LIMIT     = 244;
-    public static final int RELATIVE_TIME_INDEFINITE      = 245;
-    public static final int RELATIVE_TIME_NOW             = 246;
-    public static final int RELATIVE_TIME_MOBILE_INACTIVE = 247;
-    public static final int RELATIVE_TIME_RESERVED        = 248;
-
-    public boolean validityPeriodRelativeSet;
-    public int validityPeriodRelative;
-    public boolean deferredDeliveryTimeRelativeSet;
-    public int deferredDeliveryTimeRelative;
-
-    /**
-     * The Reply Option subparameter contains 1-bit values which
-     * indicate whether SMS acknowledgment is requested or not.  (See
-     * 3GPP2 C.S0015-B, v2, 4.5.11)
-     */
-    public boolean userAckReq;
-    public boolean deliveryAckReq;
-    public boolean readAckReq;
-    public boolean reportReq;
-
-    /**
-     * The Number of Messages subparameter (8-bit value) is a decimal
-     * number in the 0 to 99 range representing the number of messages
-     * stored at the Voice Mail System. This element is used by the
-     * Voice Mail Notification service.  (See 3GPP2 C.S0015-B, v2,
-     * 4.5.12)
-     */
-    public int numberOfMessages;
-
-    /**
-     * The Message Deposit Index subparameter is assigned by the
-     * message center as a unique index to the contents of the User
-     * Data subparameter in each message sent to a particular mobile
-     * station. The mobile station, when replying to a previously
-     * received short message which included a Message Deposit Index
-     * subparameter, may include the Message Deposit Index of the
-     * received message to indicate to the message center that the
-     * original contents of the message are to be included in the
-     * reply.  (See 3GPP2 C.S0015-B, v2, 4.5.18)
-     */
-    public int depositIndex;
-
-    /**
-     * 4-bit or 8-bit value that indicates the number to be dialed in reply to a
-     * received SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 4.5.15)
-     */
-    public CdmaSmsAddress callbackNumber;
-
-    /**
-     * CMAS warning notification information.
-     * @see #decodeCmasUserData(BearerData, int)
-     */
-    public SmsCbCmasInfo cmasWarningInfo;
-
-    /**
-     * The Service Category Program Data subparameter is used to enable and disable
-     * SMS broadcast service categories to display. If this subparameter is present,
-     * this field will contain a list of one or more
-     * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects containing the
-     * operation(s) to perform.
-     */
-    public ArrayList<CdmaSmsCbProgramData> serviceCategoryProgramData;
-
-    /**
-     * The Service Category Program Results subparameter informs the message center
-     * of the results of a Service Category Program Data request.
-     */
-    public ArrayList<CdmaSmsCbProgramResults> serviceCategoryProgramResults;
-
-
-    private static class CodingException extends Exception {
-        public CodingException(String s) {
-            super(s);
-        }
-    }
-
-    /**
-     * Returns the language indicator as a two-character ISO 639 string.
-     * @return a two character ISO 639 language code
-     */
-    public String getLanguage() {
-        return getLanguageCodeForValue(language);
-    }
-
-    /**
-     * Converts a CDMA language indicator value to an ISO 639 two character language code.
-     * @param languageValue the CDMA language value to convert
-     * @return the two character ISO 639 language code for the specified value, or null if unknown
-     */
-    private static String getLanguageCodeForValue(int languageValue) {
-        switch (languageValue) {
-            case LANGUAGE_ENGLISH:
-                return "en";
-
-            case LANGUAGE_FRENCH:
-                return "fr";
-
-            case LANGUAGE_SPANISH:
-                return "es";
-
-            case LANGUAGE_JAPANESE:
-                return "ja";
-
-            case LANGUAGE_KOREAN:
-                return "ko";
-
-            case LANGUAGE_CHINESE:
-                return "zh";
-
-            case LANGUAGE_HEBREW:
-                return "he";
-
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("BearerData ");
-        builder.append("{ messageType=" + messageType);
-        builder.append(", messageId=" + messageId);
-        builder.append(", priority=" + (priorityIndicatorSet ? priority : "unset"));
-        builder.append(", privacy=" + (privacyIndicatorSet ? privacy : "unset"));
-        builder.append(", alert=" + (alertIndicatorSet ? alert : "unset"));
-        builder.append(", displayMode=" + (displayModeSet ? displayMode : "unset"));
-        builder.append(", language=" + (languageIndicatorSet ? language : "unset"));
-        builder.append(", errorClass=" + (messageStatusSet ? errorClass : "unset"));
-        builder.append(", msgStatus=" + (messageStatusSet ? messageStatus : "unset"));
-        builder.append(", msgCenterTimeStamp=" +
-                ((msgCenterTimeStamp != null) ? msgCenterTimeStamp : "unset"));
-        builder.append(", validityPeriodAbsolute=" +
-                ((validityPeriodAbsolute != null) ? validityPeriodAbsolute : "unset"));
-        builder.append(", validityPeriodRelative=" +
-                ((validityPeriodRelativeSet) ? validityPeriodRelative : "unset"));
-        builder.append(", deferredDeliveryTimeAbsolute=" +
-                ((deferredDeliveryTimeAbsolute != null) ? deferredDeliveryTimeAbsolute : "unset"));
-        builder.append(", deferredDeliveryTimeRelative=" +
-                ((deferredDeliveryTimeRelativeSet) ? deferredDeliveryTimeRelative : "unset"));
-        builder.append(", userAckReq=" + userAckReq);
-        builder.append(", deliveryAckReq=" + deliveryAckReq);
-        builder.append(", readAckReq=" + readAckReq);
-        builder.append(", reportReq=" + reportReq);
-        builder.append(", numberOfMessages=" + numberOfMessages);
-        builder.append(", callbackNumber=" + Rlog.pii(LOG_TAG, callbackNumber));
-        builder.append(", depositIndex=" + depositIndex);
-        builder.append(", hasUserDataHeader=" + hasUserDataHeader);
-        builder.append(", userData=" + userData);
-        builder.append(" }");
-        return builder.toString();
-    }
-
-    private static void encodeMessageId(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 3);
-        outStream.write(4, bData.messageType);
-        outStream.write(8, bData.messageId >> 8);
-        outStream.write(8, bData.messageId);
-        outStream.write(1, bData.hasUserDataHeader ? 1 : 0);
-        outStream.skip(3);
-    }
-
-    private static int countAsciiSeptets(CharSequence msg, boolean force) {
-        int msgLen = msg.length();
-        if (force) return msgLen;
-        for (int i = 0; i < msgLen; i++) {
-            if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
-                return -1;
-            }
-        }
-        return msgLen;
-    }
-
-    /**
-     * Calculate the message text encoding length, fragmentation, and other details.
-     *
-     * @param msg message text
-     * @param force7BitEncoding ignore (but still count) illegal characters if true
-     * @param isEntireMsg indicates if this is entire msg or a segment in multipart msg
-     * @return septet count, or -1 on failure
-     */
-    public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
-            boolean force7BitEncoding, boolean isEntireMsg) {
-        TextEncodingDetails ted;
-        int septets = countAsciiSeptets(msg, force7BitEncoding);
-        if (septets != -1 && septets <= SmsConstants.MAX_USER_DATA_SEPTETS) {
-            ted = new TextEncodingDetails();
-            ted.msgCount = 1;
-            ted.codeUnitCount = septets;
-            ted.codeUnitsRemaining = SmsConstants.MAX_USER_DATA_SEPTETS - septets;
-            ted.codeUnitSize = SmsConstants.ENCODING_7BIT;
-        } else {
-            ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
-                    msg, force7BitEncoding);
-            if (ted.msgCount == 1 && ted.codeUnitSize == SmsConstants.ENCODING_7BIT &&
-                    isEntireMsg) {
-                // We don't support single-segment EMS, so calculate for 16-bit
-                // TODO: Consider supporting single-segment EMS
-                return SmsMessageBase.calcUnicodeEncodingDetails(msg);
-            }
-        }
-        return ted;
-    }
-
-    private static byte[] encode7bitAscii(String msg, boolean force)
-        throws CodingException
-    {
-        try {
-            BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
-            int msgLen = msg.length();
-            for (int i = 0; i < msgLen; i++) {
-                int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
-                if (charCode == -1) {
-                    if (force) {
-                        outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
-                    } else {
-                        throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
-                    }
-                } else {
-                    outStream.write(7, charCode);
-                }
-            }
-            return outStream.toByteArray();
-        } catch (BitwiseOutputStream.AccessException ex) {
-            throw new CodingException("7bit ASCII encode failed: " + ex);
-        }
-    }
-
-    private static byte[] encodeUtf16(String msg)
-        throws CodingException
-    {
-        try {
-            return msg.getBytes("utf-16be");
-        } catch (java.io.UnsupportedEncodingException ex) {
-            throw new CodingException("UTF-16 encode failed: " + ex);
-        }
-    }
-
-    private static class Gsm7bitCodingResult {
-        int septets;
-        byte[] data;
-    }
-
-    private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
-        throws CodingException
-    {
-        try {
-            /*
-             * TODO(cleanup): It would be nice if GsmAlphabet provided
-             * an option to produce just the data without prepending
-             * the septet count, as this function is really just a
-             * wrapper to strip that off.  Not to mention that the
-             * septet count is generally known prior to invocation of
-             * the encoder.  Note that it cannot be derived from the
-             * resulting array length, since that cannot distinguish
-             * if the last contains either 1 or 8 valid bits.
-             *
-             * TODO(cleanup): The BitwiseXStreams could also be
-             * extended with byte-wise reversed endianness read/write
-             * routines to allow a corresponding implementation of
-             * stringToGsm7BitPacked, and potentially directly support
-             * access to the main bitwise stream from encode/decode.
-             */
-            byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force, 0, 0);
-            Gsm7bitCodingResult result = new Gsm7bitCodingResult();
-            result.data = new byte[fullData.length - 1];
-            System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
-            result.septets = fullData[0] & 0x00FF;
-            return result;
-        } catch (com.android.internal.telephony.EncodeException ex) {
-            throw new CodingException("7bit GSM encode failed: " + ex);
-        }
-    }
-
-    private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
-        throws CodingException
-    {
-        int udhBytes = udhData.length + 1;  // Add length octet.
-        int udhSeptets = ((udhBytes * 8) + 6) / 7;
-        Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
-        uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
-        uData.msgEncodingSet = true;
-        uData.numFields = gcr.septets;
-        uData.payload = gcr.data;
-        uData.payload[0] = (byte)udhData.length;
-        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
-    }
-
-    private static void encode16bitEms(UserData uData, byte[] udhData)
-        throws CodingException
-    {
-        byte[] payload = encodeUtf16(uData.payloadStr);
-        int udhBytes = udhData.length + 1;  // Add length octet.
-        int udhCodeUnits = (udhBytes + 1) / 2;
-        int payloadCodeUnits = payload.length / 2;
-        uData.msgEncoding = UserData.ENCODING_UNICODE_16;
-        uData.msgEncodingSet = true;
-        uData.numFields = udhCodeUnits + payloadCodeUnits;
-        uData.payload = new byte[uData.numFields * 2];
-        uData.payload[0] = (byte)udhData.length;
-        System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
-        System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
-    }
-
-    private static void encodeEmsUserDataPayload(UserData uData)
-        throws CodingException
-    {
-        byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
-        if (uData.msgEncodingSet) {
-            if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
-                encode7bitEms(uData, headerData, true);
-            } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
-                encode16bitEms(uData, headerData);
-            } else {
-                throw new CodingException("unsupported EMS user data encoding (" +
-                                          uData.msgEncoding + ")");
-            }
-        } else {
-            try {
-                encode7bitEms(uData, headerData, false);
-            } catch (CodingException ex) {
-                encode16bitEms(uData, headerData);
-            }
-        }
-    }
-
-    private static byte[] encodeShiftJis(String msg) throws CodingException {
-        try {
-            return msg.getBytes("Shift_JIS");
-        } catch (java.io.UnsupportedEncodingException ex) {
-            throw new CodingException("Shift-JIS encode failed: " + ex);
-        }
-    }
-
-    private static void encodeUserDataPayload(UserData uData)
-        throws CodingException
-    {
-        if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
-            Rlog.e(LOG_TAG, "user data with null payloadStr");
-            uData.payloadStr = "";
-        }
-
-        if (uData.userDataHeader != null) {
-            encodeEmsUserDataPayload(uData);
-            return;
-        }
-
-        if (uData.msgEncodingSet) {
-            if (uData.msgEncoding == UserData.ENCODING_OCTET) {
-                if (uData.payload == null) {
-                    Rlog.e(LOG_TAG, "user data with octet encoding but null payload");
-                    uData.payload = new byte[0];
-                    uData.numFields = 0;
-                } else {
-                    uData.numFields = uData.payload.length;
-                }
-            } else {
-                if (uData.payloadStr == null) {
-                    Rlog.e(LOG_TAG, "non-octet user data with null payloadStr");
-                    uData.payloadStr = "";
-                }
-                if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
-                    Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
-                    uData.payload = gcr.data;
-                    uData.numFields = gcr.septets;
-                } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
-                    uData.payload = encode7bitAscii(uData.payloadStr, true);
-                    uData.numFields = uData.payloadStr.length();
-                } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
-                    uData.payload = encodeUtf16(uData.payloadStr);
-                    uData.numFields = uData.payloadStr.length();
-                } else if (uData.msgEncoding == UserData.ENCODING_SHIFT_JIS) {
-                    uData.payload = encodeShiftJis(uData.payloadStr);
-                    uData.numFields = uData.payload.length;
-                } else {
-                    throw new CodingException("unsupported user data encoding (" +
-                                              uData.msgEncoding + ")");
-                }
-            }
-        } else {
-            try {
-                uData.payload = encode7bitAscii(uData.payloadStr, false);
-                uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
-            } catch (CodingException ex) {
-                uData.payload = encodeUtf16(uData.payloadStr);
-                uData.msgEncoding = UserData.ENCODING_UNICODE_16;
-            }
-            uData.numFields = uData.payloadStr.length();
-            uData.msgEncodingSet = true;
-        }
-    }
-
-    private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException, CodingException
-    {
-        /*
-         * TODO(cleanup): Do we really need to set userData.payload as
-         * a side effect of encoding?  If not, we could avoid data
-         * copies by passing outStream directly.
-         */
-        encodeUserDataPayload(bData.userData);
-        bData.hasUserDataHeader = bData.userData.userDataHeader != null;
-
-        if (bData.userData.payload.length > SmsConstants.MAX_USER_DATA_BYTES) {
-            throw new CodingException("encoded user data too large (" +
-                                      bData.userData.payload.length +
-                                      " > " + SmsConstants.MAX_USER_DATA_BYTES + " bytes)");
-        }
-
-        /*
-         * TODO(cleanup): figure out what the right answer is WRT paddingBits field
-         *
-         *   userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
-         *   userData.paddingBits = 0; // XXX this seems better, but why?
-         *
-         */
-        int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
-        int paramBits = dataBits + 13;
-        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
-            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
-            paramBits += 8;
-        }
-        int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
-        int paddingBits = (paramBytes * 8) - paramBits;
-        outStream.write(8, paramBytes);
-        outStream.write(5, bData.userData.msgEncoding);
-        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
-            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
-            outStream.write(8, bData.userData.msgType);
-        }
-        outStream.write(8, bData.userData.numFields);
-        outStream.writeByteArray(dataBits, bData.userData.payload);
-        if (paddingBits > 0) outStream.write(paddingBits, 0);
-    }
-
-    private static void encodeReplyOption(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(1, bData.userAckReq     ? 1 : 0);
-        outStream.write(1, bData.deliveryAckReq ? 1 : 0);
-        outStream.write(1, bData.readAckReq     ? 1 : 0);
-        outStream.write(1, bData.reportReq      ? 1 : 0);
-        outStream.write(4, 0);
-    }
-
-    private static byte[] encodeDtmfSmsAddress(String address) {
-        int digits = address.length();
-        int dataBits = digits * 4;
-        int dataBytes = (dataBits / 8);
-        dataBytes += (dataBits % 8) > 0 ? 1 : 0;
-        byte[] rawData = new byte[dataBytes];
-        for (int i = 0; i < digits; i++) {
-            char c = address.charAt(i);
-            int val = 0;
-            if ((c >= '1') && (c <= '9')) val = c - '0';
-            else if (c == '0') val = 10;
-            else if (c == '*') val = 11;
-            else if (c == '#') val = 12;
-            else return null;
-            rawData[i / 2] |= val << (4 - ((i % 2) * 4));
-        }
-        return rawData;
-    }
-
-    /*
-     * TODO(cleanup): CdmaSmsAddress encoding should make use of
-     * CdmaSmsAddress.parse provided that DTMF encoding is unified,
-     * and the difference in 4-bit vs. 8-bit is resolved.
-     */
-
-    private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
-        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-            try {
-                addr.origBytes = addr.address.getBytes("US-ASCII");
-            } catch (java.io.UnsupportedEncodingException ex) {
-                throw new CodingException("invalid SMS address, cannot convert to ASCII");
-            }
-        } else {
-            addr.origBytes = encodeDtmfSmsAddress(addr.address);
-        }
-    }
-
-    private static void encodeCallbackNumber(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException, CodingException
-    {
-        CdmaSmsAddress addr = bData.callbackNumber;
-        encodeCdmaSmsAddress(addr);
-        int paramBits = 9;
-        int dataBits = 0;
-        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-            paramBits += 7;
-            dataBits = addr.numberOfDigits * 8;
-        } else {
-            dataBits = addr.numberOfDigits * 4;
-        }
-        paramBits += dataBits;
-        int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
-        int paddingBits = (paramBytes * 8) - paramBits;
-        outStream.write(8, paramBytes);
-        outStream.write(1, addr.digitMode);
-        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-            outStream.write(3, addr.ton);
-            outStream.write(4, addr.numberPlan);
-        }
-        outStream.write(8, addr.numberOfDigits);
-        outStream.writeByteArray(dataBits, addr.origBytes);
-        if (paddingBits > 0) outStream.write(paddingBits, 0);
-    }
-
-    private static void encodeMsgStatus(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(2, bData.errorClass);
-        outStream.write(6, bData.messageStatus);
-    }
-
-    private static void encodeMsgCount(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(8, bData.numberOfMessages);
-    }
-
-    private static void encodeValidityPeriodRel(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(8, bData.validityPeriodRelative);
-    }
-
-    private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(2, bData.privacy);
-        outStream.skip(6);
-    }
-
-    private static void encodeLanguageIndicator(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(8, bData.language);
-    }
-
-    private static void encodeDisplayMode(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(2, bData.displayMode);
-        outStream.skip(6);
-    }
-
-    private static void encodePriorityIndicator(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(2, bData.priority);
-        outStream.skip(6);
-    }
-
-    private static void encodeMsgDeliveryAlert(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        outStream.write(8, 1);
-        outStream.write(2, bData.alert);
-        outStream.skip(6);
-    }
-
-    private static void encodeScpResults(BearerData bData, BitwiseOutputStream outStream)
-        throws BitwiseOutputStream.AccessException
-    {
-        ArrayList<CdmaSmsCbProgramResults> results = bData.serviceCategoryProgramResults;
-        outStream.write(8, (results.size() * 4));   // 4 octets per program result
-        for (CdmaSmsCbProgramResults result : results) {
-            int category = result.getCategory();
-            outStream.write(8, category >> 8);
-            outStream.write(8, category);
-            outStream.write(8, result.getLanguage());
-            outStream.write(4, result.getCategoryResult());
-            outStream.skip(4);
-        }
-    }
-
-    /**
-     * Create serialized representation for BearerData object.
-     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
-     *
-     * @param bData an instance of BearerData.
-     *
-     * @return byte array of raw encoded SMS bearer data.
-     */
-    public static byte[] encode(BearerData bData) {
-        bData.hasUserDataHeader = ((bData.userData != null) &&
-                (bData.userData.userDataHeader != null));
-        try {
-            BitwiseOutputStream outStream = new BitwiseOutputStream(200);
-            outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
-            encodeMessageId(bData, outStream);
-            if (bData.userData != null) {
-                outStream.write(8, SUBPARAM_USER_DATA);
-                encodeUserData(bData, outStream);
-            }
-            if (bData.callbackNumber != null) {
-                outStream.write(8, SUBPARAM_CALLBACK_NUMBER);
-                encodeCallbackNumber(bData, outStream);
-            }
-            if (bData.userAckReq || bData.deliveryAckReq || bData.readAckReq || bData.reportReq) {
-                outStream.write(8, SUBPARAM_REPLY_OPTION);
-                encodeReplyOption(bData, outStream);
-            }
-            if (bData.numberOfMessages != 0) {
-                outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES);
-                encodeMsgCount(bData, outStream);
-            }
-            if (bData.validityPeriodRelativeSet) {
-                outStream.write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
-                encodeValidityPeriodRel(bData, outStream);
-            }
-            if (bData.privacyIndicatorSet) {
-                outStream.write(8, SUBPARAM_PRIVACY_INDICATOR);
-                encodePrivacyIndicator(bData, outStream);
-            }
-            if (bData.languageIndicatorSet) {
-                outStream.write(8, SUBPARAM_LANGUAGE_INDICATOR);
-                encodeLanguageIndicator(bData, outStream);
-            }
-            if (bData.displayModeSet) {
-                outStream.write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
-                encodeDisplayMode(bData, outStream);
-            }
-            if (bData.priorityIndicatorSet) {
-                outStream.write(8, SUBPARAM_PRIORITY_INDICATOR);
-                encodePriorityIndicator(bData, outStream);
-            }
-            if (bData.alertIndicatorSet) {
-                outStream.write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
-                encodeMsgDeliveryAlert(bData, outStream);
-            }
-            if (bData.messageStatusSet) {
-                outStream.write(8, SUBPARAM_MESSAGE_STATUS);
-                encodeMsgStatus(bData, outStream);
-            }
-            if (bData.serviceCategoryProgramResults != null) {
-                outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
-                encodeScpResults(bData, outStream);
-            }
-            return outStream.toByteArray();
-        } catch (BitwiseOutputStream.AccessException ex) {
-            Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
-        } catch (CodingException ex) {
-            Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
-        }
-        return null;
-   }
-
-    private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 3 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.messageType = inStream.read(4);
-            bData.messageId = inStream.read(8) << 8;
-            bData.messageId |= inStream.read(8);
-            bData.hasUserDataHeader = (inStream.read(1) == 1);
-            inStream.skip(3);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeReserved(
-            BearerData bData, BitwiseInputStream inStream, int subparamId)
-        throws BitwiseInputStream.AccessException, CodingException
-    {
-        boolean decodeSuccess = false;
-        int subparamLen = inStream.read(8); // SUBPARAM_LEN
-        int paramBits = subparamLen * 8;
-        if (paramBits <= inStream.available()) {
-            decodeSuccess = true;
-            inStream.skip(paramBits);
-        }
-        Rlog.d(LOG_TAG, "RESERVED bearer data subparameter " + subparamId + " decode "
-                + (decodeSuccess ? "succeeded" : "failed") + " (param bits = " + paramBits + ")");
-        if (!decodeSuccess) {
-            throw new CodingException("RESERVED bearer data subparameter " + subparamId
-                    + " had invalid SUBPARAM_LEN " + subparamLen);
-        }
-
-        return decodeSuccess;
-    }
-
-    private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException
-    {
-        int paramBits = inStream.read(8) * 8;
-        bData.userData = new UserData();
-        bData.userData.msgEncoding = inStream.read(5);
-        bData.userData.msgEncodingSet = true;
-        bData.userData.msgType = 0;
-        int consumedBits = 5;
-        if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
-            (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
-            bData.userData.msgType = inStream.read(8);
-            consumedBits += 8;
-        }
-        bData.userData.numFields = inStream.read(8);
-        consumedBits += 8;
-        int dataBits = paramBits - consumedBits;
-        bData.userData.payload = inStream.readByteArray(dataBits);
-        return true;
-    }
-
-    private static String decodeUtf8(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        return decodeCharset(data, offset, numFields, 1, "UTF-8");
-    }
-
-    private static String decodeUtf16(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        // Subtract header and possible padding byte (at end) from num fields.
-        int padding = offset % 2;
-        numFields -= (offset + padding) / 2;
-        return decodeCharset(data, offset, numFields, 2, "utf-16be");
-    }
-
-    private static String decodeCharset(byte[] data, int offset, int numFields, int width,
-            String charset) throws CodingException
-    {
-        if (numFields < 0 || (numFields * width + offset) > data.length) {
-            // Try to decode the max number of characters in payload
-            int padding = offset % width;
-            int maxNumFields = (data.length - offset - padding) / width;
-            if (maxNumFields < 0) {
-                throw new CodingException(charset + " decode failed: offset out of range");
-            }
-            Rlog.e(LOG_TAG, charset + " decode error: offset = " + offset + " numFields = "
-                    + numFields + " data.length = " + data.length + " maxNumFields = "
-                    + maxNumFields);
-            numFields = maxNumFields;
-        }
-        try {
-            return new String(data, offset, numFields * width, charset);
-        } catch (java.io.UnsupportedEncodingException ex) {
-            throw new CodingException(charset + " decode failed: " + ex);
-        }
-    }
-
-    private static String decode7bitAscii(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        try {
-            offset *= 8;
-            StringBuffer strBuf = new StringBuffer(numFields);
-            BitwiseInputStream inStream = new BitwiseInputStream(data);
-            int wantedBits = (offset * 8) + (numFields * 7);
-            if (inStream.available() < wantedBits) {
-                throw new CodingException("insufficient data (wanted " + wantedBits +
-                                          " bits, but only have " + inStream.available() + ")");
-            }
-            inStream.skip(offset);
-            for (int i = 0; i < numFields; i++) {
-                int charCode = inStream.read(7);
-                if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
-                        (charCode <= UserData.ASCII_MAP_MAX_INDEX)) {
-                    strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]);
-                } else if (charCode == UserData.ASCII_NL_INDEX) {
-                    strBuf.append('\n');
-                } else if (charCode == UserData.ASCII_CR_INDEX) {
-                    strBuf.append('\r');
-                } else {
-                    /* For other charCodes, they are unprintable, and so simply use SPACE. */
-                    strBuf.append(' ');
-                }
-            }
-            return strBuf.toString();
-        } catch (BitwiseInputStream.AccessException ex) {
-            throw new CodingException("7bit ASCII decode failed: " + ex);
-        }
-    }
-
-    private static String decode7bitGsm(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        // Start reading from the next 7-bit aligned boundary after offset.
-        int offsetBits = offset * 8;
-        int offsetSeptets = (offsetBits + 6) / 7;
-        numFields -= offsetSeptets;
-        int paddingBits = (offsetSeptets * 7) - offsetBits;
-        String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits,
-                0, 0);
-        if (result == null) {
-            throw new CodingException("7bit GSM decoding failed");
-        }
-        return result;
-    }
-
-    private static String decodeLatin(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        return decodeCharset(data, offset, numFields, 1, "ISO-8859-1");
-    }
-
-    private static String decodeShiftJis(byte[] data, int offset, int numFields)
-        throws CodingException
-    {
-        return decodeCharset(data, offset, numFields, 1, "Shift_JIS");
-    }
-
-    private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
-        throws CodingException
-    {
-        int offset = 0;
-        if (hasUserDataHeader) {
-            int udhLen = userData.payload[0] & 0x00FF;
-            offset += udhLen + 1;
-            byte[] headerData = new byte[udhLen];
-            System.arraycopy(userData.payload, 1, headerData, 0, udhLen);
-            userData.userDataHeader = SmsHeader.fromByteArray(headerData);
-        }
-        switch (userData.msgEncoding) {
-        case UserData.ENCODING_OCTET:
-            /*
-            *  Octet decoding depends on the carrier service.
-            */
-            boolean decodingtypeUTF8 = Resources.getSystem()
-                    .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
-
-            // Strip off any padding bytes, meaning any differences between the length of the
-            // array and the target length specified by numFields.  This is to avoid any
-            // confusion by code elsewhere that only considers the payload array length.
-            byte[] payload = new byte[userData.numFields];
-            int copyLen = userData.numFields < userData.payload.length
-                    ? userData.numFields : userData.payload.length;
-
-            System.arraycopy(userData.payload, 0, payload, 0, copyLen);
-            userData.payload = payload;
-
-            if (!decodingtypeUTF8) {
-                // There are many devices in the market that send 8bit text sms (latin encoded) as
-                // octet encoded.
-                userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
-            } else {
-                userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
-            }
-            break;
-
-        case UserData.ENCODING_IA5:
-        case UserData.ENCODING_7BIT_ASCII:
-            userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
-            break;
-        case UserData.ENCODING_UNICODE_16:
-            userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields);
-            break;
-        case UserData.ENCODING_GSM_7BIT_ALPHABET:
-            userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields);
-            break;
-        case UserData.ENCODING_LATIN:
-            userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
-            break;
-        case UserData.ENCODING_SHIFT_JIS:
-            userData.payloadStr = decodeShiftJis(userData.payload, offset, userData.numFields);
-            break;
-        default:
-            throw new CodingException("unsupported user data encoding ("
-                                      + userData.msgEncoding + ")");
-        }
-    }
-
-    /**
-     * IS-91 Voice Mail message decoding
-     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
-     * (For character encodings, see TIA/EIA/IS-91, Annex B)
-     *
-     * Protocol Summary: The user data payload may contain 3-14
-     * characters.  The first two characters are parsed as a number
-     * and indicate the number of voicemails.  The third character is
-     * either a SPACE or '!' to indicate normal or urgent priority,
-     * respectively.  Any following characters are treated as normal
-     * text user data payload.
-     *
-     * Note that the characters encoding is 6-bit packed.
-     */
-    private static void decodeIs91VoicemailStatus(BearerData bData)
-        throws BitwiseInputStream.AccessException, CodingException
-    {
-        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
-        int dataLen = inStream.available() / 6;  // 6-bit packed character encoding.
-        int numFields = bData.userData.numFields;
-        if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
-            throw new CodingException("IS-91 voicemail status decoding failed");
-        }
-        try {
-            StringBuffer strbuf = new StringBuffer(dataLen);
-            while (inStream.available() >= 6) {
-                strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
-            }
-            String data = strbuf.toString();
-            bData.numberOfMessages = Integer.parseInt(data.substring(0, 2));
-            char prioCode = data.charAt(2);
-            if (prioCode == ' ') {
-                bData.priority = PRIORITY_NORMAL;
-            } else if (prioCode == '!') {
-                bData.priority = PRIORITY_URGENT;
-            } else {
-                throw new CodingException("IS-91 voicemail status decoding failed: " +
-                        "illegal priority setting (" + prioCode + ")");
-            }
-            bData.priorityIndicatorSet = true;
-            bData.userData.payloadStr = data.substring(3, numFields - 3);
-       } catch (java.lang.NumberFormatException ex) {
-            throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
-        } catch (java.lang.IndexOutOfBoundsException ex) {
-            throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
-        }
-    }
-
-    /**
-     * IS-91 Short Message decoding
-     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
-     * (For character encodings, see TIA/EIA/IS-91, Annex B)
-     *
-     * Protocol Summary: The user data payload may contain 1-14
-     * characters, which are treated as normal text user data payload.
-     * Note that the characters encoding is 6-bit packed.
-     */
-    private static void decodeIs91ShortMessage(BearerData bData)
-        throws BitwiseInputStream.AccessException, CodingException
-    {
-        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
-        int dataLen = inStream.available() / 6;  // 6-bit packed character encoding.
-        int numFields = bData.userData.numFields;
-        // dataLen may be > 14 characters due to octet padding
-        if ((numFields > 14) || (dataLen < numFields)) {
-            throw new CodingException("IS-91 short message decoding failed");
-        }
-        StringBuffer strbuf = new StringBuffer(dataLen);
-        for (int i = 0; i < numFields; i++) {
-            strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
-        }
-        bData.userData.payloadStr = strbuf.toString();
-    }
-
-    /**
-     * IS-91 CLI message (callback number) decoding
-     * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
-     *
-     * Protocol Summary: The data payload may contain 1-32 digits,
-     * encoded using standard 4-bit DTMF, which are treated as a
-     * callback number.
-     */
-    private static void decodeIs91Cli(BearerData bData) throws CodingException {
-        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
-        int dataLen = inStream.available() / 4;  // 4-bit packed DTMF digit encoding.
-        int numFields = bData.userData.numFields;
-        if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
-            throw new CodingException("IS-91 voicemail status decoding failed");
-        }
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
-        addr.origBytes = bData.userData.payload;
-        addr.numberOfDigits = (byte)numFields;
-        decodeSmsAddress(addr);
-        bData.callbackNumber = addr;
-    }
-
-    private static void decodeIs91(BearerData bData)
-        throws BitwiseInputStream.AccessException, CodingException
-    {
-        switch (bData.userData.msgType) {
-        case UserData.IS91_MSG_TYPE_VOICEMAIL_STATUS:
-            decodeIs91VoicemailStatus(bData);
-            break;
-        case UserData.IS91_MSG_TYPE_CLI:
-            decodeIs91Cli(bData);
-            break;
-        case UserData.IS91_MSG_TYPE_SHORT_MESSAGE_FULL:
-        case UserData.IS91_MSG_TYPE_SHORT_MESSAGE:
-            decodeIs91ShortMessage(bData);
-            break;
-        default:
-            throw new CodingException("unsupported IS-91 message type (" +
-                    bData.userData.msgType + ")");
-        }
-    }
-
-    private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.userAckReq     = (inStream.read(1) == 1);
-            bData.deliveryAckReq = (inStream.read(1) == 1);
-            bData.readAckReq     = (inStream.read(1) == 1);
-            bData.reportReq      = (inStream.read(1) == 1);
-            inStream.skip(4);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "REPLY_OPTION decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 2 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
-        throws CodingException
-    {
-        /* DTMF 4-bit digit encoding, defined in at
-         * 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
-        StringBuffer strBuf = new StringBuffer(numFields);
-        for (int i = 0; i < numFields; i++) {
-            int val = 0x0F & (rawData[i / 2] >>> (4 - ((i % 2) * 4)));
-            if ((val >= 1) && (val <= 9)) strBuf.append(Integer.toString(val, 10));
-            else if (val == 10) strBuf.append('0');
-            else if (val == 11) strBuf.append('*');
-            else if (val == 12) strBuf.append('#');
-            else throw new CodingException("invalid SMS address DTMF code (" + val + ")");
-        }
-        return strBuf.toString();
-    }
-
-    private static void decodeSmsAddress(CdmaSmsAddress addr) throws CodingException {
-        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-            try {
-                /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
-                 * just 7-bit ASCII encoding, with the MSB being zero. */
-                addr.address = new String(addr.origBytes, 0, addr.origBytes.length, "US-ASCII");
-            } catch (java.io.UnsupportedEncodingException ex) {
-                throw new CodingException("invalid SMS address ASCII code");
-            }
-        } else {
-            addr.address = decodeDtmfSmsAddress(addr.origBytes, addr.numberOfDigits);
-        }
-    }
-
-    private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException, CodingException
-    {
-        final int EXPECTED_PARAM_SIZE = 1 * 8; //at least
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits < EXPECTED_PARAM_SIZE) {
-            inStream.skip(paramBits);
-            return false;
-        }
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        addr.digitMode = inStream.read(1);
-        byte fieldBits = 4;
-        byte consumedBits = 1;
-        if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
-            addr.ton = inStream.read(3);
-            addr.numberPlan = inStream.read(4);
-            fieldBits = 8;
-            consumedBits += 7;
-        }
-        addr.numberOfDigits = inStream.read(8);
-        consumedBits += 8;
-        int remainingBits = paramBits - consumedBits;
-        int dataBits = addr.numberOfDigits * fieldBits;
-        int paddingBits = remainingBits - dataBits;
-        if (remainingBits < dataBits) {
-            throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
-                                      "remainingBits + " + remainingBits + ", dataBits + " +
-                                      dataBits + ", paddingBits + " + paddingBits + ")");
-        }
-        addr.origBytes = inStream.readByteArray(dataBits);
-        inStream.skip(paddingBits);
-        decodeSmsAddress(addr);
-        bData.callbackNumber = addr;
-        return true;
-    }
-
-    private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.errorClass = inStream.read(2);
-            bData.messageStatus = inStream.read(6);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.messageStatusSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 6 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 6 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 6 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
-                    inStream.readByteArray(6 * 8));
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        return decodeSuccess;
-    }
-
-    private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.deferredDeliveryTimeRelative = inStream.read(8);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.validityPeriodRelative = inStream.read(8);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.validityPeriodRelativeSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.privacy = inStream.read(2);
-            inStream.skip(6);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.privacyIndicatorSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.language = inStream.read(8);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.languageIndicatorSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.displayMode = inStream.read(2);
-            inStream.skip(6);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.displayModeSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.priority = inStream.read(2);
-            inStream.skip(6);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.priorityIndicatorSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.alert = inStream.read(2);
-            inStream.skip(6);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.alertIndicatorSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
-        throws BitwiseInputStream.AccessException {
-        final int EXPECTED_PARAM_SIZE = 1 * 8;
-        boolean decodeSuccess = false;
-        int paramBits = inStream.read(8) * 8;
-        if (paramBits >= EXPECTED_PARAM_SIZE) {
-            paramBits -= EXPECTED_PARAM_SIZE;
-            decodeSuccess = true;
-            bData.userResponseCode = inStream.read(8);
-        }
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ")");
-        }
-        inStream.skip(paramBits);
-        bData.userResponseCodeSet = decodeSuccess;
-        return decodeSuccess;
-    }
-
-    private static boolean decodeServiceCategoryProgramData(BearerData bData,
-            BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException
-    {
-        if (inStream.available() < 13) {
-            throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
-                    + inStream.available() + " bits available");
-        }
-
-        int paramBits = inStream.read(8) * 8;
-        int msgEncoding = inStream.read(5);
-        paramBits -= 5;
-
-        if (inStream.available() < paramBits) {
-            throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
-                    + inStream.available() + " bits available (" + paramBits + " bits expected)");
-        }
-
-        ArrayList<CdmaSmsCbProgramData> programDataList = new ArrayList<CdmaSmsCbProgramData>();
-
-        final int CATEGORY_FIELD_MIN_SIZE = 6 * 8;
-        boolean decodeSuccess = false;
-        while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
-            int operation = inStream.read(4);
-            int category = (inStream.read(8) << 8) | inStream.read(8);
-            int language = inStream.read(8);
-            int maxMessages = inStream.read(8);
-            int alertOption = inStream.read(4);
-            int numFields = inStream.read(8);
-            paramBits -= CATEGORY_FIELD_MIN_SIZE;
-
-            int textBits = getBitsForNumFields(msgEncoding, numFields);
-            if (paramBits < textBits) {
-                throw new CodingException("category name is " + textBits + " bits in length,"
-                        + " but there are only " + paramBits + " bits available");
-            }
-
-            UserData userData = new UserData();
-            userData.msgEncoding = msgEncoding;
-            userData.msgEncodingSet = true;
-            userData.numFields = numFields;
-            userData.payload = inStream.readByteArray(textBits);
-            paramBits -= textBits;
-
-            decodeUserDataPayload(userData, false);
-            String categoryName = userData.payloadStr;
-            CdmaSmsCbProgramData programData = new CdmaSmsCbProgramData(operation, category,
-                    language, maxMessages, alertOption, categoryName);
-            programDataList.add(programData);
-
-            decodeSuccess = true;
-        }
-
-        if ((! decodeSuccess) || (paramBits > 0)) {
-            Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
-                      (decodeSuccess ? "succeeded" : "failed") +
-                      " (extra bits = " + paramBits + ')');
-        }
-
-        inStream.skip(paramBits);
-        bData.serviceCategoryProgramData = programDataList;
-        return decodeSuccess;
-    }
-
-    private static int serviceCategoryToCmasMessageClass(int serviceCategory) {
-        switch (serviceCategory) {
-            case SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT:
-                return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
-
-            case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
-                return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
-
-            case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
-                return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
-
-            case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
-                return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
-
-            case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
-
-            default:
-                return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
-        }
-    }
-
-    /**
-     * Calculates the number of bits to read for the specified number of encoded characters.
-     * @param msgEncoding the message encoding to use
-     * @param numFields the number of characters to read. For Shift-JIS and Korean encodings,
-     *  this is the number of bytes to read.
-     * @return the number of bits to read from the stream
-     * @throws CodingException if the specified encoding is not supported
-     */
-    private static int getBitsForNumFields(int msgEncoding, int numFields)
-            throws CodingException {
-        switch (msgEncoding) {
-            case UserData.ENCODING_OCTET:
-            case UserData.ENCODING_SHIFT_JIS:
-            case UserData.ENCODING_KOREAN:
-            case UserData.ENCODING_LATIN:
-            case UserData.ENCODING_LATIN_HEBREW:
-                return numFields * 8;
-
-            case UserData.ENCODING_IA5:
-            case UserData.ENCODING_7BIT_ASCII:
-            case UserData.ENCODING_GSM_7BIT_ALPHABET:
-                return numFields * 7;
-
-            case UserData.ENCODING_UNICODE_16:
-                return numFields * 16;
-
-            default:
-                throw new CodingException("unsupported message encoding (" + msgEncoding + ')');
-        }
-    }
-
-    /**
-     * CMAS message decoding.
-     * (See TIA-1149-0-1, CMAS over CDMA)
-     *
-     * @param serviceCategory is the service category from the SMS envelope
-     */
-    private static void decodeCmasUserData(BearerData bData, int serviceCategory)
-            throws BitwiseInputStream.AccessException, CodingException {
-        BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
-        if (inStream.available() < 8) {
-            throw new CodingException("emergency CB with no CMAE_protocol_version");
-        }
-        int protocolVersion = inStream.read(8);
-        if (protocolVersion != 0) {
-            throw new CodingException("unsupported CMAE_protocol_version " + protocolVersion);
-        }
-
-        int messageClass = serviceCategoryToCmasMessageClass(serviceCategory);
-        int category = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN;
-        int responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN;
-        int severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
-        int urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
-        int certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
-
-        while (inStream.available() >= 16) {
-            int recordType = inStream.read(8);
-            int recordLen = inStream.read(8);
-            switch (recordType) {
-                case 0:     // Type 0 elements (Alert text)
-                    UserData alertUserData = new UserData();
-                    alertUserData.msgEncoding = inStream.read(5);
-                    alertUserData.msgEncodingSet = true;
-                    alertUserData.msgType = 0;
-
-                    int numFields;                          // number of chars to decode
-                    switch (alertUserData.msgEncoding) {
-                        case UserData.ENCODING_OCTET:
-                        case UserData.ENCODING_LATIN:
-                            numFields = recordLen - 1;      // subtract 1 byte for encoding
-                            break;
-
-                        case UserData.ENCODING_IA5:
-                        case UserData.ENCODING_7BIT_ASCII:
-                        case UserData.ENCODING_GSM_7BIT_ALPHABET:
-                            numFields = ((recordLen * 8) - 5) / 7;  // subtract 5 bits for encoding
-                            break;
-
-                        case UserData.ENCODING_UNICODE_16:
-                            numFields = (recordLen - 1) / 2;
-                            break;
-
-                        default:
-                            numFields = 0;      // unsupported encoding
-                    }
-
-                    alertUserData.numFields = numFields;
-                    alertUserData.payload = inStream.readByteArray(recordLen * 8 - 5);
-                    decodeUserDataPayload(alertUserData, false);
-                    bData.userData = alertUserData;
-                    break;
-
-                case 1:     // Type 1 elements
-                    category = inStream.read(8);
-                    responseType = inStream.read(8);
-                    severity = inStream.read(4);
-                    urgency = inStream.read(4);
-                    certainty = inStream.read(4);
-                    inStream.skip(recordLen * 8 - 28);
-                    break;
-
-                default:
-                    Rlog.w(LOG_TAG, "skipping unsupported CMAS record type " + recordType);
-                    inStream.skip(recordLen * 8);
-                    break;
-            }
-        }
-
-        bData.cmasWarningInfo = new SmsCbCmasInfo(messageClass, category, responseType, severity,
-                urgency, certainty);
-    }
-
-    /**
-     * Create BearerData object from serialized representation.
-     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
-     *
-     * @param smsData byte array of raw encoded SMS bearer data.
-     * @return an instance of BearerData.
-     */
-    public static BearerData decode(byte[] smsData) {
-        return decode(smsData, 0);
-    }
-
-    private static boolean isCmasAlertCategory(int category) {
-        return category >= SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT
-                && category <= SmsEnvelope.SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE;
-    }
-
-    /**
-     * Create BearerData object from serialized representation.
-     * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
-     *
-     * @param smsData byte array of raw encoded SMS bearer data.
-     * @param serviceCategory the envelope service category (for CMAS alert handling)
-     * @return an instance of BearerData.
-     */
-    public static BearerData decode(byte[] smsData, int serviceCategory) {
-        try {
-            BitwiseInputStream inStream = new BitwiseInputStream(smsData);
-            BearerData bData = new BearerData();
-            int foundSubparamMask = 0;
-            while (inStream.available() > 0) {
-                int subparamId = inStream.read(8);
-                int subparamIdBit = 1 << subparamId;
-                // int is 4 bytes. This duplicate check has a limit to Id number up to 32 (4*8)
-                // as 32th bit is the max bit in int.
-                // Per 3GPP2 C.S0015-B Table 4.5-1 Bearer Data Subparameter Identifiers:
-                // last defined subparam ID is 23 (00010111 = 0x17 = 23).
-                // Only do duplicate subparam ID check if subparam is within defined value as
-                // reserved subparams are just skipped.
-                if ((foundSubparamMask & subparamIdBit) != 0 &&
-                        (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
-                        subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
-                    throw new CodingException("illegal duplicate subparameter (" +
-                                              subparamId + ")");
-                }
-                boolean decodeSuccess;
-                switch (subparamId) {
-                case SUBPARAM_MESSAGE_IDENTIFIER:
-                    decodeSuccess = decodeMessageId(bData, inStream);
-                    break;
-                case SUBPARAM_USER_DATA:
-                    decodeSuccess = decodeUserData(bData, inStream);
-                    break;
-                case SUBPARAM_USER_RESPONSE_CODE:
-                    decodeSuccess = decodeUserResponseCode(bData, inStream);
-                    break;
-                case SUBPARAM_REPLY_OPTION:
-                    decodeSuccess = decodeReplyOption(bData, inStream);
-                    break;
-                case SUBPARAM_NUMBER_OF_MESSAGES:
-                    decodeSuccess = decodeMsgCount(bData, inStream);
-                    break;
-                case SUBPARAM_CALLBACK_NUMBER:
-                    decodeSuccess = decodeCallbackNumber(bData, inStream);
-                    break;
-                case SUBPARAM_MESSAGE_STATUS:
-                    decodeSuccess = decodeMsgStatus(bData, inStream);
-                    break;
-                case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
-                    decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
-                    break;
-                case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
-                    decodeSuccess = decodeValidityAbs(bData, inStream);
-                    break;
-                case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
-                    decodeSuccess = decodeValidityRel(bData, inStream);
-                    break;
-                case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
-                    decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
-                    break;
-                case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
-                    decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
-                    break;
-                case SUBPARAM_PRIVACY_INDICATOR:
-                    decodeSuccess = decodePrivacyIndicator(bData, inStream);
-                    break;
-                case SUBPARAM_LANGUAGE_INDICATOR:
-                    decodeSuccess = decodeLanguageIndicator(bData, inStream);
-                    break;
-                case SUBPARAM_MESSAGE_DISPLAY_MODE:
-                    decodeSuccess = decodeDisplayMode(bData, inStream);
-                    break;
-                case SUBPARAM_PRIORITY_INDICATOR:
-                    decodeSuccess = decodePriorityIndicator(bData, inStream);
-                    break;
-                case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
-                    decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
-                    break;
-                case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
-                    decodeSuccess = decodeDepositIndex(bData, inStream);
-                    break;
-                case SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA:
-                    decodeSuccess = decodeServiceCategoryProgramData(bData, inStream);
-                    break;
-                default:
-                    decodeSuccess = decodeReserved(bData, inStream, subparamId);
-                }
-                if (decodeSuccess &&
-                        (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
-                        subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
-                    foundSubparamMask |= subparamIdBit;
-                }
-            }
-            if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
-                throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
-            }
-            if (bData.userData != null) {
-                if (isCmasAlertCategory(serviceCategory)) {
-                    decodeCmasUserData(bData, serviceCategory);
-                } else if (bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) {
-                    if ((foundSubparamMask ^
-                             (1 << SUBPARAM_MESSAGE_IDENTIFIER) ^
-                             (1 << SUBPARAM_USER_DATA))
-                            != 0) {
-                        Rlog.e(LOG_TAG, "IS-91 must occur without extra subparams (" +
-                              foundSubparamMask + ")");
-                    }
-                    decodeIs91(bData);
-                } else {
-                    decodeUserDataPayload(bData.userData, bData.hasUserDataHeader);
-                }
-            }
-            return bData;
-        } catch (BitwiseInputStream.AccessException ex) {
-            Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
-        } catch (CodingException ex) {
-            Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
-        }
-        return null;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
deleted file mode 100644
index 5f2e561..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ /dev/null
@@ -1,228 +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 com.android.internal.telephony.cdma.sms;
-
-import android.util.SparseBooleanArray;
-
-import com.android.internal.telephony.SmsAddress;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.util.HexDump;
-
-public class CdmaSmsAddress extends SmsAddress {
-
-    /**
-     * Digit Mode Indicator is a 1-bit value that indicates whether
-     * the address digits are 4-bit DTMF codes or 8-bit codes.  (See
-     * 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    static public final int DIGIT_MODE_4BIT_DTMF              = 0x00;
-    static public final int DIGIT_MODE_8BIT_CHAR              = 0x01;
-
-    public int digitMode;
-
-    /**
-     * Number Mode Indicator is 1-bit value that indicates whether the
-     * address type is a data network address or not.  (See 3GPP2
-     * C.S0015-B, v2, 3.4.3.3)
-     */
-    static public final int NUMBER_MODE_NOT_DATA_NETWORK      = 0x00;
-    static public final int NUMBER_MODE_DATA_NETWORK          = 0x01;
-
-    public int numberMode;
-
-    /**
-     * Number Types for data networks.
-     * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
-     * NOTE: value is stored in the parent class ton field.
-     */
-    static public final int TON_UNKNOWN                   = 0x00;
-    static public final int TON_INTERNATIONAL_OR_IP       = 0x01;
-    static public final int TON_NATIONAL_OR_EMAIL         = 0x02;
-    static public final int TON_NETWORK                   = 0x03;
-    static public final int TON_SUBSCRIBER                = 0x04;
-    static public final int TON_ALPHANUMERIC              = 0x05;
-    static public final int TON_ABBREVIATED               = 0x06;
-    static public final int TON_RESERVED                  = 0x07;
-
-    /**
-     * Maximum lengths for fields as defined in ril_cdma_sms.h.
-     */
-    static public final int SMS_ADDRESS_MAX          =  36;
-    static public final int SMS_SUBADDRESS_MAX       =  36;
-
-    /**
-     * This field shall be set to the number of address digits
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    public int numberOfDigits;
-
-    /**
-     * Numbering Plan identification is a 0 or 4-bit value that
-     * indicates which numbering plan identification is set.  (See
-     * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
-     */
-    static public final int NUMBERING_PLAN_UNKNOWN           = 0x0;
-    static public final int NUMBERING_PLAN_ISDN_TELEPHONY    = 0x1;
-    //static protected final int NUMBERING_PLAN_DATA              = 0x3;
-    //static protected final int NUMBERING_PLAN_TELEX             = 0x4;
-    //static protected final int NUMBERING_PLAN_PRIVATE           = 0x9;
-
-    public int numberPlan;
-
-    /**
-     * NOTE: the parsed string address and the raw byte array values
-     * are stored in the parent class address and origBytes fields,
-     * respectively.
-     */
-
-    public CdmaSmsAddress(){
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("CdmaSmsAddress ");
-        builder.append("{ digitMode=" + digitMode);
-        builder.append(", numberMode=" + numberMode);
-        builder.append(", numberPlan=" + numberPlan);
-        builder.append(", numberOfDigits=" + numberOfDigits);
-        builder.append(", ton=" + ton);
-        builder.append(", address=\"" + address + "\"");
-        builder.append(", origBytes=" + HexDump.toHexString(origBytes));
-        builder.append(" }");
-        return builder.toString();
-    }
-
-    /*
-     * TODO(cleanup): Refactor the parsing for addresses to better
-     * share code and logic with GSM.  Also, gather all DTMF/BCD
-     * processing code in one place.
-     */
-
-    private static byte[] parseToDtmf(String address) {
-        int digits = address.length();
-        byte[] result = new byte[digits];
-        for (int i = 0; i < digits; i++) {
-            char c = address.charAt(i);
-            int val = 0;
-            if ((c >= '1') && (c <= '9')) val = c - '0';
-            else if (c == '0') val = 10;
-            else if (c == '*') val = 11;
-            else if (c == '#') val = 12;
-            else return null;
-            result[i] = (byte)val;
-        }
-        return result;
-    }
-
-    private static final char[] numericCharsDialable = {
-        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
-    };
-
-    private static final char[] numericCharsSugar = {
-        '(', ')', ' ', '-', '+', '.', '/', '\\'
-    };
-
-    private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
-            numericCharsDialable.length + numericCharsSugar.length);
-    static {
-        for (int i = 0; i < numericCharsDialable.length; i++) {
-            numericCharDialableMap.put(numericCharsDialable[i], true);
-        }
-        for (int i = 0; i < numericCharsSugar.length; i++) {
-            numericCharDialableMap.put(numericCharsSugar[i], false);
-        }
-    }
-
-    /**
-     * Given a numeric address string, return the string without
-     * syntactic sugar, meaning parens, spaces, hyphens/minuses, or
-     * plus signs.  If the input string contains non-numeric
-     * non-punctuation characters, return null.
-     */
-    private static String filterNumericSugar(String address) {
-        StringBuilder builder = new StringBuilder();
-        int len = address.length();
-        for (int i = 0; i < len; i++) {
-            char c = address.charAt(i);
-            int mapIndex = numericCharDialableMap.indexOfKey(c);
-            if (mapIndex < 0) return null;
-            if (! numericCharDialableMap.valueAt(mapIndex)) continue;
-            builder.append(c);
-        }
-        return builder.toString();
-    }
-
-    /**
-     * Given a string, return the string without whitespace,
-     * including CR/LF.
-     */
-    private static String filterWhitespace(String address) {
-        StringBuilder builder = new StringBuilder();
-        int len = address.length();
-        for (int i = 0; i < len; i++) {
-            char c = address.charAt(i);
-            if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
-            builder.append(c);
-        }
-        return builder.toString();
-    }
-
-    /**
-     * Given a string, create a corresponding CdmaSmsAddress object.
-     *
-     * The result will be null if the input string is not
-     * representable using printable ASCII.
-     *
-     * For numeric addresses, the string is cleaned up by removing
-     * common punctuation.  For alpha addresses, the string is cleaned
-     * up by removing whitespace.
-     */
-    public static CdmaSmsAddress parse(String address) {
-        CdmaSmsAddress addr = new CdmaSmsAddress();
-        addr.address = address;
-        addr.ton = CdmaSmsAddress.TON_UNKNOWN;
-        byte[] origBytes = null;
-        String filteredAddr = filterNumericSugar(address);
-        if (filteredAddr != null) {
-            origBytes = parseToDtmf(filteredAddr);
-        }
-        if (origBytes != null) {
-            addr.digitMode = DIGIT_MODE_4BIT_DTMF;
-            addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
-            if (address.indexOf('+') != -1) {
-                addr.ton = TON_INTERNATIONAL_OR_IP;
-            }
-        } else {
-            filteredAddr = filterWhitespace(address);
-            origBytes = UserData.stringToAscii(filteredAddr);
-            if (origBytes == null) {
-                return null;
-            }
-            addr.digitMode = DIGIT_MODE_8BIT_CHAR;
-            addr.numberMode = NUMBER_MODE_DATA_NETWORK;
-            if (address.indexOf('@') != -1) {
-                addr.ton = TON_NATIONAL_OR_EMAIL;
-            }
-        }
-        addr.origBytes = origBytes;
-        addr.numberOfDigits = origBytes.length;
-        return addr;
-    }
-
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java b/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
deleted file mode 100644
index 0d5b502..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project. All rights reserved.
- *
- * 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.cdma.sms;
-
-public class CdmaSmsSubaddress {
-    public int type;
-
-    public byte odd;
-
-    public byte[] origBytes;
-}
-
diff --git a/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
deleted file mode 100644
index f73df56..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ /dev/null
@@ -1,130 +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 com.android.internal.telephony.cdma.sms;
-
-
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
-
-public final class SmsEnvelope {
-    /**
-     * Message Types
-     * (See 3GPP2 C.S0015-B 3.4.1)
-     */
-    static public final int MESSAGE_TYPE_POINT_TO_POINT   = 0x00;
-    static public final int MESSAGE_TYPE_BROADCAST        = 0x01;
-    static public final int MESSAGE_TYPE_ACKNOWLEDGE      = 0x02;
-
-    /**
-     * Supported Teleservices
-     * (See 3GPP2 N.S0005 and TIA-41)
-     */
-    static public final int TELESERVICE_NOT_SET           = 0x0000;
-    static public final int TELESERVICE_WMT               = 0x1002;
-    static public final int TELESERVICE_VMN               = 0x1003;
-    static public final int TELESERVICE_WAP               = 0x1004;
-    static public final int TELESERVICE_WEMT              = 0x1005;
-    static public final int TELESERVICE_SCPT              = 0x1006;
-
-    /**
-     * The following are defined as extensions to the standard teleservices
-     */
-    // Voice mail notification through Message Waiting Indication in CDMA mode or Analog mode.
-    // Defined in 3GPP2 C.S-0005, 3.7.5.6, an Info Record containing an 8-bit number with the
-    // number of messages waiting, it's used by some CDMA carriers for a voice mail count.
-    static public final int TELESERVICE_MWI               = 0x40000;
-
-    // Service Categories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
-    // static final int SERVICE_CATEGORY_EMERGENCY      = 0x0001;
-    //...
-
-    // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1
-    public static final int SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT  = 0x1000;
-    public static final int SERVICE_CATEGORY_CMAS_EXTREME_THREAT            = 0x1001;
-    public static final int SERVICE_CATEGORY_CMAS_SEVERE_THREAT             = 0x1002;
-    public static final int SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003;
-    public static final int SERVICE_CATEGORY_CMAS_TEST_MESSAGE              = 0x1004;
-    public static final int SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE       = 0x10ff;
-
-    /**
-     * Provides the type of a SMS message like point to point, broadcast or acknowledge
-     */
-    public int messageType;
-
-    /**
-     * The 16-bit Teleservice parameter identifies which upper layer service access point is sending
-     * or receiving the message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.1)
-     */
-    public int teleService = TELESERVICE_NOT_SET;
-
-    /**
-     * The 16-bit service category parameter identifies the type of service provided
-     * by the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.2)
-     */
-    public int serviceCategory;
-
-    /**
-     * The origination address identifies the originator of the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    public CdmaSmsAddress origAddress;
-
-    /**
-     * The destination address identifies the target of the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
-     */
-    public CdmaSmsAddress destAddress;
-
-    /**
-     * The origination subaddress identifies the originator of the SMS message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
-     */
-    public CdmaSmsSubaddress origSubaddress;
-
-    /**
-     * The 6-bit bearer reply parameter is used to request the return of a
-     * SMS Acknowledge Message.
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.5)
-     */
-    public int bearerReply;
-
-    /**
-     * Cause Code values:
-     * The cause code parameters are an indication whether an SMS error has occurred and if so,
-     * whether the condition is considered temporary or permanent.
-     * ReplySeqNo 6-bit value,
-     * ErrorClass 2-bit value,
-     * CauseCode 0-bit or 8-bit value
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.6)
-     */
-    public byte replySeqNo;
-    public byte errorClass;
-    public byte causeCode;
-
-    /**
-     * encoded bearer data
-     * (See 3GPP2 C.S0015-B, v2, 3.4.3.7)
-     */
-    public byte[] bearerData;
-
-    public SmsEnvelope() {
-        // nothing to see here
-    }
-
-}
-
diff --git a/src/java/com/android/internal/telephony/cdma/sms/UserData.java b/src/java/com/android/internal/telephony/cdma/sms/UserData.java
deleted file mode 100644
index 599c2b3..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ /dev/null
@@ -1,165 +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 com.android.internal.telephony.cdma.sms;
-
-import android.util.SparseIntArray;
-
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.util.HexDump;
-
-public class UserData {
-
-    /**
-     * User data encoding types.
-     * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
-     */
-    public static final int ENCODING_OCTET                      = 0x00;
-    public static final int ENCODING_IS91_EXTENDED_PROTOCOL     = 0x01;
-    public static final int ENCODING_7BIT_ASCII                 = 0x02;
-    public static final int ENCODING_IA5                        = 0x03;
-    public static final int ENCODING_UNICODE_16                 = 0x04;
-    public static final int ENCODING_SHIFT_JIS                  = 0x05;
-    public static final int ENCODING_KOREAN                     = 0x06;
-    public static final int ENCODING_LATIN_HEBREW               = 0x07;
-    public static final int ENCODING_LATIN                      = 0x08;
-    public static final int ENCODING_GSM_7BIT_ALPHABET          = 0x09;
-    public static final int ENCODING_GSM_DCS                    = 0x0A;
-
-    /**
-     * IS-91 message types.
-     * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3)
-     */
-    public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS   = 0x82;
-    public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83;
-    public static final int IS91_MSG_TYPE_CLI                = 0x84;
-    public static final int IS91_MSG_TYPE_SHORT_MESSAGE      = 0x85;
-
-    /**
-     * US ASCII character mapping table.
-     *
-     * This table contains only the printable ASCII characters, with a
-     * 0x20 offset, meaning that the ASCII SPACE character is at index
-     * 0, with the resulting code of 0x20.
-     *
-     * Note this mapping is also equivalent to that used by both the
-     * IA5 and the IS-91 encodings.  For the former this is defined
-     * using CCITT Rec. T.50 Tables 1 and 3.  For the latter IS 637 B,
-     * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits,
-     * and hence only maps entries up to the '_' character.
-     *
-     */
-    public static final char[] ASCII_MAP = {
-        ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
-        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
-        '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
-        '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-        'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'};
-
-    /**
-     * Character to use when forced to encode otherwise unencodable
-     * characters, meaning those not in the respective ASCII or GSM
-     * 7-bit encoding tables.  Current choice is SPACE, which is 0x20
-     * in both the GSM-7bit and ASCII-7bit encodings.
-     */
-    static final byte UNENCODABLE_7_BIT_CHAR = 0x20;
-
-    /**
-     * Only elements between these indices in the ASCII table are printable.
-     */
-    public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
-    public static final int ASCII_NL_INDEX = 0x0A;
-    public static final int ASCII_CR_INDEX = 0x0D;
-    public static final SparseIntArray charToAscii = new SparseIntArray();
-    static {
-        for (int i = 0; i < ASCII_MAP.length; i++) {
-            charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
-        }
-        charToAscii.put('\n', ASCII_NL_INDEX);
-        charToAscii.put('\r', ASCII_CR_INDEX);
-    }
-
-    /*
-     * TODO(cleanup): Move this very generic functionality somewhere
-     * more general.
-     */
-    /**
-     * Given a string generate a corresponding ASCII-encoded byte
-     * array, but limited to printable characters.  If the input
-     * contains unprintable characters, return null.
-     */
-    public static byte[] stringToAscii(String str) {
-        int len = str.length();
-        byte[] result = new byte[len];
-        for (int i = 0; i < len; i++) {
-            int charCode = charToAscii.get(str.charAt(i), -1);
-            if (charCode == -1) return null;
-            result[i] = (byte)charCode;
-        }
-        return result;
-    }
-
-    /**
-     * Mapping for ASCII values less than 32 are flow control signals
-     * and not used here.
-     */
-    public static final int ASCII_MAP_BASE_INDEX = 0x20;
-    public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1;
-
-    /**
-     * Contains the data header of the user data
-     */
-    public SmsHeader userDataHeader;
-
-    /**
-     * Contains the data encoding type for the SMS message
-     */
-    public int msgEncoding;
-    public boolean msgEncodingSet = false;
-
-    public int msgType;
-
-    /**
-     * Number of invalid bits in the last byte of data.
-     */
-    public int paddingBits;
-
-    public int numFields;
-
-    /**
-     * Contains the user data of a SMS message
-     * (See 3GPP2 C.S0015-B, v2, 4.5.2)
-     */
-    public byte[] payload;
-    public String payloadStr;
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("UserData ");
-        builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset"));
-        builder.append(", msgType=" + msgType);
-        builder.append(", paddingBits=" + paddingBits);
-        builder.append(", numFields=" + numFields);
-        builder.append(", userDataHeader=" + userDataHeader);
-        builder.append(", payload='" + HexDump.toHexString(payload) + "'");
-        builder.append(", payloadStr='" + payloadStr + "'");
-        builder.append(" }");
-        return builder.toString();
-    }
-
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/package.html b/src/java/com/android/internal/telephony/cdma/sms/package.html
deleted file mode 100644
index b2bc736..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Provides CDMA-specific features for text/data/PDU SMS messages
-@hide
-</BODY>
-</HTML>
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
index 00c77bc..0ce1991 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
@@ -24,6 +24,7 @@
 import android.telephony.ServiceState;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.uicc.IccRecords;
@@ -404,15 +405,41 @@
         return false;
     }
 
-    public static boolean isMeteredApnType(String type, Context context, int subId,
-                                           boolean isRoaming) {
+    /**
+     * Check if this APN type is metered.
+     *
+     * @param type The APN type
+     * @param phone The phone object
+     * @return True if the APN type is metered, otherwise false.
+     */
+    public static boolean isMeteredApnType(String type, Phone phone) {
+        if (phone == null) {
+            return true;
+        }
 
-        String carrierConfig = (isRoaming) ?
-                CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS :
-                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS;
+        boolean isRoaming = phone.getServiceState().getDataRoaming();
+        boolean isIwlan = phone.getServiceState().getRilDataRadioTechnology()
+                == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+        int subId = phone.getSubId();
+
+        String carrierConfig;
+        // First check if the device is in IWLAN mode. If yes, use the IWLAN metered APN list. Then
+        // check if the device is roaming. If yes, use the roaming metered APN list. Otherwise, use
+        // the normal metered APN list.
+        if (isIwlan) {
+            carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS;
+        } else if (isRoaming) {
+            carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS;
+        } else {
+            carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS;
+        }
+
+        if (DBG) {
+            Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming + ", isIwlan=" + isIwlan);
+        }
 
         CarrierConfigManager configManager = (CarrierConfigManager)
-                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+                phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) {
             Rlog.e(LOG_TAG, "Carrier config service is not available");
             return true;
@@ -432,44 +459,49 @@
 
         HashSet<String> meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes));
         if (DBG) {
-            Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " +
-                    Arrays.toString(meteredApnSet.toArray()) +
-                    " isRoaming: " + isRoaming);
+            Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are "
+                    + Arrays.toString(meteredApnSet.toArray()));
         }
 
         // If all types of APN are metered, then this APN setting must be metered.
         if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) {
-            if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming);
+            if (DBG) Rlog.d(LOG_TAG, "All APN types are metered.");
             return true;
         }
 
         if (meteredApnSet.contains(type)) {
-            if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming);
+            if (DBG) Rlog.d(LOG_TAG, type + " is metered.");
             return true;
         } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) {
             // Assuming no configuration error, if at least one APN type is
             // metered, then this APN setting is metered.
             if (meteredApnSet.size() > 0) {
-                if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " +
-                        isRoaming);
+                if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered.");
                 return true;
             }
         }
 
-        if (DBG) Rlog.d(LOG_TAG, type + " is not metered. isRoaming: " + isRoaming);
+        if (DBG) Rlog.d(LOG_TAG, type + " is not metered.");
         return false;
     }
 
-    public boolean isMetered(Context context, int subId, boolean isRoaming ) {
+    /**
+     * Check if this APN setting is metered.
+     *
+     * @param phone The phone object
+     * @return True if this APN setting is metered, otherwise false.
+     */
+    public boolean isMetered(Phone phone) {
+        if (phone == null) {
+            return true;
+        }
+
         for (String type : types) {
             // If one of the APN type is metered, then this APN setting is metered.
-            if (isMeteredApnType(type, context, subId, isRoaming)) {
-                if (DBG) Rlog.d(LOG_TAG, "Metered. APN = " + toString() +
-                        "isRoaming: " + isRoaming);
+            if (isMeteredApnType(type, phone)) {
                 return true;
             }
         }
-        if (DBG) Rlog.d(LOG_TAG, "Not metered. APN = " + toString() + "isRoaming: " + isRoaming);
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 75f515e..8662bd3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -104,14 +104,17 @@
         ApnContext mApnContext;
         int mProfileId;
         int mRilRat;
+        final boolean mUnmeteredUseOnly;
         Message mOnCompletedMsg;
         final int mConnectionGeneration;
 
-        ConnectionParams(ApnContext apnContext, int profileId,
-                int rilRadioTechnology, Message onCompletedMsg, int connectionGeneration) {
+        ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology,
+                         boolean unmeteredUseOnly,  Message onCompletedMsg,
+                         int connectionGeneration) {
             mApnContext = apnContext;
             mProfileId = profileId;
             mRilRat = rilRadioTechnology;
+            mUnmeteredUseOnly = unmeteredUseOnly;
             mOnCompletedMsg = onCompletedMsg;
             mConnectionGeneration = connectionGeneration;
         }
@@ -121,6 +124,7 @@
             return "{mTag=" + mTag + " mApnContext=" + mApnContext
                     + " mProfileId=" + mProfileId
                     + " mRat=" + mRilRat
+                    + " mUnmeteredUseOnly=" + mUnmeteredUseOnly
                     + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
         }
     }
@@ -255,10 +259,6 @@
 
     /* Getter functions */
 
-    NetworkCapabilities getCopyNetworkCapabilities() {
-        return makeNetworkCapabilities();
-    }
-
     LinkProperties getCopyLinkProperties() {
         return new LinkProperties(mLinkProperties);
     }
@@ -852,21 +852,26 @@
 
         // Do we need a restricted network to satisfy the request?
         // Is this network metered?  If not, then don't add restricted
-        if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
-                mPhone.getServiceState().getDataRoaming())) {
+        if (!mApnSetting.isMetered(mPhone)) {
             return;
         }
 
         // Is data disabled?
-        mRestrictedNetworkOverride = (mDct.isDataEnabled(true) == false);
+        mRestrictedNetworkOverride = !mDct.isDataEnabled();
     }
 
-    private NetworkCapabilities makeNetworkCapabilities() {
+    NetworkCapabilities getNetworkCapabilities() {
         NetworkCapabilities result = new NetworkCapabilities();
         result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
 
         if (mApnSetting != null) {
             for (String type : mApnSetting.types) {
+                if (!mRestrictedNetworkOverride
+                        && (mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly)
+                        && ApnSetting.isMeteredApnType(type, mPhone)) {
+                    log("Dropped the metered " + type + " for the unmetered data call.");
+                    continue;
+                }
                 switch (type) {
                     case PhoneConstants.APN_TYPE_ALL: {
                         result.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
@@ -921,10 +926,12 @@
                 }
             }
 
-            // If none of the APN types associated with this APN setting is metered,
-            // then we apply NOT_METERED capability to the network.
-            if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
-                    mPhone.getServiceState().getDataRoaming())) {
+            // Mark NOT_METERED in the following cases,
+            // 1. All APNs in APN settings are unmetered.
+            // 2. The non-restricted data and is intended for unmetered use only.
+            if (((mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly)
+                    && !mRestrictedNetworkOverride)
+                    || !mApnSetting.isMetered(mPhone)) {
                 result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
                 mNetworkInfo.setMetered(false);
             } else {
@@ -1143,7 +1150,7 @@
                     break;
                 }
                 case DcAsyncChannel.REQ_GET_NETWORK_CAPABILITIES: {
-                    NetworkCapabilities nc = getCopyNetworkCapabilities();
+                    NetworkCapabilities nc = getNetworkCapabilities();
                     if (VDBG) log("REQ_GET_NETWORK_CAPABILITIES networkCapabilities" + nc);
                     mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_NETWORK_CAPABILITIES, nc);
                     break;
@@ -1205,7 +1212,7 @@
                             TelephonyManager.getNetworkTypeName(networkType));
                     if (mNetworkAgent != null) {
                         updateNetworkInfoSuspendState();
-                        mNetworkAgent.sendNetworkCapabilities(makeNetworkCapabilities());
+                        mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
                         mNetworkAgent.sendNetworkInfo(mNetworkInfo);
                         mNetworkAgent.sendLinkProperties(mLinkProperties);
                     }
@@ -1530,34 +1537,23 @@
 
             // verify and get updated information in case these things
             // are obsolete
-            {
-                ServiceState ss = mPhone.getServiceState();
-                final int networkType = ss.getDataNetworkType();
-                if (mNetworkInfo.getSubtype() != networkType) {
-                    log("DcActiveState with incorrect subtype (" + mNetworkInfo.getSubtype() +
-                            ", " + networkType + "), updating.");
-                }
-                mNetworkInfo.setSubtype(networkType, TelephonyManager.getNetworkTypeName(networkType));
-                final boolean roaming = ss.getDataRoaming();
-                if (roaming != mNetworkInfo.isRoaming()) {
-                    log("DcActiveState with incorrect roaming (" + mNetworkInfo.isRoaming() +
-                            ", " + roaming +"), updating.");
-                }
-                mNetworkInfo.setRoaming(roaming);
+            ServiceState ss = mPhone.getServiceState();
+            final int networkType = ss.getDataNetworkType();
+            if (mNetworkInfo.getSubtype() != networkType) {
+                log("DcActiveState with incorrect subtype (" + mNetworkInfo.getSubtype()
+                        + ", " + networkType + "), updating.");
+            }
+            mNetworkInfo.setSubtype(networkType, TelephonyManager.getNetworkTypeName(networkType));
+            final boolean roaming = ss.getDataRoaming();
+            if (roaming != mNetworkInfo.isRoaming()) {
+                log("DcActiveState with incorrect roaming (" + mNetworkInfo.isRoaming()
+                        + ", " + roaming + "), updating.");
             }
 
-            boolean createNetworkAgent = true;
-            // If a disconnect is already pending, avoid notifying all of connected
-            if (hasMessages(EVENT_DISCONNECT) ||
-                    hasMessages(EVENT_DISCONNECT_ALL) ||
-                    hasDeferredMessages(EVENT_DISCONNECT) ||
-                    hasDeferredMessages(EVENT_DISCONNECT_ALL)) {
-                log("DcActiveState: skipping notifyAllOfConnected()");
-                createNetworkAgent = false;
-            } else {
-                // If we were retrying there maybe more than one, otherwise they'll only be one.
-                notifyAllOfConnected(Phone.REASON_CONNECTED);
-            }
+            mNetworkInfo.setRoaming(roaming);
+
+            // If we were retrying there maybe more than one, otherwise they'll only be one.
+            notifyAllOfConnected(Phone.REASON_CONNECTED);
 
             mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(),
                     DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null);
@@ -1582,12 +1578,10 @@
             }
             misc.subscriberId = mPhone.getSubscriberId();
 
-            if (createNetworkAgent) {
-                setNetworkRestriction();
-                mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
-                        "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
-                        50, misc);
-            }
+            setNetworkRestriction();
+            mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
+                    "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
+                    50, misc);
         }
 
         @Override
@@ -1707,7 +1701,7 @@
                     } else {
                         final ArrayList<Integer> capInfo = (ArrayList<Integer>)ar.result;
                         final int lceBwDownKbps = capInfo.get(0);
-                        NetworkCapabilities nc = makeNetworkCapabilities();
+                        NetworkCapabilities nc = getNetworkCapabilities();
                         if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) {
                             nc.setLinkDownstreamBandwidthKbps(lceBwDownKbps);
                             if (mNetworkAgent != null) {
@@ -2060,7 +2054,7 @@
                 + " mLastFailCause=" + mLastFailCause
                 + " mTag=" + mTag
                 + " mLinkProperties=" + mLinkProperties
-                + " linkCapabilities=" + makeNetworkCapabilities()
+                + " linkCapabilities=" + getNetworkCapabilities()
                 + " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride;
     }
 
@@ -2110,7 +2104,7 @@
         pw.flush();
         pw.println(" mDataRegState=" + mDataRegState);
         pw.println(" mRilRat=" + mRilRat);
-        pw.println(" mNetworkCapabilities=" + makeNetworkCapabilities());
+        pw.println(" mNetworkCapabilities=" + getNetworkCapabilities());
         pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
         pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
         pw.println(" mLastFailCause=" + mLastFailCause);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
new file mode 100644
index 0000000..e949acf
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
@@ -0,0 +1,132 @@
+/*
+ * 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.dataconnection;
+
+import java.util.HashSet;
+
+/**
+ * The class to describe the reasons of allowing or disallowing to establish a data connection.
+ */
+public class DataConnectionReasons {
+    private HashSet<DataDisallowedReasonType> mDataDisallowedReasonSet = new HashSet<>();
+    private DataAllowedReasonType mDataAllowedReason = DataAllowedReasonType.NONE;
+
+    public DataConnectionReasons() {}
+
+    void add(DataDisallowedReasonType reason) {
+        // Adding a disallowed reason will clean up the allowed reason because they are
+        // mutual exclusive.
+        mDataAllowedReason = DataAllowedReasonType.NONE;
+        mDataDisallowedReasonSet.add(reason);
+    }
+
+    void add(DataAllowedReasonType reason) {
+        // Adding an allowed reason will clean up the disallowed reasons because they are
+        // mutual exclusive.
+        mDataDisallowedReasonSet.clear();
+
+        // Only higher priority allowed reason can overwrite the old one. See
+        // DataAllowedReasonType for the oder.
+        if (reason.ordinal() > mDataAllowedReason.ordinal()) {
+            mDataAllowedReason = reason;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder reasonStr = new StringBuilder();
+        if (mDataDisallowedReasonSet.size() > 0) {
+            reasonStr.append("Data disallowed, reasons:");
+            for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
+                reasonStr.append(" ").append(reason);
+            }
+        } else {
+            reasonStr.append("Data allowed, reason:");
+            reasonStr.append(" ").append(mDataAllowedReason);
+        }
+        return reasonStr.toString();
+    }
+
+    void copyFrom(DataConnectionReasons reasons) {
+        this.mDataDisallowedReasonSet = reasons.mDataDisallowedReasonSet;
+        this.mDataAllowedReason = reasons.mDataAllowedReason;
+    }
+
+    boolean allowed() {
+        return mDataDisallowedReasonSet.size() == 0;
+    }
+
+    boolean contains(DataDisallowedReasonType reason) {
+        return mDataDisallowedReasonSet.contains(reason);
+    }
+
+    boolean contains(DataAllowedReasonType reason) {
+        return reason == mDataAllowedReason;
+    }
+
+    boolean containsHardDisallowedReasons() {
+        for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
+            if (reason.isHardReason()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Disallowed reasons. There could be multiple reasons if data connection is not allowed.
+    enum DataDisallowedReasonType {
+        // Soft failure reasons. Normally the reasons from users or policy settings.
+        DATA_DISABLED(false),                   // Data is disabled by the user or policy.
+        ROAMING_DISABLED(false),                // Data roaming is disabled by the user.
+
+        // Belows are all hard failure reasons.
+        NOT_ATTACHED(true),
+        RECORD_NOT_LOADED(true),
+        INVALID_PHONE_STATE(true),
+        CONCURRENT_VOICE_DATA_NOT_ALLOWED(true),
+        PS_RESTRICTED(true),
+        UNDESIRED_POWER_STATE(true),
+        INTERNAL_DATA_DISABLED(true),
+        DEFAULT_DATA_UNSELECTED(true),
+        RADIO_DISABLED_BY_CARRIER(true),
+        APN_NOT_CONNECTABLE(true),
+        ON_IWLAN(true),
+        IN_ECBM(true);
+
+        private boolean mIsHardReason;
+
+        boolean isHardReason() {
+            return mIsHardReason;
+        }
+
+        DataDisallowedReasonType(boolean isHardReason) {
+            mIsHardReason = isHardReason;
+        }
+    }
+
+    // Data allowed reasons. There will be only one reason if data is allowed.
+    enum DataAllowedReasonType {
+        // Note that unlike disallowed reasons, we only have one allowed reason every time
+        // when we check data is allowed or not. The order of these allowed reasons is very
+        // important. The lower ones take precedence over the upper ones.
+        NONE,
+        NORMAL,
+        UNMETERED_APN,
+        RESTRICTED_REQUEST,
+        EMERGENCY_APN,
+    }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
index a052f6a..a8bffd3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -63,10 +63,17 @@
 
     private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();
 
+    @Override
+    public String toString() {
+        return "[mInternalDataEnabled=" + mInternalDataEnabled + ", mUserDataEnabled="
+                + mUserDataEnabled + ", mPolicyDataEnabled=" + mPolicyDataEnabled
+                + ", mCarrierDataEnabled=" + mCarrierDataEnabled + "]";
+    }
+
     public synchronized void setInternalDataEnabled(boolean enabled) {
-        boolean prevDataEnabled = isDataEnabled(true);
+        boolean prevDataEnabled = isDataEnabled();
         mInternalDataEnabled = enabled;
-        if (prevDataEnabled != isDataEnabled(true)) {
+        if (prevDataEnabled != isDataEnabled()) {
             notifyDataEnabledChanged(!prevDataEnabled, REASON_INTERNAL_DATA_ENABLED);
         }
     }
@@ -75,9 +82,9 @@
     }
 
     public synchronized void setUserDataEnabled(boolean enabled) {
-        boolean prevDataEnabled = isDataEnabled(true);
+        boolean prevDataEnabled = isDataEnabled();
         mUserDataEnabled = enabled;
-        if (prevDataEnabled != isDataEnabled(true)) {
+        if (prevDataEnabled != isDataEnabled()) {
             notifyDataEnabledChanged(!prevDataEnabled, REASON_USER_DATA_ENABLED);
         }
     }
@@ -86,9 +93,9 @@
     }
 
     public synchronized void setPolicyDataEnabled(boolean enabled) {
-        boolean prevDataEnabled = isDataEnabled(true);
+        boolean prevDataEnabled = isDataEnabled();
         mPolicyDataEnabled = enabled;
-        if (prevDataEnabled != isDataEnabled(true)) {
+        if (prevDataEnabled != isDataEnabled()) {
             notifyDataEnabledChanged(!prevDataEnabled, REASON_POLICY_DATA_ENABLED);
         }
     }
@@ -97,9 +104,9 @@
     }
 
     public synchronized void setCarrierDataEnabled(boolean enabled) {
-        boolean prevDataEnabled = isDataEnabled(true);
+        boolean prevDataEnabled = isDataEnabled();
         mCarrierDataEnabled = enabled;
-        if (prevDataEnabled != isDataEnabled(true)) {
+        if (prevDataEnabled != isDataEnabled()) {
             notifyDataEnabledChanged(!prevDataEnabled, REASON_DATA_ENABLED_BY_CARRIER);
         }
     }
@@ -107,11 +114,9 @@
         return mCarrierDataEnabled;
     }
 
-    public synchronized boolean isDataEnabled(boolean checkUserDataEnabled) {
-        return (mInternalDataEnabled
-                && (!checkUserDataEnabled || mUserDataEnabled)
-                && (!checkUserDataEnabled || mPolicyDataEnabled)
-                && (!checkUserDataEnabled || mCarrierDataEnabled));
+    public synchronized boolean isDataEnabled() {
+        return (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
+                && mCarrierDataEnabled);
     }
 
     private void notifyDataEnabledChanged(boolean enabled, int reason) {
@@ -120,7 +125,7 @@
 
     public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
         mDataEnabledChangedRegistrants.addUnique(h, what, obj);
-        notifyDataEnabledChanged(isDataEnabled(true), REASON_REGISTERED);
+        notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED);
     }
 
     public void unregisterForDataEnabledChanged(Handler h) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
index 13ab30b..67d91d3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
@@ -16,16 +16,16 @@
 
 package com.android.internal.telephony.dataconnection;
 
-import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
-import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-
 import android.net.LinkProperties;
 import android.net.NetworkCapabilities;
 import android.net.ProxyInfo;
 import android.os.Message;
 
+import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
+import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
 /**
  * AsyncChannel to a DataConnection
  */
@@ -319,7 +319,7 @@
      * Evaluate RSP_GET_NETWORK_CAPABILITIES
      *
      * @param response
-     * @return NetworkCapabilites, maybe null.
+     * @return NetworkCapabilities, maybe null.
      */
     public NetworkCapabilities rspNetworkCapabilities(Message response) {
         NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
@@ -342,7 +342,7 @@
                 value = null;
             }
         } else {
-            value = mDc.getCopyNetworkCapabilities();
+            value = mDc.getNetworkCapabilities();
         }
         return value;
     }
@@ -357,23 +357,29 @@
 
     /**
      * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
-     * Used for cellular networks that use Acesss Point Names (APN) such
+     * Used for cellular networks that use Access Point Names (APN) such
      * as GSM networks.
      *
      * @param apnContext is the Access Point Name to bring up a connection to
-     * @param profileId for the conneciton
+     * @param profileId for the connection
+     * @param rilRadioTechnology Radio technology for the data connection
+     * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes
      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
-     *        With AsyncResult.userObj set to the original msg.obj,
-     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     *                       With AsyncResult.userObj set to the original msg.obj,
+     *                       AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     * @param connectionGeneration used to track a single connection request so disconnects can get
+     *                             ignored if obsolete.
      */
     public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
-                        Message onCompletedMsg, int connectionGeneration) {
+                        boolean unmeteredUseOnly, Message onCompletedMsg,
+                        int connectionGeneration) {
         if (DBG) {
-            log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
+            log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly
+                    + " onCompletedMsg=" + onCompletedMsg);
         }
         sendMessage(DataConnection.EVENT_CONNECT,
-                new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
-                        connectionGeneration));
+                new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly,
+                        onCompletedMsg, connectionGeneration));
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 176fa53..f00bfe6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -84,8 +84,9 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType;
+import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.telephony.uicc.IccRecords;
 import com.android.internal.telephony.uicc.UiccController;
@@ -98,7 +99,6 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.PriorityQueue;
@@ -160,57 +160,6 @@
     private static final String INTENT_DATA_STALL_ALARM =
             "com.android.internal.telephony.data-stall";
 
-    @VisibleForTesting
-    public static class DataAllowFailReason {
-        private HashSet<DataAllowFailReasonType> mDataAllowFailReasonSet = new HashSet<>();
-
-        public void addDataAllowFailReason(DataAllowFailReasonType type) {
-            mDataAllowFailReasonSet.add(type);
-        }
-
-        public String getDataAllowFailReason() {
-            StringBuilder failureReason = new StringBuilder();
-            failureReason.append("isDataAllowed: No");
-            for(DataAllowFailReasonType reason : mDataAllowFailReasonSet) {
-                failureReason.append(reason.mFailReasonStr);
-            }
-            return failureReason.toString();
-        }
-
-        public boolean isFailForSingleReason(DataAllowFailReasonType failReasonType) {
-            return (mDataAllowFailReasonSet.size() == 1) &&
-                    (mDataAllowFailReasonSet.contains(failReasonType));
-        }
-
-        public void clearAllReasons() {
-            mDataAllowFailReasonSet.clear();
-        }
-
-        public boolean isFailed() {
-            return mDataAllowFailReasonSet.size() > 0;
-        }
-    }
-
-    @VisibleForTesting
-    public enum DataAllowFailReasonType {
-        NOT_ATTACHED(" - Not attached"),
-        RECORD_NOT_LOADED(" - SIM not loaded"),
-        ROAMING_DISABLED(" - Roaming and data roaming not enabled"),
-        INVALID_PHONE_STATE(" - PhoneState is not idle"),
-        CONCURRENT_VOICE_DATA_NOT_ALLOWED(" - Concurrent voice and data not allowed"),
-        PS_RESTRICTED(" - mIsPsRestricted= true"),
-        UNDESIRED_POWER_STATE(" - desiredPowerState= false"),
-        INTERNAL_DATA_DISABLED(" - mInternalDataEnabled= false"),
-        DEFAULT_DATA_UNSELECTED(" - defaultDataSelected= false"),
-        RADIO_DISABLED_BY_CARRIER(" - powerStateFromCarrier= false");
-
-        public String mFailReasonStr;
-
-        DataAllowFailReasonType(String reason) {
-            mFailReasonStr = reason;
-        }
-    }
-
     private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
     private DcController mDcc;
 
@@ -473,13 +422,19 @@
     }
 
     private void onActionIntentReconnectAlarm(Intent intent) {
-        String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
-        String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
+        Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT);
+        msg.setData(intent.getExtras());
+        sendMessage(msg);
+    }
+
+    private void onDataReconnect(Bundle bundle) {
+        String reason = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_REASON);
+        String apnType = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
 
         int phoneSubId = mPhone.getSubId();
-        int currSubId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+        int currSubId = bundle.getInt(PhoneConstants.SUBSCRIPTION_KEY,
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-        log("onActionIntentReconnectAlarm: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
+        log("onDataReconnect: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
 
         // Stop reconnect if not current subId is not correct.
         // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
@@ -491,33 +446,33 @@
         ApnContext apnContext = mApnContexts.get(apnType);
 
         if (DBG) {
-            log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
-                    " apnType=" + apnType + " apnContext=" + apnContext +
-                    " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
+            log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType
+                    + " apnContext=" + apnContext + " mDataConnectionAsyncChannels="
+                    + mDataConnectionAcHashMap);
         }
 
         if ((apnContext != null) && (apnContext.isEnabled())) {
             apnContext.setReason(reason);
             DctConstants.State apnContextState = apnContext.getState();
             if (DBG) {
-                log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
+                log("onDataReconnect: apnContext state=" + apnContextState);
             }
             if ((apnContextState == DctConstants.State.FAILED)
                     || (apnContextState == DctConstants.State.IDLE)) {
                 if (DBG) {
-                    log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
+                    log("onDataReconnect: state is FAILED|IDLE, disassociate");
                 }
                 DcAsyncChannel dcac = apnContext.getDcAc();
                 if (dcac != null) {
                     if (DBG) {
-                        log("onActionIntentReconnectAlarm: tearDown apnContext=" + apnContext);
+                        log("onDataReconnect: tearDown apnContext=" + apnContext);
                     }
                     dcac.tearDown(apnContext, "", null);
                 }
                 apnContext.setDataConnectionAc(null);
                 apnContext.setState(DctConstants.State.IDLE);
             } else {
-                if (DBG) log("onActionIntentReconnectAlarm: keep associated");
+                if (DBG) log("onDataReconnect: keep associated");
             }
             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
@@ -900,8 +855,7 @@
                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA + phoneSubId,
                             enabled ? 1 : 0);
                 }
-                if (getDataOnRoamingEnabled() == false &&
-                        mPhone.getServiceState().getDataRoaming() == true) {
+                if (!getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) {
                     if (enabled) {
                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
                     } else {
@@ -912,7 +866,7 @@
                 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
                 // handle the rest from there.
                 if (enabled) {
-                    teardownRestrictedMeteredConnections();
+                    reevaluateDataConnections();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
                     onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
@@ -922,33 +876,48 @@
     }
 
     /**
-     * Handle reverting restricted networks back to unrestricted.
-     * If we're changing user data to enabled and this makes data
-     * truely enabled (not disabled by other factors) we need to
-     * tear down any metered apn type that was enabled anyway by
-     * a privileged request.  This allows us to reconnect
-     * to it in an unrestricted way.
+     * Reevaluate existing data connections when conditions change.
+     *
+     * For example, handle reverting restricted networks back to unrestricted. If we're changing
+     * user data to enabled and this makes data truly enabled (not disabled by other factors) we
+     * need to tear down any metered apn type that was enabled anyway by a privileged request.
+     * This allows us to reconnect to it in an unrestricted way.
+     *
+     * Or when we brought up a unmetered data connection while data is off, we only limit this
+     * data connection for unmetered use only. When data is turned back on, we need to tear that
+     * down so a full capable data connection can be re-established.
      */
-    private void teardownRestrictedMeteredConnections() {
-        if (mDataEnabledSettings.isDataEnabled(true)) {
+    private void reevaluateDataConnections() {
+        if (mDataEnabledSettings.isDataEnabled()) {
             for (ApnContext apnContext : mApnContexts.values()) {
-                if (apnContext.isConnectedOrConnecting() &&
-                        apnContext.getApnSetting().isMetered(mPhone.getContext(),
-                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {
-
-                    final DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
-                    if (dataConnectionAc != null) {
-                        final NetworkCapabilities nc =
-                                dataConnectionAc.getNetworkCapabilitiesSync();
-                        if (nc != null && nc.hasCapability(NetworkCapabilities.
-                              NET_CAPABILITY_NOT_RESTRICTED)) {
-                            if (DBG) log("not tearing down unrestricted metered net:" + apnContext);
-                            continue;
+                if (apnContext.isConnectedOrConnecting()) {
+                    final DcAsyncChannel dcac = apnContext.getDcAc();
+                    if (dcac != null) {
+                        final NetworkCapabilities netCaps = dcac.getNetworkCapabilitiesSync();
+                        if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities
+                                .NET_CAPABILITY_NOT_RESTRICTED)) {
+                            if (DBG) {
+                                log("Tearing down restricted net:" + apnContext);
+                            }
+                            // Tearing down the restricted data call (metered or unmetered) when
+                            // conditions change. This will allow reestablishing a new unrestricted
+                            // data connection.
+                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
+                            cleanUpConnection(true, apnContext);
+                        } else if (apnContext.getApnSetting().isMetered(mPhone)
+                                && (netCaps != null && netCaps.hasCapability(
+                                        NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) {
+                            if (DBG) {
+                                log("Tearing down unmetered net:" + apnContext);
+                            }
+                            // The APN settings is metered, but the data was still marked as
+                            // unmetered data, must be the unmetered data connection brought up when
+                            // data is off. We need to tear that down when data is enabled again.
+                            // This will allow reestablishing a new full capability data connection.
+                            apnContext.setReason(Phone.REASON_DATA_ENABLED);
+                            cleanUpConnection(true, apnContext);
                         }
                     }
-                    if (DBG) log("tearing down restricted metered net: " + apnContext);
-                    apnContext.setReason(Phone.REASON_DATA_ENABLED);
-                    cleanUpConnection(true, apnContext);
                 }
             }
         }
@@ -957,7 +926,7 @@
     private void onDeviceProvisionedChange() {
         if (getDataEnabled()) {
             mDataEnabledSettings.setUserDataEnabled(true);
-            teardownRestrictedMeteredConnections();
+            reevaluateDataConnections();
             onTrySetupData(Phone.REASON_DATA_ENABLED);
         } else {
             mDataEnabledSettings.setUserDataEnabled(false);
@@ -1077,38 +1046,6 @@
         }
     }
 
-    public boolean isDataPossible(String apnType) {
-        ApnContext apnContext = mApnContexts.get(apnType);
-        if (apnContext == null) {
-            return false;
-        }
-        boolean apnContextIsEnabled = apnContext.isEnabled();
-        DctConstants.State apnContextState = apnContext.getState();
-        boolean apnTypePossible = !(apnContextIsEnabled &&
-                (apnContextState == DctConstants.State.FAILED));
-        boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
-        // Set the emergency APN availability status as TRUE irrespective of conditions checked in
-        // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
-        boolean dataAllowed = isEmergencyApn || isDataAllowed(null);
-        boolean possible = dataAllowed && apnTypePossible;
-
-        if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
-                    || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
-                && (mPhone.getServiceState().getRilDataRadioTechnology()
-                == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
-            log("Default data call activation not possible in iwlan.");
-            possible = false;
-        }
-
-        if (VDBG) {
-            log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
-                            "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
-                    apnType, possible, dataAllowed, apnTypePossible,
-                    apnContextIsEnabled, apnContextState));
-        }
-        return possible;
-    }
-
     @Override
     protected void finalize() {
         if(DBG && mPhone != null) log("finalize");
@@ -1292,45 +1229,9 @@
         }
     }
 
-    /**
-     * Report on whether data connectivity is enabled for any APN.
-     * @return {@code false} if data connectivity has been explicitly disabled,
-     * {@code true} otherwise.
-     */
-    public boolean getAnyDataEnabled() {
-        if (!mDataEnabledSettings.isDataEnabled(true)) return false;
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-        if (!isDataAllowed(failureReason)) {
-            if (DBG) log(failureReason.getDataAllowFailReason());
-            return false;
-        }
-        for (ApnContext apnContext : mApnContexts.values()) {
-            // Make sure we don't have a context that is going down
-            // and is explicitly disabled.
-            if (isDataAllowedForApn(apnContext)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     @VisibleForTesting
-    public boolean isDataEnabled(boolean checkUserDataEnabled) {
-        return mDataEnabledSettings.isDataEnabled(checkUserDataEnabled);
-    }
-
-    private boolean isDataAllowedForApn(ApnContext apnContext) {
-        //If RAT is iwlan then dont allow default/IA PDP at all.
-        //Rest of APN types can be evaluated for remaining conditions.
-        if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
-                    || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
-                && (mPhone.getServiceState().getRilDataRadioTechnology()
-                == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
-            log("Default data call activation not allowed in iwlan.");
-            return false;
-        }
-
-        return apnContext.isReady();
+    public boolean isDataEnabled() {
+        return mDataEnabledSettings.isDataEnabled();
     }
 
     //****** Called from ServiceStateTracker
@@ -1368,30 +1269,58 @@
         setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
     }
 
-    private boolean isDataAllowed(DataAllowFailReason failureReason) {
-        final boolean internalDataEnabled;
-        internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
+    /**
+     * Check if it is allowed to make a data connection (without checking APN context specific
+     * conditions).
+     *
+     * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
+     *                              param. It's okay to pass null here and no reasons will be
+     *                              provided.
+     * @return True if data connection is allowed, otherwise false.
+     */
+    public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) {
+        return isDataAllowed(null, dataConnectionReasons);
+    }
 
+    /**
+     * Check if it is allowed to make a data connection for a given APN type.
+     *
+     * @param apnContext APN context. If passing null, then will only check general but not APN
+     *                   specific conditions (e.g. APN state, metered/unmetered APN).
+     * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
+     *                              param. It's okay to pass null here and no reasons will be
+     *                              provided.
+     * @return True if data connection is allowed, otherwise false.
+     */
+    boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) {
+        // Step 1: Get all environment conditions.
+        // Step 2: Special handling for emergency APN.
+        // Step 3. Build disallowed reasons.
+        // Step 4: Determine if data should be allowed in some special conditions.
+
+        DataConnectionReasons reasons = new DataConnectionReasons();
+
+        // Step 1: Get all environment conditions.
+        final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
         boolean attachedState = mAttached.get();
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
         boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
+        // TODO: Remove this hack added by ag/641832.
         int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
         if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
             desiredPowerState = true;
             radioStateFromCarrier = true;
         }
 
-        IccRecords r = mIccRecords.get();
-        boolean recordsLoaded = false;
-        if (r != null) {
-            recordsLoaded = r.getRecordsLoaded();
-            if (DBG && !recordsLoaded) log("isDataAllowed getRecordsLoaded=" + recordsLoaded);
-        }
+        boolean recordsLoaded = mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded();
 
-        int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
-        boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub);
+        boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(
+                SubscriptionManager.getDefaultDataSubscriptionId());
 
-        PhoneConstants.State state = PhoneConstants.State.IDLE;
+        boolean isMeteredApnType = apnContext == null
+                || ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone);
+
+        PhoneConstants.State phoneState = PhoneConstants.State.IDLE;
         // Note this is explicitly not using mPhone.getState.  See b/19090488.
         // mPhone.getState reports the merge of CS and PS (volte) voice call state
         // but we only care about CS calls here for data/voice concurrency issues.
@@ -1400,52 +1329,110 @@
         // This should be redesigned to ask explicitly what we want:
         // voiceCallStateAllowDataCall, or dataCallAllowed or something similar.
         if (mPhone.getCallTracker() != null) {
-            state = mPhone.getCallTracker().getState();
+            phoneState = mPhone.getCallTracker().getState();
         }
 
-        if (failureReason != null) failureReason.clearAllReasons();
+        // Step 2: Special handling for emergency APN.
+        if (apnContext != null
+                && apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY)
+                && apnContext.isConnectable()) {
+            // If this is an emergency APN, as long as the APN is connectable, we
+            // should allow it.
+            if (dataConnectionReasons != null) {
+                dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN);
+            }
+            // Bail out without further checks.
+            return true;
+        }
+
+        // Step 3. Build disallowed reasons.
+        if (apnContext != null && !apnContext.isConnectable()) {
+            reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE);
+        }
+
+        // If RAT is IWLAN then don't allow default/IA PDP at all.
+        // Rest of APN types can be evaluated for remaining conditions.
+        if ((apnContext != null && (apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
+                || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA)))
+                && (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
+            reasons.add(DataDisallowedReasonType.ON_IWLAN);
+        }
+
+        if (isEmergency()) {
+            reasons.add(DataDisallowedReasonType.IN_ECBM);
+        }
+
         if (!(attachedState || mAutoAttachOnCreation.get())) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.NOT_ATTACHED);
+            reasons.add(DataDisallowedReasonType.NOT_ATTACHED);
         }
         if (!recordsLoaded) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.RECORD_NOT_LOADED);
+            reasons.add(DataDisallowedReasonType.RECORD_NOT_LOADED);
         }
-        if (state != PhoneConstants.State.IDLE &&
-                !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.INVALID_PHONE_STATE);
-            failureReason.addDataAllowFailReason(
-                    DataAllowFailReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
+        if (phoneState != PhoneConstants.State.IDLE
+                && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
+            reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE);
+            reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
         }
         if (!internalDataEnabled) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.INTERNAL_DATA_DISABLED);
+            reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED);
         }
         if (!defaultDataSelected) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(
-                    DataAllowFailReasonType.DEFAULT_DATA_UNSELECTED);
+            reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED);
         }
-        if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.ROAMING_DISABLED);
+        if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) {
+            reasons.add(DataDisallowedReasonType.ROAMING_DISABLED);
         }
         if (mIsPsRestricted) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.PS_RESTRICTED);
+            reasons.add(DataDisallowedReasonType.PS_RESTRICTED);
         }
         if (!desiredPowerState) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.UNDESIRED_POWER_STATE);
+            reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE);
         }
         if (!radioStateFromCarrier) {
-            if(failureReason == null) return false;
-            failureReason.addDataAllowFailReason(DataAllowFailReasonType.RADIO_DISABLED_BY_CARRIER);
+            reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER);
+        }
+        if (!mDataEnabledSettings.isDataEnabled()) {
+            reasons.add(DataDisallowedReasonType.DATA_DISABLED);
         }
 
-        return failureReason == null || !failureReason.isFailed();
+        // If there are hard disallowed reasons, we should not allow data connection no matter what.
+        if (reasons.containsHardDisallowedReasons()) {
+            if (dataConnectionReasons != null) {
+                dataConnectionReasons.copyFrom(reasons);
+            }
+            return false;
+        }
+
+        // Step 4: Determine if data should be allowed in some special conditions.
+
+        // At this point, if data is not allowed, it must be because of the soft reasons. We
+        // should start to check some special conditions that data will be allowed.
+
+        // If the request APN type is unmetered and there are soft disallowed reasons (e.g. data
+        // disabled, data roaming disabled) existing, we should allow the data because the user
+        // won't be charged anyway.
+        if (!isMeteredApnType && !reasons.allowed()) {
+            reasons.add(DataAllowedReasonType.UNMETERED_APN);
+        }
+
+        // If the request is restricted and there are only soft disallowed reasons (e.g. data
+        // disabled, data roaming disabled) existing, we should allow the data.
+        if (apnContext != null
+                && !apnContext.hasNoRestrictedRequests(true)
+                && !reasons.allowed()) {
+            reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST);
+        }
+
+        // If at this point, we still haven't built any disallowed reasons, we should allow data.
+        if (reasons.allowed()) {
+            reasons.add(DataAllowedReasonType.NORMAL);
+        }
+
+        if (dataConnectionReasons != null) {
+            dataConnectionReasons.copyFrom(reasons);
+        }
+
+        return reasons.allowed();
     }
 
     // arg for setupDataOnConnectableApns
@@ -1527,11 +1514,6 @@
     }
 
     private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) {
-        if (DBG) {
-            log("trySetupData for type:" + apnContext.getApnType() +
-                    " due to " + apnContext.getReason() + ", mIsPsRestricted=" + mIsPsRestricted);
-        }
-        apnContext.requestLog("trySetupData due to " + apnContext.getReason());
 
         if (mPhone.getSimulatedRadioControl() != null) {
             // Assume data is connected on the simulator
@@ -1543,34 +1525,13 @@
             return true;
         }
 
-        // Allow SETUP_DATA request for E-APN to be completed during emergency call
-        // and MOBILE DATA On/Off cases as well.
-        boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
-        final ServiceStateTracker sst = mPhone.getServiceStateTracker();
-
-        // set to false if apn type is non-metered or if we have a restricted (priveleged)
-        // request for the network.
-        // TODO - may want restricted requests to only apply to carrier-limited data access
-        //        rather than applying to user limited as well.
-        // Exclude DUN for the purposes of the override until we get finer grained
-        // intention in NetworkRequests
-        boolean checkUserDataEnabled =
-                ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
-                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
-                apnContext.hasNoRestrictedRequests(true /*exclude DUN */);
-
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-
-        // allow data if currently in roaming service, roaming setting disabled
-        // and requested apn type is non-metered for roaming.
-        boolean isDataAllowed = isDataAllowed(failureReason) ||
-                (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED) &&
-                !(ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
-                mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())));
-
-        if (apnContext.isConnectable() && (isEmergencyApn ||
-                (isDataAllowed && isDataAllowedForApn(apnContext) &&
-                        mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
+        DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+        boolean isDataAllowed = isDataAllowed(apnContext, dataConnectionReasons);
+        String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
+                + apnContext.getReason() + ". " + dataConnectionReasons.toString();
+        if (DBG) log(logStr);
+        apnContext.requestLog(logStr);
+        if (isDataAllowed) {
             if (apnContext.getState() == DctConstants.State.FAILED) {
                 String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
                 if (DBG) log(str);
@@ -1578,7 +1539,8 @@
                 apnContext.setState(DctConstants.State.IDLE);
             }
             int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
-            apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed());
+            apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker()
+                    .isConcurrentVoiceAndDataAllowed());
             if (apnContext.getState() == DctConstants.State.IDLE) {
                 if (waitingApns == null) {
                     waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
@@ -1599,7 +1561,8 @@
                 }
             }
 
-            boolean retValue = setupData(apnContext, radioTech);
+            boolean retValue = setupData(apnContext, radioTech, dataConnectionReasons.contains(
+                    DataAllowedReasonType.UNMETERED_APN));
             notifyOffApnsOfAvailability(apnContext.getReason());
 
             if (DBG) log("trySetupData: X retValue=" + retValue);
@@ -1613,48 +1576,30 @@
 
             StringBuilder str = new StringBuilder();
 
-            str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() +
-                    ", mState=" + apnContext.getState() + ", mDataEnabled=" +
-                    apnContext.isEnabled() + ", mDependencyMet=" +
-                    apnContext.getDependencyMet() + "] ");
+            str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType()
+                    + ", mState=" + apnContext.getState() + ", apnEnabled="
+                    + apnContext.isEnabled() + ", mDependencyMet="
+                    + apnContext.getDependencyMet() + "] ");
 
-            if (!apnContext.isConnectable()) {
-                str.append("isConnectable = false. ");
+            if (!mDataEnabledSettings.isDataEnabled()) {
+                str.append("isDataEnabled() = false. " + mDataEnabledSettings);
             }
-            if (!isDataAllowed) {
-                str.append("data not allowed: " + failureReason.getDataAllowFailReason() + ". ");
-            }
-            if (!isDataAllowedForApn(apnContext)) {
-                str.append("isDataAllowedForApn = false. RAT = " +
-                        mPhone.getServiceState().getRilDataRadioTechnology());
-            }
-            if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
-                str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
-                        "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
-                        ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
-                        ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
-                        ", isCarrierDataEnabled = " +
-                        mDataEnabledSettings.isCarrierDataEnabled());
-            }
-            if (isEmergency()) {
-                str.append("emergency = true");
+
+            // If this is a data retry, we should set the APN state to FAILED so it won't stay
+            // in SCANNING forever.
+            if (apnContext.getState() == DctConstants.State.SCANNING) {
+                apnContext.setState(DctConstants.State.FAILED);
+                str.append(" Stop retrying.");
             }
 
             if (DBG) log(str.toString());
             apnContext.requestLog(str.toString());
-
             return false;
         }
     }
 
     // Disabled apn's still need avail/unavail notifications - send them out
     private void notifyOffApnsOfAvailability(String reason) {
-        if (DBG) {
-            DataAllowFailReason failureReason = new DataAllowFailReason();
-            if (!isDataAllowed(failureReason)) {
-                log(failureReason.getDataAllowFailReason());
-            }
-        }
         for (ApnContext apnContext : mApnContexts.values()) {
             if (!mAttached.get() || !apnContext.isReady()) {
                 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
@@ -1699,8 +1644,7 @@
                 // Use ApnSetting to decide metered or non-metered.
                 // Tear down all metered data connections.
                 ApnSetting apnSetting = apnContext.getApnSetting();
-                if (apnSetting != null && apnSetting.isMetered(mPhone.getContext(),
-                        mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {
+                if (apnSetting != null && apnSetting.isMetered(mPhone)) {
                     if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
                     apnContext.setReason(reason);
                     cleanUpConnection(tearDown, apnContext);
@@ -2060,7 +2004,16 @@
         return null;
     }
 
-    private boolean setupData(ApnContext apnContext, int radioTech) {
+    /**
+     * Setup a data connection based on given APN type.
+     *
+     * @param apnContext APN context
+     * @param radioTech RAT of the data connection
+     * @param unmeteredUseOnly True if this data connection should be only used for unmetered
+     *                         purposes only.
+     * @return True if successful, otherwise false.
+     */
+    private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) {
         if (DBG) log("setupData: apnContext=" + apnContext);
         apnContext.requestLog("setupData");
         ApnSetting apnSetting;
@@ -2142,7 +2095,7 @@
         Message msg = obtainMessage();
         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
         msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
-        dcac.bringUp(apnContext, profileId, radioTech, msg, generation);
+        dcac.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation);
 
         if (DBG) log("setupData: initing!");
         return true;
@@ -2421,15 +2374,15 @@
 
                 if (!enabled) {
                     // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
-                    mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
+                    mPhone.notifyOtaspChanged(TelephonyManager.OTASP_SIM_UNPROVISIONED);
                     // Tear down all metered apns
                     cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
                 } else {
-                    // Re-evauluate Otasp state
+                    // Re-evaluate Otasp state
                     int otaspState = mPhone.getServiceStateTracker().getOtasp();
                     mPhone.notifyOtaspChanged(otaspState);
 
-                    teardownRestrictedMeteredConnections();
+                    reevaluateDataConnections();
                     setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
                 }
             }
@@ -2473,14 +2426,14 @@
 
     private void onSetPolicyDataEnabled(boolean enabled) {
         synchronized (mDataEnabledSettings) {
-            final boolean prevEnabled = getAnyDataEnabled();
+            final boolean prevEnabled = isDataEnabled();
             if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) {
                 mDataEnabledSettings.setPolicyDataEnabled(enabled);
                 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
                 // handle the rest from there.
-                if (prevEnabled != getAnyDataEnabled()) {
+                if (prevEnabled != isDataEnabled()) {
                     if (!prevEnabled) {
-                        teardownRestrictedMeteredConnections();
+                        reevaluateDataConnections();
                         onTrySetupData(Phone.REASON_DATA_ENABLED);
                     } else {
                         onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
@@ -2505,7 +2458,6 @@
                 DctConstants.State state = apnContext.getState();
                 switch(state) {
                     case CONNECTING:
-                    case SCANNING:
                     case CONNECTED:
                     case DISCONNECTING:
                         // We're "READY" and active so just return
@@ -2515,6 +2467,7 @@
                     case IDLE:
                         // fall through: this is unexpected but if it happens cleanup and try setup
                     case FAILED:
+                    case SCANNING:
                     case RETRYING: {
                         // We're "READY" but not active so disconnect (cleanup = true) and
                         // connect (trySetup = true) to be sure we retry the connection.
@@ -2729,9 +2682,9 @@
     /**
      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
      */
-    public void setDataOnRoamingEnabled(boolean enabled) {
+    public void setDataRoamingEnabled(boolean enabled) {
         final int phoneSubId = mPhone.getSubId();
-        if (getDataOnRoamingEnabled() != enabled) {
+        if (getDataRoamingEnabled() != enabled) {
             int roaming = enabled ? 1 : 0;
 
             // For single SIM phones, this is a per phone property.
@@ -2745,12 +2698,12 @@
             mSubscriptionManager.setDataRoaming(roaming, phoneSubId);
             // will trigger handleDataOnRoamingChange() through observer
             if (DBG) {
-               log("setDataOnRoamingEnabled: set phoneSubId=" + phoneSubId
-                       + " isRoaming=" + enabled);
+                log("setDataRoamingEnabled: set phoneSubId=" + phoneSubId
+                        + " isRoaming=" + enabled);
             }
         } else {
             if (DBG) {
-                log("setDataOnRoamingEnabled: unchanged phoneSubId=" + phoneSubId
+                log("setDataRoamingEnabled: unchanged phoneSubId=" + phoneSubId
                         + " isRoaming=" + enabled);
              }
         }
@@ -2759,7 +2712,7 @@
     /**
      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
      */
-    public boolean getDataOnRoamingEnabled() {
+    public boolean getDataRoamingEnabled() {
         boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get(
                 "ro.com.android.dataroaming", "false"));
         final int phoneSubId = mPhone.getSubId();
@@ -2774,28 +2727,30 @@
                         Settings.Global.DATA_ROAMING, phoneSubId) != 0;
             }
         } catch (SettingNotFoundException snfe) {
-            if (DBG) log("getDataOnRoamingEnabled: SettingNofFoundException snfe=" + snfe);
+            if (DBG) log("getDataRoamingEnabled: SettingNofFoundException snfe=" + snfe);
         }
         if (VDBG) {
-            log("getDataOnRoamingEnabled: phoneSubId=" + phoneSubId +
-                    " isDataRoamingEnabled=" + isDataRoamingEnabled);
+            log("getDataRoamingEnabled: phoneSubId=" + phoneSubId
+                    + " isDataRoamingEnabled=" + isDataRoamingEnabled);
         }
         return isDataRoamingEnabled;
     }
 
-    private void onRoamingOff() {
-        if (DBG) log("onRoamingOff");
+    // When the data roaming status changes from roaming to non-roaming.
+    private void onDataRoamingOff() {
+        if (DBG) log("onDataRoamingOff");
 
-        // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn
-        // attach and send the data profile again as the modem should have both roaming and
-        // non-roaming protocol in place. Modem should choose the right protocol based on the
-        // roaming condition.
-        setInitialAttachApn();
-        setDataProfilesAsNeeded();
+        if (!getDataRoamingEnabled()) {
+            // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn
+            // attach and send the data profile again as the modem should have both roaming and
+            // non-roaming protocol in place. Modem should choose the right protocol based on the
+            // roaming condition.
+            setInitialAttachApn();
+            setDataProfilesAsNeeded();
 
-        if (!mDataEnabledSettings.isUserDataEnabled()) return;
+            // If the user did not enable data roaming, now when we transit from roaming to
+            // non-roaming, we should try to reestablish the data connection.
 
-        if (getDataOnRoamingEnabled() == false) {
             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
             setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
         } else {
@@ -2803,20 +2758,11 @@
         }
     }
 
-    private void onRoamingOn() {
-        if (DBG) log("onRoamingOn");
-
-        // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn
-        // attach and send the data profile again as the modem should have both roaming and
-        // non-roaming protocol in place. Modem should choose the right protocol based on the
-        // roaming condition.
-        setInitialAttachApn();
-        setDataProfilesAsNeeded();
-
-        if (!mDataEnabledSettings.isUserDataEnabled()) {
-            if (DBG) log("data not enabled by user");
-            return;
-        }
+    // This method is called
+    // 1. When the data roaming status changes from non-roaming to roaming.
+    // 2. When allowed data roaming settings is changed by the user.
+    private void onDataRoamingOnOrSettingsChanged() {
+        if (DBG) log("onDataRoamingOnOrSettingsChanged");
 
         // Check if the device is actually data roaming
         if (!mPhone.getServiceState().getDataRoaming()) {
@@ -2824,12 +2770,16 @@
             return;
         }
 
-        if (getDataOnRoamingEnabled()) {
-            if (DBG) log("onRoamingOn: setup data on roaming");
+        if (getDataRoamingEnabled()) {
+            if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming");
+
             setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
             notifyDataConnection(Phone.REASON_ROAMING_ON);
         } else {
-            if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
+            // If the user does not turn on data roaming, when we transit from non-roaming to
+            // roaming, we need to tear down the data connection otherwise the user might be
+            // charged for data roaming usage.
+            if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming.");
             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
         }
@@ -3845,11 +3795,11 @@
                 break;
 
             case DctConstants.EVENT_ROAMING_OFF:
-                onRoamingOff();
+                onDataRoamingOff();
                 break;
 
             case DctConstants.EVENT_ROAMING_ON:
-                onRoamingOn();
+                onDataRoamingOnOrSettingsChanged();
                 break;
 
             case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
@@ -4056,6 +4006,9 @@
             case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED:
                 onSetCarrierDataEnabled((AsyncResult) msg.obj);
                 break;
+            case DctConstants.EVENT_DATA_RECONNECT:
+                onDataReconnect(msg.getData());
+                break;
             default:
                 Rlog.e("DcTracker", "Unhandled event=" + msg);
                 break;
@@ -4238,9 +4191,8 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("DcTracker:");
         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
-        pw.println(" isInternalDataEnabled=" + mDataEnabledSettings.isInternalDataEnabled());
-        pw.println(" isUserDataEnabled=" + mDataEnabledSettings.isUserDataEnabled());
-        pw.println(" isPolicyDataEnabled=" + mDataEnabledSettings.isPolicyDataEnabled());
+        pw.println(" mDataEnabledSettings=" + mDataEnabledSettings);
+        pw.println(" isDataAllowed=" + isDataAllowed(null));
         pw.flush();
         pw.println(" mRequestedApnType=" + mRequestedApnType);
         pw.println(" mPhone=" + mPhone.getPhoneName());
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 532285a..355629a 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -135,6 +135,7 @@
     State mState = State.PENDING;
     CharSequence mMessage;
     private boolean mIsSsInfo = false;
+    private ResultReceiver mCallbackReceiver;
 
 
     //***** Class Variables
@@ -182,9 +183,13 @@
      *
      * Please see flow chart in TS 22.030 6.5.3.2
      */
+    public static GsmMmiCode newFromDialString(String dialString, GsmCdmaPhone phone,
+            UiccCardApplication app) {
+        return newFromDialString(dialString, phone, app, null);
+    }
 
-    public static GsmMmiCode
-    newFromDialString(String dialString, GsmCdmaPhone phone, UiccCardApplication app) {
+    public static GsmMmiCode newFromDialString(String dialString, GsmCdmaPhone phone,
+            UiccCardApplication app, ResultReceiver wrappedCallback) {
         Matcher m;
         GsmMmiCode ret = null;
 
@@ -201,6 +206,7 @@
             ret.mSic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
             ret.mPwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
             ret.mDialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
+            ret.mCallbackReceiver = wrappedCallback;
             // According to TS 22.030 6.5.2 "Structure of the MMI",
             // the dialing number should not ending with #.
             // The dialing number ending # is treated as unique USSD,
@@ -623,6 +629,11 @@
 
     }
 
+    @Override
+    public String getDialString() {
+        return mPoundString;
+    }
+
     static private boolean
     isTwoDigitShortCode(Context context, String dialString) {
         Rlog.d(LOG_TAG, "isTwoDigitShortCode");
@@ -1061,7 +1072,6 @@
         // response does not complete this MMI code...we wait for
         // an unsolicited USSD "Notify" or "Request".
         // The matching up of this is done in GsmCdmaPhone.
-
         mPhone.mCi.sendUSSD(ussdMessage,
             obtainMessage(EVENT_USSD_COMPLETE, this));
     }
@@ -1597,6 +1607,10 @@
         return sb;
     }
 
+    public ResultReceiver getUssdCallbackReceiver() {
+        return this.mCallbackReceiver;
+    }
+
     /***
      * TODO: It would be nice to have a method here that can take in a dialstring and
      * figure out if there is an MMI code embedded within it.  This code would replace
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
deleted file mode 100644
index 2fbf7ed..0000000
--- a/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
+++ /dev/null
@@ -1,153 +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 com.android.internal.telephony.gsm;
-
-import android.telephony.PhoneNumberUtils;
-import java.text.ParseException;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsAddress;
-
-public class GsmSmsAddress extends SmsAddress {
-
-    static final int OFFSET_ADDRESS_LENGTH = 0;
-
-    static final int OFFSET_TOA = 1;
-
-    static final int OFFSET_ADDRESS_VALUE = 2;
-
-    /**
-     * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field
-     *
-     * @param offset the offset of the Address-Length byte
-     * @param length the length in bytes rounded up, e.g. "2 +
-     *        (addressLength + 1) / 2"
-     * @throws ParseException
-     */
-
-    public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException {
-        origBytes = new byte[length];
-        System.arraycopy(data, offset, origBytes, 0, length);
-
-        // addressLength is the count of semi-octets, not bytes
-        int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff;
-
-        int toa = origBytes[OFFSET_TOA] & 0xff;
-        ton = 0x7 & (toa >> 4);
-
-        // TOA must have its high bit set
-        if ((toa & 0x80) != 0x80) {
-            throw new ParseException("Invalid TOA - high bit must be set. toa = " + toa,
-                    offset + OFFSET_TOA);
-        }
-
-        if (isAlphanumeric()) {
-            // An alphanumeric address
-            int countSeptets = addressLength * 4 / 7;
-
-            address = GsmAlphabet.gsm7BitPackedToString(origBytes,
-                    OFFSET_ADDRESS_VALUE, countSeptets);
-        } else {
-            // TS 23.040 9.1.2.5 says
-            // that "the MS shall interpret reserved values as 'Unknown'
-            // but shall store them exactly as received"
-
-            byte lastByte = origBytes[length - 1];
-
-            if ((addressLength & 1) == 1) {
-                // Make sure the final unused BCD digit is 0xf
-                origBytes[length - 1] |= 0xf0;
-            }
-            address = PhoneNumberUtils.calledPartyBCDToString(origBytes,
-                    OFFSET_TOA, length - OFFSET_TOA);
-
-            // And restore origBytes
-            origBytes[length - 1] = lastByte;
-        }
-    }
-
-    @Override
-    public String getAddressString() {
-        return address;
-    }
-
-    /**
-     * Returns true if this is an alphanumeric address
-     */
-    @Override
-    public boolean isAlphanumeric() {
-        return ton == TON_ALPHANUMERIC;
-    }
-
-    @Override
-    public boolean isNetworkSpecific() {
-        return ton == TON_NETWORK;
-    }
-
-    /**
-     * Returns true of this is a valid CPHS voice message waiting indicator
-     * address
-     */
-    public boolean isCphsVoiceMessageIndicatorAddress() {
-        // CPHS-style MWI message
-        // See CPHS 4.7 B.4.2.1
-        //
-        // Basically:
-        //
-        // - Originating address should be 4 bytes long and alphanumeric
-        // - Decode will result with two chars:
-        // - Char 1
-        // 76543210
-        // ^ set/clear indicator (0 = clear)
-        // ^^^ type of indicator (000 = voice)
-        // ^^^^ must be equal to 0001
-        // - Char 2:
-        // 76543210
-        // ^ line number (0 = line 1)
-        // ^^^^^^^ set to 0
-        //
-        // Remember, since the alpha address is stored in 7-bit compact form,
-        // the "line number" is really the top bit of the first address value
-        // byte
-
-        return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4
-                && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0;
-    }
-
-    /**
-     * Returns true if this is a valid CPHS voice message waiting indicator
-     * address indicating a "set" of "indicator 1" of type "voice message
-     * waiting"
-     */
-    public boolean isCphsVoiceMessageSet() {
-        // 0x11 means "set" "voice message waiting" "indicator 1"
-        return isCphsVoiceMessageIndicatorAddress()
-                && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11;
-
-    }
-
-    /**
-     * Returns true if this is a valid CPHS voice message waiting indicator
-     * address indicating a "clear" of "indicator 1" of type "voice message
-     * waiting"
-     */
-    public boolean isCphsVoiceMessageClear() {
-        // 0x10 means "clear" "voice message waiting" "indicator 1"
-        return isCphsVoiceMessageIndicatorAddress()
-                && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10;
-
-    }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
deleted file mode 100644
index 6bf22a0..0000000
--- a/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ /dev/null
@@ -1,314 +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 com.android.internal.telephony.gsm;
-
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.util.Pair;
-
-import com.android.internal.R;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsConstants;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is
- * public because {@link #createSmsCbMessage(SmsCbLocation, byte[][])} is used by some test cases.
- */
-public class GsmSmsCbMessage {
-
-    /**
-     * Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
-     */
-    private static final String[] LANGUAGE_CODES_GROUP_0 = {
-            "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
-            "pl", null
-    };
-
-    /**
-     * Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
-     */
-    private static final String[] LANGUAGE_CODES_GROUP_2 = {
-            "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
-            null, null
-    };
-
-    private static final char CARRIAGE_RETURN = 0x0d;
-
-    private static final int PDU_BODY_PAGE_LENGTH = 82;
-
-    /** Utility class with only static methods. */
-    private GsmSmsCbMessage() { }
-
-    /**
-     * Get built-in ETWS primary messages by category. ETWS primary message does not contain text,
-     * so we have to show the pre-built messages to the user.
-     *
-     * @param context Device context
-     * @param category ETWS message category defined in SmsCbConstants
-     * @return ETWS text message in string. Return an empty string if no match.
-     */
-    private static String getEtwsPrimaryMessage(Context context, int category) {
-        final Resources r = context.getResources();
-        switch (category) {
-            case ETWS_WARNING_TYPE_EARTHQUAKE:
-                return r.getString(R.string.etws_primary_default_message_earthquake);
-            case ETWS_WARNING_TYPE_TSUNAMI:
-                return r.getString(R.string.etws_primary_default_message_tsunami);
-            case ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI:
-                return r.getString(R.string.etws_primary_default_message_earthquake_and_tsunami);
-            case ETWS_WARNING_TYPE_TEST_MESSAGE:
-                return r.getString(R.string.etws_primary_default_message_test);
-            case ETWS_WARNING_TYPE_OTHER_EMERGENCY:
-                return r.getString(R.string.etws_primary_default_message_others);
-            default:
-                return "";
-        }
-    }
-
-    /**
-     * Create a new SmsCbMessage object from a header object plus one or more received PDUs.
-     *
-     * @param pdus PDU bytes
-     */
-    public static SmsCbMessage createSmsCbMessage(Context context, SmsCbHeader header,
-                                                  SmsCbLocation location, byte[][] pdus)
-            throws IllegalArgumentException {
-        if (header.isEtwsPrimaryNotification()) {
-            // ETSI TS 23.041 ETWS Primary Notification message
-            // ETWS primary message only contains 4 fields including serial number,
-            // message identifier, warning type, and warning security information.
-            // There is no field for the content/text so we get the text from the resources.
-            return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP, header.getGeographicalScope(),
-                    header.getSerialNumber(), location, header.getServiceCategory(), null,
-                    getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
-                    SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
-                    header.getCmasInfo());
-        } else {
-            String language = null;
-            StringBuilder sb = new StringBuilder();
-            for (byte[] pdu : pdus) {
-                Pair<String, String> p = parseBody(header, pdu);
-                language = p.first;
-                sb.append(p.second);
-            }
-            int priority = header.isEmergencyMessage() ? SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY
-                    : SmsCbMessage.MESSAGE_PRIORITY_NORMAL;
-
-            return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
-                    header.getGeographicalScope(), header.getSerialNumber(), location,
-                    header.getServiceCategory(), language, sb.toString(), priority,
-                    header.getEtwsInfo(), header.getCmasInfo());
-        }
-    }
-
-    /**
-     * Parse and unpack the body text according to the encoding in the DCS.
-     * After completing successfully this method will have assigned the body
-     * text into mBody, and optionally the language code into mLanguage
-     *
-     * @param header the message header to use
-     * @param pdu the PDU to decode
-     * @return a Pair of Strings containing the language and body of the message
-     */
-    private static Pair<String, String> parseBody(SmsCbHeader header, byte[] pdu) {
-        int encoding;
-        String language = null;
-        boolean hasLanguageIndicator = false;
-        int dataCodingScheme = header.getDataCodingScheme();
-
-        // Extract encoding and language from DCS, as defined in 3gpp TS 23.038,
-        // section 5.
-        switch ((dataCodingScheme & 0xf0) >> 4) {
-            case 0x00:
-                encoding = SmsConstants.ENCODING_7BIT;
-                language = LANGUAGE_CODES_GROUP_0[dataCodingScheme & 0x0f];
-                break;
-
-            case 0x01:
-                hasLanguageIndicator = true;
-                if ((dataCodingScheme & 0x0f) == 0x01) {
-                    encoding = SmsConstants.ENCODING_16BIT;
-                } else {
-                    encoding = SmsConstants.ENCODING_7BIT;
-                }
-                break;
-
-            case 0x02:
-                encoding = SmsConstants.ENCODING_7BIT;
-                language = LANGUAGE_CODES_GROUP_2[dataCodingScheme & 0x0f];
-                break;
-
-            case 0x03:
-                encoding = SmsConstants.ENCODING_7BIT;
-                break;
-
-            case 0x04:
-            case 0x05:
-                switch ((dataCodingScheme & 0x0c) >> 2) {
-                    case 0x01:
-                        encoding = SmsConstants.ENCODING_8BIT;
-                        break;
-
-                    case 0x02:
-                        encoding = SmsConstants.ENCODING_16BIT;
-                        break;
-
-                    case 0x00:
-                    default:
-                        encoding = SmsConstants.ENCODING_7BIT;
-                        break;
-                }
-                break;
-
-            case 0x06:
-            case 0x07:
-                // Compression not supported
-            case 0x09:
-                // UDH structure not supported
-            case 0x0e:
-                // Defined by the WAP forum not supported
-                throw new IllegalArgumentException("Unsupported GSM dataCodingScheme "
-                        + dataCodingScheme);
-
-            case 0x0f:
-                if (((dataCodingScheme & 0x04) >> 2) == 0x01) {
-                    encoding = SmsConstants.ENCODING_8BIT;
-                } else {
-                    encoding = SmsConstants.ENCODING_7BIT;
-                }
-                break;
-
-            default:
-                // Reserved values are to be treated as 7-bit
-                encoding = SmsConstants.ENCODING_7BIT;
-                break;
-        }
-
-        if (header.isUmtsFormat()) {
-            // Payload may contain multiple pages
-            int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
-
-            if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1)
-                    * nrPages) {
-                throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match "
-                        + nrPages + " pages");
-            }
-
-            StringBuilder sb = new StringBuilder();
-
-            for (int i = 0; i < nrPages; i++) {
-                // Each page is 82 bytes followed by a length octet indicating
-                // the number of useful octets within those 82
-                int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i;
-                int length = pdu[offset + PDU_BODY_PAGE_LENGTH];
-
-                if (length > PDU_BODY_PAGE_LENGTH) {
-                    throw new IllegalArgumentException("Page length " + length
-                            + " exceeds maximum value " + PDU_BODY_PAGE_LENGTH);
-                }
-
-                Pair<String, String> p = unpackBody(pdu, encoding, offset, length,
-                        hasLanguageIndicator, language);
-                language = p.first;
-                sb.append(p.second);
-            }
-            return new Pair<String, String>(language, sb.toString());
-        } else {
-            // Payload is one single page
-            int offset = SmsCbHeader.PDU_HEADER_LENGTH;
-            int length = pdu.length - offset;
-
-            return unpackBody(pdu, encoding, offset, length, hasLanguageIndicator, language);
-        }
-    }
-
-    /**
-     * Unpack body text from the pdu using the given encoding, position and
-     * length within the pdu
-     *
-     * @param pdu The pdu
-     * @param encoding The encoding, as derived from the DCS
-     * @param offset Position of the first byte to unpack
-     * @param length Number of bytes to unpack
-     * @param hasLanguageIndicator true if the body text is preceded by a
-     *            language indicator. If so, this method will as a side-effect
-     *            assign the extracted language code into mLanguage
-     * @param language the language to return if hasLanguageIndicator is false
-     * @return a Pair of Strings containing the language and body of the message
-     */
-    private static Pair<String, String> unpackBody(byte[] pdu, int encoding, int offset, int length,
-            boolean hasLanguageIndicator, String language) {
-        String body = null;
-
-        switch (encoding) {
-            case SmsConstants.ENCODING_7BIT:
-                body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7);
-
-                if (hasLanguageIndicator && body != null && body.length() > 2) {
-                    // Language is two GSM characters followed by a CR.
-                    // The actual body text is offset by 3 characters.
-                    language = body.substring(0, 2);
-                    body = body.substring(3);
-                }
-                break;
-
-            case SmsConstants.ENCODING_16BIT:
-                if (hasLanguageIndicator && pdu.length >= offset + 2) {
-                    // Language is two GSM characters.
-                    // The actual body text is offset by 2 bytes.
-                    language = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2);
-                    offset += 2;
-                    length -= 2;
-                }
-
-                try {
-                    body = new String(pdu, offset, (length & 0xfffe), "utf-16");
-                } catch (UnsupportedEncodingException e) {
-                    // Apparently it wasn't valid UTF-16.
-                    throw new IllegalArgumentException("Error decoding UTF-16 message", e);
-                }
-                break;
-
-            default:
-                break;
-        }
-
-        if (body != null) {
-            // Remove trailing carriage return
-            for (int i = body.length() - 1; i >= 0; i--) {
-                if (body.charAt(i) != CARRIAGE_RETURN) {
-                    body = body.substring(0, i + 1);
-                    break;
-                }
-            }
-        } else {
-            body = "";
-        }
-
-        return new Pair<String, String>(language, body);
-    }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java b/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java
deleted file mode 100644
index f4f4036..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2009 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.gsm;
-
-/**
- * SmsBroadcastConfigInfo defines one configuration of Cell Broadcast
- * Message (CBM) to be received by the ME
- *
- * fromServiceId - toServiceId defines a range of CBM message identifiers
- * whose value is 0x0000 - 0xFFFF as defined in TS 23.041 9.4.1.2.2 for GMS
- * and 9.4.4.2.2 for UMTS. All other values can be treated as empty
- * CBM message ID.
- *
- * fromCodeScheme - toCodeScheme defines a range of CBM data coding schemes
- * whose value is 0x00 - 0xFF as defined in TS 23.041 9.4.1.2.3 for GMS
- * and 9.4.4.2.3 for UMTS.
- * All other values can be treated as empty CBM data coding scheme.
- *
- * selected false means message types specified in {@code <fromServiceId, toServiceId>}
- * and {@code <fromCodeScheme, toCodeScheme>} are not accepted, while true means accepted.
- *
- */
-public final class SmsBroadcastConfigInfo {
-    private int mFromServiceId;
-    private int mToServiceId;
-    private int mFromCodeScheme;
-    private int mToCodeScheme;
-    private boolean mSelected;
-
-    /**
-     * Initialize the object from rssi and cid.
-     */
-    public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme,
-            int toScheme, boolean selected) {
-        mFromServiceId = fromId;
-        mToServiceId = toId;
-        mFromCodeScheme = fromScheme;
-        mToCodeScheme = toScheme;
-        mSelected = selected;
-    }
-
-    /**
-     * @param fromServiceId the fromServiceId to set
-     */
-    public void setFromServiceId(int fromServiceId) {
-        mFromServiceId = fromServiceId;
-    }
-
-    /**
-     * @return the fromServiceId
-     */
-    public int getFromServiceId() {
-        return mFromServiceId;
-    }
-
-    /**
-     * @param toServiceId the toServiceId to set
-     */
-    public void setToServiceId(int toServiceId) {
-        mToServiceId = toServiceId;
-    }
-
-    /**
-     * @return the toServiceId
-     */
-    public int getToServiceId() {
-        return mToServiceId;
-    }
-
-    /**
-     * @param fromCodeScheme the fromCodeScheme to set
-     */
-    public void setFromCodeScheme(int fromCodeScheme) {
-        mFromCodeScheme = fromCodeScheme;
-    }
-
-    /**
-     * @return the fromCodeScheme
-     */
-    public int getFromCodeScheme() {
-        return mFromCodeScheme;
-    }
-
-    /**
-     * @param toCodeScheme the toCodeScheme to set
-     */
-    public void setToCodeScheme(int toCodeScheme) {
-        mToCodeScheme = toCodeScheme;
-    }
-
-    /**
-     * @return the toCodeScheme
-     */
-    public int getToCodeScheme() {
-        return mToCodeScheme;
-    }
-
-    /**
-     * @param selected the selected to set
-     */
-    public void setSelected(boolean selected) {
-        mSelected = selected;
-    }
-
-    /**
-     * @return the selected
-     */
-    public boolean isSelected() {
-        return mSelected;
-    }
-
-    @Override
-    public String toString() {
-        return "SmsBroadcastConfigInfo: Id [" +
-                mFromServiceId + ',' + mToServiceId + "] Code [" +
-                mFromCodeScheme + ',' + mToCodeScheme + "] " +
-            (mSelected ? "ENABLED" : "DISABLED");
-    }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java
deleted file mode 100644
index bce5680..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ /dev/null
@@ -1,217 +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 com.android.internal.telephony.gsm;
-
-/**
- * Constants used in SMS Cell Broadcast messages (see 3GPP TS 23.041). This class is used by the
- * boot-time broadcast channel enable and database upgrade code in CellBroadcastReceiver, so it
- * is public, but should be avoided in favor of the radio technology independent constants in
- * {@link android.telephony.SmsCbMessage}, {@link android.telephony.SmsCbEtwsInfo}, and
- * {@link android.telephony.SmsCbCmasInfo} classes.
- *
- * {@hide}
- */
-public class SmsCbConstants {
-
-    /** Private constructor for utility class. */
-    private SmsCbConstants() { }
-
-    /** Channel 50 required by Brazil. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_50
-            = 0x0032;
-
-    /** Channel 911 required by Taiwan NCC. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_911
-            = 0x038F; // 911
-
-    /** Channel 919 required by Taiwan NCC and Israel. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919
-            = 0x0397; // 919
-
-    /** Channel 928 required by Israel. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_928
-            = 0x03A0; // 928
-
-    /** Start of PWS Message Identifier range (includes ETWS and CMAS). */
-    public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER
-            = 0x1100; // 4352
-
-    /** Bitmask for messages of ETWS type (including future extensions). */
-    public static final int MESSAGE_ID_ETWS_TYPE_MASK
-            = 0xFFF8;
-
-    /** Value for messages of ETWS type after applying {@link #MESSAGE_ID_ETWS_TYPE_MASK}. */
-    public static final int MESSAGE_ID_ETWS_TYPE
-            = 0x1100; // 4352
-
-    /** ETWS Message Identifier for earthquake warning message. */
-    public static final int MESSAGE_ID_ETWS_EARTHQUAKE_WARNING
-            = 0x1100; // 4352
-
-    /** ETWS Message Identifier for tsunami warning message. */
-    public static final int MESSAGE_ID_ETWS_TSUNAMI_WARNING
-            = 0x1101; // 4353
-
-    /** ETWS Message Identifier for earthquake and tsunami combined warning message. */
-    public static final int MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING
-            = 0x1102; // 4354
-
-    /** ETWS Message Identifier for test message. */
-    public static final int MESSAGE_ID_ETWS_TEST_MESSAGE
-            = 0x1103; // 4355
-
-    /** ETWS Message Identifier for messages related to other emergency types. */
-    public static final int MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE
-            = 0x1104; // 4356
-
-    /** Start of CMAS Message Identifier range. */
-    public static final int MESSAGE_ID_CMAS_FIRST_IDENTIFIER
-            = 0x1112; // 4370
-
-    /** CMAS Message Identifier for Presidential Level alerts. */
-    public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL
-            = 0x1112; // 4370
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED
-            = 0x1113; // 4371
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY
-            = 0x1114; // 4372
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED
-            = 0x1115; // 4373
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY
-            = 0x1116; // 4374
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED
-            = 0x1117; // 4375
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY
-            = 0x1118; // 4376
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED
-            = 0x1119; // 4377
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY
-            = 0x111A; // 4378
-
-    /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert). */
-    public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY
-            = 0x111B; // 4379
-
-    /** CMAS Message Identifier for the Required Monthly Test. */
-    public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST
-            = 0x111C; // 4380
-
-    /** CMAS Message Identifier for CMAS Exercise. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE
-            = 0x111D; // 4381
-
-    /** CMAS Message Identifier for operator defined use. */
-    public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE
-            = 0x111E; // 4382
-
-    /** CMAS Message Identifier for Presidential Level alerts for additional languages
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE
-            = 0x111F; // 4383
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE
-            = 0x1120; // 4384
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE
-            = 0x1121; // 4385
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE
-            = 0x1122; // 4386
-
-    /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE
-            = 0x1123; // 4387
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE
-            = 0x1124; // 4388
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
-     *  for additional languages.*/
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE
-            = 0x1125; // 4389
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE
-            = 0x1126; // 4390
-
-    /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
-     *  for additional languages.*/
-    public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE
-            = 0x1127; // 4391
-
-    /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE
-            = 0x1128; // 4392
-
-    /** CMAS Message Identifier for the Required Monthly Test
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE
-            = 0x1129; // 4393
-
-    /** CMAS Message Identifier for CMAS Exercise
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE
-            = 0x112A; // 4394
-
-    /** CMAS Message Identifier for operator defined use
-     *  for additional languages. */
-    public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE
-            = 0x112B; // 4395
-
-    /** End of CMAS Message Identifier range (including future extensions). */
-    public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER
-            = 0x112F; // 4399
-
-    /** End of PWS Message Identifier range (includes ETWS, CMAS, and future extensions). */
-    public static final int MESSAGE_ID_PWS_LAST_IDENTIFIER
-            = 0x18FF; // 6399
-
-    /** ETWS serial number flag to activate the popup display. */
-    public static final int SERIAL_NUMBER_ETWS_ACTIVATE_POPUP
-            = 0x1000; // 4096
-
-    /** ETWS serial number flag to activate the emergency user alert. */
-    public static final int SERIAL_NUMBER_ETWS_EMERGENCY_USER_ALERT
-            = 0x2000; // 8192
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java
deleted file mode 100644
index d267ad2..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ /dev/null
@@ -1,450 +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 com.android.internal.telephony.gsm;
-
-import android.telephony.SmsCbCmasInfo;
-import android.telephony.SmsCbEtwsInfo;
-
-import java.util.Arrays;
-
-/**
- * Parses a 3GPP TS 23.041 cell broadcast message header. This class is public for use by
- * CellBroadcastReceiver test cases, but should not be used by applications.
- *
- * All relevant header information is now sent as a Parcelable
- * {@link android.telephony.SmsCbMessage} object in the "message" extra of the
- * {@link android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION} or
- * {@link android.provider.Telephony.Sms.Intents#SMS_EMERGENCY_CB_RECEIVED_ACTION} intent.
- * The raw PDU is no longer sent to SMS CB applications.
- */
-public class SmsCbHeader {
-
-    /**
-     * Length of SMS-CB header
-     */
-    static final int PDU_HEADER_LENGTH = 6;
-
-    /**
-     * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
-     */
-    static final int FORMAT_GSM = 1;
-
-    /**
-     * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
-     */
-    static final int FORMAT_UMTS = 2;
-
-    /**
-     * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3
-     */
-    static final int FORMAT_ETWS_PRIMARY = 3;
-
-    /**
-     * Message type value as defined in 3gpp TS 25.324, section 11.1.
-     */
-    private static final int MESSAGE_TYPE_CBS_MESSAGE = 1;
-
-    /**
-     * Length of GSM pdus
-     */
-    private static final int PDU_LENGTH_GSM = 88;
-
-    /**
-     * Maximum length of ETWS primary message GSM pdus
-     */
-    private static final int PDU_LENGTH_ETWS = 56;
-
-    private final int mGeographicalScope;
-
-    /** The serial number combines geographical scope, message code, and update number. */
-    private final int mSerialNumber;
-
-    /** The Message Identifier in 3GPP is the same as the Service Category in CDMA. */
-    private final int mMessageIdentifier;
-
-    private final int mDataCodingScheme;
-
-    private final int mPageIndex;
-
-    private final int mNrOfPages;
-
-    private final int mFormat;
-
-    /** ETWS warning notification info. */
-    private final SmsCbEtwsInfo mEtwsInfo;
-
-    /** CMAS warning notification info. */
-    private final SmsCbCmasInfo mCmasInfo;
-
-    public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
-        if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
-            throw new IllegalArgumentException("Illegal PDU");
-        }
-
-        if (pdu.length <= PDU_LENGTH_GSM) {
-            // can be ETWS or GSM format.
-            // Per TS23.041 9.4.1.2 and 9.4.1.3.2, GSM and ETWS format both
-            // contain serial number which contains GS, Message Code, and Update Number
-            // per 9.4.1.2.1, and message identifier in same octets
-            mGeographicalScope = (pdu[0] & 0xc0) >>> 6;
-            mSerialNumber = ((pdu[0] & 0xff) << 8) | (pdu[1] & 0xff);
-            mMessageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff);
-            if (isEtwsMessage() && pdu.length <= PDU_LENGTH_ETWS) {
-                mFormat = FORMAT_ETWS_PRIMARY;
-                mDataCodingScheme = -1;
-                mPageIndex = -1;
-                mNrOfPages = -1;
-                boolean emergencyUserAlert = (pdu[4] & 0x1) != 0;
-                boolean activatePopup = (pdu[5] & 0x80) != 0;
-                int warningType = (pdu[4] & 0xfe) >>> 1;
-                byte[] warningSecurityInfo;
-                // copy the Warning-Security-Information, if present
-                if (pdu.length > PDU_HEADER_LENGTH) {
-                    warningSecurityInfo = Arrays.copyOfRange(pdu, 6, pdu.length);
-                } else {
-                    warningSecurityInfo = null;
-                }
-                mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
-                        true, warningSecurityInfo);
-                mCmasInfo = null;
-                return;     // skip the ETWS/CMAS initialization code for regular notifications
-            } else {
-                // GSM pdus are no more than 88 bytes
-                mFormat = FORMAT_GSM;
-                mDataCodingScheme = pdu[4] & 0xff;
-
-                // Check for invalid page parameter
-                int pageIndex = (pdu[5] & 0xf0) >>> 4;
-                int nrOfPages = pdu[5] & 0x0f;
-
-                if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
-                    pageIndex = 1;
-                    nrOfPages = 1;
-                }
-
-                mPageIndex = pageIndex;
-                mNrOfPages = nrOfPages;
-            }
-        } else {
-            // UMTS pdus are always at least 90 bytes since the payload includes
-            // a number-of-pages octet and also one length octet per page
-            mFormat = FORMAT_UMTS;
-
-            int messageType = pdu[0];
-
-            if (messageType != MESSAGE_TYPE_CBS_MESSAGE) {
-                throw new IllegalArgumentException("Unsupported message type " + messageType);
-            }
-
-            mMessageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff;
-            mGeographicalScope = (pdu[3] & 0xc0) >>> 6;
-            mSerialNumber = ((pdu[3] & 0xff) << 8) | (pdu[4] & 0xff);
-            mDataCodingScheme = pdu[5] & 0xff;
-
-            // We will always consider a UMTS message as having one single page
-            // since there's only one instance of the header, even though the
-            // actual payload may contain several pages.
-            mPageIndex = 1;
-            mNrOfPages = 1;
-        }
-
-        if (isEtwsMessage()) {
-            boolean emergencyUserAlert = isEtwsEmergencyUserAlert();
-            boolean activatePopup = isEtwsPopupAlert();
-            int warningType = getEtwsWarningType();
-            mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
-                    false, null);
-            mCmasInfo = null;
-        } else if (isCmasMessage()) {
-            int messageClass = getCmasMessageClass();
-            int severity = getCmasSeverity();
-            int urgency = getCmasUrgency();
-            int certainty = getCmasCertainty();
-            mEtwsInfo = null;
-            mCmasInfo = new SmsCbCmasInfo(messageClass, SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN,
-                    SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, severity, urgency, certainty);
-        } else {
-            mEtwsInfo = null;
-            mCmasInfo = null;
-        }
-    }
-
-    int getGeographicalScope() {
-        return mGeographicalScope;
-    }
-
-    int getSerialNumber() {
-        return mSerialNumber;
-    }
-
-    int getServiceCategory() {
-        return mMessageIdentifier;
-    }
-
-    int getDataCodingScheme() {
-        return mDataCodingScheme;
-    }
-
-    int getPageIndex() {
-        return mPageIndex;
-    }
-
-    int getNumberOfPages() {
-        return mNrOfPages;
-    }
-
-    SmsCbEtwsInfo getEtwsInfo() {
-        return mEtwsInfo;
-    }
-
-    SmsCbCmasInfo getCmasInfo() {
-        return mCmasInfo;
-    }
-
-    /**
-     * Return whether this broadcast is an emergency (PWS) message type.
-     * @return true if this message is emergency type; false otherwise
-     */
-    boolean isEmergencyMessage() {
-        return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER
-                && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER;
-    }
-
-    /**
-     * Return whether this broadcast is an ETWS emergency message type.
-     * @return true if this message is ETWS emergency type; false otherwise
-     */
-    private boolean isEtwsMessage() {
-        return (mMessageIdentifier & SmsCbConstants.MESSAGE_ID_ETWS_TYPE_MASK)
-                == SmsCbConstants.MESSAGE_ID_ETWS_TYPE;
-    }
-
-    /**
-     * Return whether this broadcast is an ETWS primary notification.
-     * @return true if this message is an ETWS primary notification; false otherwise
-     */
-    boolean isEtwsPrimaryNotification() {
-        return mFormat == FORMAT_ETWS_PRIMARY;
-    }
-
-    /**
-     * Return whether this broadcast is in UMTS format.
-     * @return true if this message is in UMTS format; false otherwise
-     */
-    boolean isUmtsFormat() {
-        return mFormat == FORMAT_UMTS;
-    }
-
-    /**
-     * Return whether this message is a CMAS emergency message type.
-     * @return true if this message is CMAS emergency type; false otherwise
-     */
-    private boolean isCmasMessage() {
-        return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_CMAS_FIRST_IDENTIFIER
-                && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_CMAS_LAST_IDENTIFIER;
-    }
-
-    /**
-     * Return whether the popup alert flag is set for an ETWS warning notification.
-     * This method assumes that the message ID has already been checked for ETWS type.
-     *
-     * @return true if the message code indicates a popup alert should be displayed
-     */
-    private boolean isEtwsPopupAlert() {
-        return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_ACTIVATE_POPUP) != 0;
-    }
-
-    /**
-     * Return whether the emergency user alert flag is set for an ETWS warning notification.
-     * This method assumes that the message ID has already been checked for ETWS type.
-     *
-     * @return true if the message code indicates an emergency user alert
-     */
-    private boolean isEtwsEmergencyUserAlert() {
-        return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_EMERGENCY_USER_ALERT) != 0;
-    }
-
-    /**
-     * Returns the warning type for an ETWS warning notification.
-     * This method assumes that the message ID has already been checked for ETWS type.
-     *
-     * @return the ETWS warning type defined in 3GPP TS 23.041 section 9.3.24
-     */
-    private int getEtwsWarningType() {
-        return mMessageIdentifier - SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING;
-    }
-
-    /**
-     * Returns the message class for a CMAS warning notification.
-     * This method assumes that the message ID has already been checked for CMAS type.
-     * @return the CMAS message class as defined in {@link SmsCbCmasInfo}
-     */
-    private int getCmasMessageClass() {
-        switch (mMessageIdentifier) {
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_CMAS_EXERCISE;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CLASS_OPERATOR_DEFINED_USE;
-
-            default:
-                return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
-        }
-    }
-
-    /**
-     * Returns the severity for a CMAS warning notification. This is only available for extreme
-     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
-     * This method assumes that the message ID has already been checked for CMAS type.
-     * @return the CMAS severity as defined in {@link SmsCbCmasInfo}
-     */
-    private int getCmasSeverity() {
-        switch (mMessageIdentifier) {
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_SEVERITY_EXTREME;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_SEVERITY_SEVERE;
-
-            default:
-                return SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
-        }
-    }
-
-    /**
-     * Returns the urgency for a CMAS warning notification. This is only available for extreme
-     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
-     * This method assumes that the message ID has already been checked for CMAS type.
-     * @return the CMAS urgency as defined in {@link SmsCbCmasInfo}
-     */
-    private int getCmasUrgency() {
-        switch (mMessageIdentifier) {
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_URGENCY_EXPECTED;
-
-            default:
-                return SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
-        }
-    }
-
-    /**
-     * Returns the certainty for a CMAS warning notification. This is only available for extreme
-     * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
-     * This method assumes that the message ID has already been checked for CMAS type.
-     * @return the CMAS certainty as defined in {@link SmsCbCmasInfo}
-     */
-    private int getCmasCertainty() {
-        switch (mMessageIdentifier) {
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED;
-
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
-            case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
-                return SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY;
-
-            default:
-                return SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "SmsCbHeader{GS=" + mGeographicalScope + ", serialNumber=0x" +
-                Integer.toHexString(mSerialNumber) +
-                ", messageIdentifier=0x" + Integer.toHexString(mMessageIdentifier) +
-                ", DCS=0x" + Integer.toHexString(mDataCodingScheme) +
-                ", page " + mPageIndex + " of " + mNrOfPages + '}';
-    }
-}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/gsm/SmsMessage.java b/src/java/com/android/internal/telephony/gsm/SmsMessage.java
deleted file mode 100644
index 582506a..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ /dev/null
@@ -1,1369 +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 com.android.internal.telephony.gsm;
-
-import android.telephony.PhoneNumberUtils;
-import android.text.format.Time;
-import android.telephony.Rlog;
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.ParseException;
-
-import static com.android.internal.telephony.SmsConstants.MessageClass;
-import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN;
-import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
-
-/**
- * A Short Message Service message.
- *
- */
-public class SmsMessage extends SmsMessageBase {
-    static final String LOG_TAG = "SmsMessage";
-    private static final boolean VDBG = false;
-
-    private MessageClass messageClass;
-
-    /**
-     * TP-Message-Type-Indicator
-     * 9.2.3
-     */
-    private int mMti;
-
-    /** TP-Protocol-Identifier (TP-PID) */
-    private int mProtocolIdentifier;
-
-    // TP-Data-Coding-Scheme
-    // see TS 23.038
-    private int mDataCodingScheme;
-
-    // TP-Reply-Path
-    // e.g. 23.040 9.2.2.1
-    private boolean mReplyPathPresent = false;
-
-    /** The address of the receiver. */
-    private GsmSmsAddress mRecipientAddress;
-
-    /**
-     *  TP-Status - status of a previously submitted SMS.
-     *  This field applies to SMS-STATUS-REPORT messages.  0 indicates success;
-     *  see TS 23.040, 9.2.3.15 for description of other possible values.
-     */
-    private int mStatus;
-
-    /**
-     *  TP-Status - status of a previously submitted SMS.
-     *  This field is true iff the message is a SMS-STATUS-REPORT message.
-     */
-    private boolean mIsStatusReportMessage = false;
-
-    private int mVoiceMailCount = 0;
-
-    public static class SubmitPdu extends SubmitPduBase {
-    }
-
-    /**
-     * Create an SmsMessage from a raw PDU.
-     */
-    public static SmsMessage createFromPdu(byte[] pdu) {
-        try {
-            SmsMessage msg = new SmsMessage();
-            msg.parsePdu(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
-            return null;
-        } catch (OutOfMemoryError e) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e);
-            return null;
-        }
-    }
-
-    /**
-     * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated
-     * by TP_PID field set to value 0x40
-     */
-    public boolean isTypeZero() {
-        return (mProtocolIdentifier == 0x40);
-    }
-
-    /**
-     * 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
-     *
-     * {@hide}
-     */
-    public static SmsMessage newFromCMT(byte[] pdu) {
-        try {
-            SmsMessage msg = new SmsMessage();
-            msg.parsePdu(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
-            return null;
-        }
-    }
-
-    /** @hide */
-    public static SmsMessage newFromCDS(byte[] pdu) {
-        try {
-            SmsMessage msg = new SmsMessage();
-            msg.parsePdu(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex);
-            return null;
-        }
-    }
-
-    /**
-     * 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) {
-        try {
-            SmsMessage msg = new SmsMessage();
-
-            msg.mIndexOnIcc = index;
-
-            // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
-            // or STORED_UNSENT
-            // See TS 51.011 10.5.3
-            if ((data[0] & 1) == 0) {
-                Rlog.w(LOG_TAG,
-                        "SMS parsing failed: Trying to parse a free record");
-                return null;
-            } else {
-                msg.mStatusOnIcc = data[0] & 0x07;
-            }
-
-            int size = data.length - 1;
-
-            // Note: Data may include trailing FF's.  That's OK; message
-            // should still parse correctly.
-            byte[] pdu = new byte[size];
-            System.arraycopy(data, 1, pdu, 0, size);
-            msg.parsePdu(pdu);
-            return msg;
-        } catch (RuntimeException ex) {
-            Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
-            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
-     */
-    public static int getTPLayerLengthForPDU(String pdu) {
-        int len = pdu.length() / 2;
-        int smscLen = Integer.parseInt(pdu.substring(0, 2), 16);
-
-        return len - smscLen - 1;
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message
-     *
-     * @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.
-     * @hide
-     */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destinationAddress, String message,
-            boolean statusReportRequested, byte[] header) {
-        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
-                ENCODING_UNKNOWN, 0, 0);
-    }
-
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message using the
-     * specified encoding.
-     *
-     * @param scAddress Service Centre address.  Null means use default.
-     * @param encoding Encoding defined by constants in
-     *        com.android.internal.telephony.SmsConstants.ENCODING_*
-     * @param languageTable
-     * @param languageShiftTable
-     * @return a <code>SubmitPdu</code> containing the encoded SC
-     *         address, if applicable, and the encoded message.
-     *         Returns null on encode error.
-     * @hide
-     */
-    public static SubmitPdu getSubmitPdu(String scAddress,
-            String destinationAddress, String message,
-            boolean statusReportRequested, byte[] header, int encoding,
-            int languageTable, int languageShiftTable) {
-
-        // Perform null parameter checks.
-        if (message == null || destinationAddress == null) {
-            return null;
-        }
-
-        if (encoding == ENCODING_UNKNOWN) {
-            // Find the best encoding to use
-            TextEncodingDetails ted = calculateLength(message, false);
-            encoding = ted.codeUnitSize;
-            languageTable = ted.languageTable;
-            languageShiftTable = ted.languageShiftTable;
-
-            if (encoding == ENCODING_7BIT &&
-                    (languageTable != 0 || languageShiftTable != 0)) {
-                if (header != null) {
-                    SmsHeader smsHeader = SmsHeader.fromByteArray(header);
-                    if (smsHeader.languageTable != languageTable
-                            || smsHeader.languageShiftTable != languageShiftTable) {
-                        Rlog.w(LOG_TAG, "Updating language table in SMS header: "
-                                + smsHeader.languageTable + " -> " + languageTable + ", "
-                                + smsHeader.languageShiftTable + " -> " + languageShiftTable);
-                        smsHeader.languageTable = languageTable;
-                        smsHeader.languageShiftTable = languageShiftTable;
-                        header = SmsHeader.toByteArray(smsHeader);
-                    }
-                } else {
-                    SmsHeader smsHeader = new SmsHeader();
-                    smsHeader.languageTable = languageTable;
-                    smsHeader.languageShiftTable = languageShiftTable;
-                    header = SmsHeader.toByteArray(smsHeader);
-                }
-            }
-        }
-
-        SubmitPdu ret = new SubmitPdu();
-        // MTI = SMS-SUBMIT, UDHI = header != null
-        byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
-        ByteArrayOutputStream bo = getSubmitPduHead(
-                scAddress, destinationAddress, mtiByte,
-                statusReportRequested, ret);
-
-        // User Data (and length)
-        byte[] userData;
-        try {
-            if (encoding == ENCODING_7BIT) {
-                userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
-                        languageTable, languageShiftTable);
-            } else { //assume UCS-2
-                try {
-                    userData = encodeUCS2(message, header);
-                } catch(UnsupportedEncodingException uex) {
-                    Rlog.e(LOG_TAG,
-                            "Implausible UnsupportedEncodingException ",
-                            uex);
-                    return null;
-                }
-            }
-        } catch (EncodeException ex) {
-            // Encoding to the 7-bit alphabet failed. Let's see if we can
-            // send it as a UCS-2 encoded message
-            try {
-                userData = encodeUCS2(message, header);
-                encoding = ENCODING_16BIT;
-            } catch(UnsupportedEncodingException uex) {
-                Rlog.e(LOG_TAG,
-                        "Implausible UnsupportedEncodingException ",
-                        uex);
-                return null;
-            }
-        }
-
-        if (encoding == ENCODING_7BIT) {
-            if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
-                // Message too long
-                Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
-                return null;
-            }
-            // TP-Data-Coding-Scheme
-            // Default encoding, uncompressed
-            // To test writing messages to the SIM card, change this value 0x00
-            // to 0x12, which means "bits 1 and 0 contain message class, and the
-            // class is 2". Note that this takes effect for the sender. In other
-            // words, messages sent by the phone with this change will end up on
-            // the receiver's SIM card. You can then send messages to yourself
-            // (on a phone with this change) and they'll end up on the SIM card.
-            bo.write(0x00);
-        } else { // assume UCS-2
-            if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
-                // Message too long
-                Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
-                return null;
-            }
-            // TP-Data-Coding-Scheme
-            // UCS-2 encoding, uncompressed
-            bo.write(0x08);
-        }
-
-        // (no TP-Validity-Period)
-        bo.write(userData, 0, userData.length);
-        ret.encodedMessage = bo.toByteArray();
-        return ret;
-    }
-
-    /**
-     * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary
-     *
-     * @return encoded message as UCS2
-     * @throws UnsupportedEncodingException
-     */
-    private static byte[] encodeUCS2(String message, byte[] header)
-        throws UnsupportedEncodingException {
-        byte[] userData, textPart;
-        textPart = message.getBytes("utf-16be");
-
-        if (header != null) {
-            // Need 1 byte for UDHL
-            userData = new byte[header.length + textPart.length + 1];
-
-            userData[0] = (byte)header.length;
-            System.arraycopy(header, 0, userData, 1, header.length);
-            System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
-        }
-        else {
-            userData = textPart;
-        }
-        byte[] ret = new byte[userData.length+1];
-        ret[0] = (byte) (userData.length & 0xff );
-        System.arraycopy(userData, 0, ret, 1, userData.length);
-        return ret;
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a destination address and a message
-     *
-     * @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) {
-
-        return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
-    }
-
-    /**
-     * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
-     *
-     * @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, int destinationPort, byte[] data,
-            boolean statusReportRequested) {
-
-        SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
-        portAddrs.destPort = destinationPort;
-        portAddrs.origPort = 0;
-        portAddrs.areEightBits = false;
-
-        SmsHeader smsHeader = new SmsHeader();
-        smsHeader.portAddrs = portAddrs;
-
-        byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader);
-
-        if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) {
-            Rlog.e(LOG_TAG, "SMS data message may only contain "
-                    + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes");
-            return null;
-        }
-
-        SubmitPdu ret = new SubmitPdu();
-        ByteArrayOutputStream bo = getSubmitPduHead(
-                scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT,
-                                                            // TP-UDHI = true
-                statusReportRequested, ret);
-
-        // TP-Data-Coding-Scheme
-        // No class, 8 bit data
-        bo.write(0x04);
-
-        // (no TP-Validity-Period)
-
-        // Total size
-        bo.write(data.length + smsHeaderData.length + 1);
-
-        // User data header
-        bo.write(smsHeaderData.length);
-        bo.write(smsHeaderData, 0, smsHeaderData.length);
-
-        // User data
-        bo.write(data, 0, data.length);
-
-        ret.encodedMessage = bo.toByteArray();
-        return ret;
-    }
-
-    /**
-     * Create the beginning of a SUBMIT PDU.  This is the part of the
-     * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu},
-     * one of which takes a byte array and the other of which takes a
-     * <code>String</code>.
-     *
-     * @param scAddress Service Centre address. null == use default
-     * @param destinationAddress the address of the destination for the message
-     * @param mtiByte
-     * @param ret <code>SubmitPdu</code> containing the encoded SC
-     *        address, if applicable, and the encoded message
-     */
-    private static ByteArrayOutputStream getSubmitPduHead(
-            String scAddress, String destinationAddress, byte mtiByte,
-            boolean statusReportRequested, SubmitPdu ret) {
-        ByteArrayOutputStream bo = new ByteArrayOutputStream(
-                MAX_USER_DATA_BYTES + 40);
-
-        // SMSC address with length octet, or 0
-        if (scAddress == null) {
-            ret.encodedScAddress = null;
-        } else {
-            ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
-                    scAddress);
-        }
-
-        // TP-Message-Type-Indicator (and friends)
-        if (statusReportRequested) {
-            // Set TP-Status-Report-Request bit.
-            mtiByte |= 0x20;
-            if (VDBG) Rlog.d(LOG_TAG, "SMS status report requested");
-        }
-        bo.write(mtiByte);
-
-        // space for TP-Message-Reference
-        bo.write(0);
-
-        byte[] daBytes;
-
-        daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress);
-
-        // destination address length in BCD digits, ignoring TON byte and pad
-        // TODO Should be better.
-        bo.write((daBytes.length - 1) * 2
-                - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
-
-        // destination address
-        bo.write(daBytes, 0, daBytes.length);
-
-        // TP-Protocol-Identifier
-        bo.write(0);
-        return bo;
-    }
-
-    private static class PduParser {
-        byte mPdu[];
-        int mCur;
-        SmsHeader mUserDataHeader;
-        byte[] mUserData;
-        int mUserDataSeptetPadding;
-
-        PduParser(byte[] pdu) {
-            mPdu = pdu;
-            mCur = 0;
-            mUserDataSeptetPadding = 0;
-        }
-
-        /**
-         * Parse and return the SC address prepended to SMS messages coming via
-         * the TS 27.005 / AT interface.  Returns null on invalid address
-         */
-        String getSCAddress() {
-            int len;
-            String ret;
-
-            // length of SC Address
-            len = getByte();
-
-            if (len == 0) {
-                // no SC address
-                ret = null;
-            } else {
-                // SC address
-                try {
-                    ret = PhoneNumberUtils
-                            .calledPartyBCDToString(mPdu, mCur, len);
-                } catch (RuntimeException tr) {
-                    Rlog.d(LOG_TAG, "invalid SC address: ", tr);
-                    ret = null;
-                }
-            }
-
-            mCur += len;
-
-            return ret;
-        }
-
-        /**
-         * returns non-sign-extended byte value
-         */
-        int getByte() {
-            return mPdu[mCur++] & 0xff;
-        }
-
-        /**
-         * Any address except the SC address (eg, originating address) See TS
-         * 23.040 9.1.2.5
-         */
-        GsmSmsAddress getAddress() {
-            GsmSmsAddress ret;
-
-            // "The Address-Length field is an integer representation of
-            // the number field, i.e. excludes any semi-octet containing only
-            // fill bits."
-            // The TOA field is not included as part of this
-            int addressLength = mPdu[mCur] & 0xff;
-            int lengthBytes = 2 + (addressLength + 1) / 2;
-
-            try {
-                ret = new GsmSmsAddress(mPdu, mCur, lengthBytes);
-            } catch (ParseException e) {
-                ret = null;
-                //This is caught by createFromPdu(byte[] pdu)
-                throw new RuntimeException(e.getMessage());
-            }
-
-            mCur += lengthBytes;
-
-            return ret;
-        }
-
-        /**
-         * Parses an SC timestamp and returns a currentTimeMillis()-style
-         * timestamp
-         */
-
-        long getSCTimestampMillis() {
-            // TP-Service-Centre-Time-Stamp
-            int year = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-            int month = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-            int day = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-            int hour = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-            int minute = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-            int second = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-
-            // 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 = mPdu[mCur++];
-
-            // Mask out sign bit.
-            int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
-
-            timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
-
-            Time time = new Time(Time.TIMEZONE_UTC);
-
-            // It's 2006.  Should I really support years < 2000?
-            time.year = year >= 90 ? year + 1900 : 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);
-        }
-
-        /**
-         * Pulls the user data out of the PDU, and separates the payload from
-         * the header if there is one.
-         *
-         * @param hasUserDataHeader true if there is a user data header
-         * @param dataInSeptets true if the data payload is in septets instead
-         *  of octets
-         * @return the number of septets or octets in the user data payload
-         */
-        int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) {
-            int offset = mCur;
-            int userDataLength = mPdu[offset++] & 0xff;
-            int headerSeptets = 0;
-            int userDataHeaderLength = 0;
-
-            if (hasUserDataHeader) {
-                userDataHeaderLength = mPdu[offset++] & 0xff;
-
-                byte[] udh = new byte[userDataHeaderLength];
-                System.arraycopy(mPdu, offset, udh, 0, userDataHeaderLength);
-                mUserDataHeader = SmsHeader.fromByteArray(udh);
-                offset += userDataHeaderLength;
-
-                int headerBits = (userDataHeaderLength + 1) * 8;
-                headerSeptets = headerBits / 7;
-                headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
-                mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
-            }
-
-            int bufferLen;
-            if (dataInSeptets) {
-                /*
-                 * Here we just create the user data length to be the remainder of
-                 * the pdu minus the user data header, since userDataLength means
-                 * the number of uncompressed septets.
-                 */
-                bufferLen = mPdu.length - offset;
-            } else {
-                /*
-                 * userDataLength is the count of octets, so just subtract the
-                 * user data header.
-                 */
-                bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0);
-                if (bufferLen < 0) {
-                    bufferLen = 0;
-                }
-            }
-
-            mUserData = new byte[bufferLen];
-            System.arraycopy(mPdu, offset, mUserData, 0, mUserData.length);
-            mCur = offset;
-
-            if (dataInSeptets) {
-                // Return the number of septets
-                int count = userDataLength - headerSeptets;
-                // If count < 0, return 0 (means UDL was probably incorrect)
-                return count < 0 ? 0 : count;
-            } else {
-                // Return the number of octets
-                return mUserData.length;
-            }
-        }
-
-        /**
-         * Returns the user data payload, not including the headers
-         *
-         * @return the user data payload, not including the headers
-         */
-        byte[] getUserData() {
-            return mUserData;
-        }
-
-        /**
-         * Returns an object representing the user data headers
-         *
-         * {@hide}
-         */
-        SmsHeader getUserDataHeader() {
-            return mUserDataHeader;
-        }
-
-        /**
-         * Interprets the user data payload as packed GSM 7bit characters, and
-         * decodes them into a String.
-         *
-         * @param septetCount the number of septets in the user data payload
-         * @return a String with the decoded characters
-         */
-        String getUserDataGSM7Bit(int septetCount, int languageTable,
-                int languageShiftTable) {
-            String ret;
-
-            ret = GsmAlphabet.gsm7BitPackedToString(mPdu, mCur, septetCount,
-                    mUserDataSeptetPadding, languageTable, languageShiftTable);
-
-            mCur += (septetCount * 7) / 8;
-
-            return ret;
-        }
-
-        /**
-         * Interprets the user data payload as pack GSM 8-bit (a GSM alphabet string that's
-         * stored in 8-bit unpacked format) characters, and decodes them into a String.
-         *
-         * @param byteCount the number of byest in the user data payload
-         * @return a String with the decoded characters
-         */
-        String getUserDataGSM8bit(int byteCount) {
-            String ret;
-
-            ret = GsmAlphabet.gsm8BitUnpackedToString(mPdu, mCur, byteCount);
-
-            mCur += byteCount;
-
-            return ret;
-        }
-
-        /**
-         * Interprets the user data payload as UCS2 characters, and
-         * decodes them into a String.
-         *
-         * @param byteCount the number of bytes in the user data payload
-         * @return a String with the decoded characters
-         */
-        String getUserDataUCS2(int byteCount) {
-            String ret;
-
-            try {
-                ret = new String(mPdu, mCur, byteCount, "utf-16");
-            } catch (UnsupportedEncodingException ex) {
-                ret = "";
-                Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
-            }
-
-            mCur += byteCount;
-            return ret;
-        }
-
-        /**
-         * Interprets the user data payload as KSC-5601 characters, and
-         * decodes them into a String.
-         *
-         * @param byteCount the number of bytes in the user data payload
-         * @return a String with the decoded characters
-         */
-        String getUserDataKSC5601(int byteCount) {
-            String ret;
-
-            try {
-                ret = new String(mPdu, mCur, byteCount, "KSC5601");
-            } catch (UnsupportedEncodingException ex) {
-                ret = "";
-                Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
-            }
-
-            mCur += byteCount;
-            return ret;
-        }
-
-        boolean moreDataPresent() {
-            return (mPdu.length > mCur);
-        }
-    }
-
-    /**
-     * 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 ignore (but still count) illegal characters if true
-     * @return TextEncodingDetails
-     */
-    public static TextEncodingDetails calculateLength(CharSequence msgBody,
-            boolean use7bitOnly) {
-        CharSequence newMsgBody = null;
-        Resources r = Resources.getSystem();
-        if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
-            newMsgBody  = Sms7BitEncodingTranslator.translate(msgBody);
-        }
-        if (TextUtils.isEmpty(newMsgBody)) {
-            newMsgBody = msgBody;
-        }
-        TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(newMsgBody, use7bitOnly);
-        if (ted == null) {
-            return SmsMessageBase.calcUnicodeEncodingDetails(newMsgBody);
-        }
-        return ted;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getProtocolIdentifier() {
-        return mProtocolIdentifier;
-    }
-
-    /**
-     * Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages.
-     * @return the TP-DCS field of the SMS header
-     */
-    int getDataCodingScheme() {
-        return mDataCodingScheme;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isReplace() {
-        return (mProtocolIdentifier & 0xc0) == 0x40
-                && (mProtocolIdentifier & 0x3f) > 0
-                && (mProtocolIdentifier & 0x3f) < 8;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isCphsMwiMessage() {
-        return ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear()
-                || ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isMWIClearMessage() {
-        if (mIsMwi && !mMwiSense) {
-            return true;
-        }
-
-        return mOriginatingAddress != null
-                && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isMWISetMessage() {
-        if (mIsMwi && mMwiSense) {
-            return true;
-        }
-
-        return mOriginatingAddress != null
-                && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isMwiDontStore() {
-        if (mIsMwi && mMwiDontStore) {
-            return true;
-        }
-
-        if (isCphsMwiMessage()) {
-            // See CPHS 4.2 Section B.4.2.1
-            // If the user data is a single space char, do not store
-            // the message. Otherwise, store and display as usual
-            if (" ".equals(getMessageBody())) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public int getStatus() {
-        return mStatus;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isStatusReportMessage() {
-        return mIsStatusReportMessage;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean isReplyPathPresent() {
-        return mReplyPathPresent;
-    }
-
-    /**
-     * TS 27.005 3.1, &lt;pdu&gt; definition "In the case of SMS: 3GPP TS 24.011 [6]
-     * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format:
-     * ME/TA converts each octet of TP data unit into two IRA character long
-     * hex number (e.g. octet with integer value 42 is presented to TE as two
-     * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast,
-     * something else...
-     */
-    private void parsePdu(byte[] pdu) {
-        mPdu = pdu;
-        // Rlog.d(LOG_TAG, "raw sms message:");
-        // Rlog.d(LOG_TAG, s);
-
-        PduParser p = new PduParser(pdu);
-
-        mScAddress = p.getSCAddress();
-
-        if (mScAddress != null) {
-            if (VDBG) Rlog.d(LOG_TAG, "SMS SC address: " + mScAddress);
-        }
-
-        // TODO(mkf) support reply path, user data header indicator
-
-        // TP-Message-Type-Indicator
-        // 9.2.3
-        int firstByte = p.getByte();
-
-        mMti = firstByte & 0x3;
-        switch (mMti) {
-        // TP-Message-Type-Indicator
-        // 9.2.3
-        case 0:
-        case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved.
-                //This should be processed in the same way as MTI == 0 (Deliver)
-            parseSmsDeliver(p, firstByte);
-            break;
-        case 1:
-            parseSmsSubmit(p, firstByte);
-            break;
-        case 2:
-            parseSmsStatusReport(p, firstByte);
-            break;
-        default:
-            // TODO(mkf) the rest of these
-            throw new RuntimeException("Unsupported message type");
-        }
-    }
-
-    /**
-     * Parses a SMS-STATUS-REPORT message.
-     *
-     * @param p A PduParser, cued past the first byte.
-     * @param firstByte The first byte of the PDU, which contains MTI, etc.
-     */
-    private void parseSmsStatusReport(PduParser p, int firstByte) {
-        mIsStatusReportMessage = true;
-
-        // TP-Message-Reference
-        mMessageRef = p.getByte();
-        // TP-Recipient-Address
-        mRecipientAddress = p.getAddress();
-        // TP-Service-Centre-Time-Stamp
-        mScTimeMillis = p.getSCTimestampMillis();
-        p.getSCTimestampMillis();
-        // TP-Status
-        mStatus = p.getByte();
-
-        // The following are optional fields that may or may not be present.
-        if (p.moreDataPresent()) {
-            // TP-Parameter-Indicator
-            int extraParams = p.getByte();
-            int moreExtraParams = extraParams;
-            while ((moreExtraParams & 0x80) != 0) {
-                // We only know how to parse a few extra parameters, all
-                // indicated in the first TP-PI octet, so skip over any
-                // additional TP-PI octets.
-                moreExtraParams = p.getByte();
-            }
-            // As per 3GPP 23.040 section 9.2.3.27 TP-Parameter-Indicator,
-            // only process the byte if the reserved bits (bits3 to 6) are zero.
-            if ((extraParams & 0x78) == 0) {
-                // TP-Protocol-Identifier
-                if ((extraParams & 0x01) != 0) {
-                    mProtocolIdentifier = p.getByte();
-                }
-                // TP-Data-Coding-Scheme
-                if ((extraParams & 0x02) != 0) {
-                    mDataCodingScheme = p.getByte();
-                }
-                // TP-User-Data-Length (implies existence of TP-User-Data)
-                if ((extraParams & 0x04) != 0) {
-                    boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
-                    parseUserData(p, hasUserDataHeader);
-                }
-            }
-        }
-    }
-
-    private void parseSmsDeliver(PduParser p, int firstByte) {
-        mReplyPathPresent = (firstByte & 0x80) == 0x80;
-
-        mOriginatingAddress = p.getAddress();
-
-        if (mOriginatingAddress != null) {
-            if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: "
-                    + mOriginatingAddress.address);
-        }
-
-        // TP-Protocol-Identifier (TP-PID)
-        // TS 23.040 9.2.3.9
-        mProtocolIdentifier = p.getByte();
-
-        // TP-Data-Coding-Scheme
-        // see TS 23.038
-        mDataCodingScheme = p.getByte();
-
-        if (VDBG) {
-            Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier
-                    + " data coding scheme: " + mDataCodingScheme);
-        }
-
-        mScTimeMillis = p.getSCTimestampMillis();
-
-        if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);
-
-        boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
-
-        parseUserData(p, hasUserDataHeader);
-    }
-
-    /**
-     * Parses a SMS-SUBMIT message.
-     *
-     * @param p A PduParser, cued past the first byte.
-     * @param firstByte The first byte of the PDU, which contains MTI, etc.
-     */
-    private void parseSmsSubmit(PduParser p, int firstByte) {
-        mReplyPathPresent = (firstByte & 0x80) == 0x80;
-
-        // TP-MR (TP-Message Reference)
-        mMessageRef = p.getByte();
-
-        mRecipientAddress = p.getAddress();
-
-        if (mRecipientAddress != null) {
-            if (VDBG) Rlog.v(LOG_TAG, "SMS recipient address: " + mRecipientAddress.address);
-        }
-
-        // TP-Protocol-Identifier (TP-PID)
-        // TS 23.040 9.2.3.9
-        mProtocolIdentifier = p.getByte();
-
-        // TP-Data-Coding-Scheme
-        // see TS 23.038
-        mDataCodingScheme = p.getByte();
-
-        if (VDBG) {
-            Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier
-                    + " data coding scheme: " + mDataCodingScheme);
-        }
-
-        // TP-Validity-Period-Format
-        int validityPeriodLength = 0;
-        int validityPeriodFormat = ((firstByte>>3) & 0x3);
-        if (0x0 == validityPeriodFormat) /* 00, TP-VP field not present*/
-        {
-            validityPeriodLength = 0;
-        }
-        else if (0x2 == validityPeriodFormat) /* 10, TP-VP: relative format*/
-        {
-            validityPeriodLength = 1;
-        }
-        else /* other case, 11 or 01, TP-VP: absolute or enhanced format*/
-        {
-            validityPeriodLength = 7;
-        }
-
-        // TP-Validity-Period is not used on phone, so just ignore it for now.
-        while (validityPeriodLength-- > 0)
-        {
-            p.getByte();
-        }
-
-        boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
-
-        parseUserData(p, hasUserDataHeader);
-    }
-
-    /**
-     * Parses the User Data of an SMS.
-     *
-     * @param p The current PduParser.
-     * @param hasUserDataHeader Indicates whether a header is present in the
-     *                          User Data.
-     */
-    private void parseUserData(PduParser p, boolean hasUserDataHeader) {
-        boolean hasMessageClass = false;
-        boolean userDataCompressed = false;
-
-        int encodingType = ENCODING_UNKNOWN;
-
-        // Look up the data encoding scheme
-        if ((mDataCodingScheme & 0x80) == 0) {
-            userDataCompressed = (0 != (mDataCodingScheme & 0x20));
-            hasMessageClass = (0 != (mDataCodingScheme & 0x10));
-
-            if (userDataCompressed) {
-                Rlog.w(LOG_TAG, "4 - Unsupported SMS data coding scheme "
-                        + "(compression) " + (mDataCodingScheme & 0xff));
-            } else {
-                switch ((mDataCodingScheme >> 2) & 0x3) {
-                case 0: // GSM 7 bit default alphabet
-                    encodingType = ENCODING_7BIT;
-                    break;
-
-                case 2: // UCS 2 (16bit)
-                    encodingType = ENCODING_16BIT;
-                    break;
-
-                case 1: // 8 bit data
-                    //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
-                    //that's stored in 8-bit unpacked format) characters.
-                    Resources r = Resources.getSystem();
-                    if (r.getBoolean(com.android.internal.
-                            R.bool.config_sms_decode_gsm_8bit_data)) {
-                        encodingType = ENCODING_8BIT;
-                        break;
-                    }
-
-                case 3: // reserved
-                    Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
-                            + (mDataCodingScheme & 0xff));
-                    encodingType = ENCODING_8BIT;
-                    break;
-                }
-            }
-        } else if ((mDataCodingScheme & 0xf0) == 0xf0) {
-            hasMessageClass = true;
-            userDataCompressed = false;
-
-            if (0 == (mDataCodingScheme & 0x04)) {
-                // GSM 7 bit default alphabet
-                encodingType = ENCODING_7BIT;
-            } else {
-                // 8 bit data
-                encodingType = ENCODING_8BIT;
-            }
-        } else if ((mDataCodingScheme & 0xF0) == 0xC0
-                || (mDataCodingScheme & 0xF0) == 0xD0
-                || (mDataCodingScheme & 0xF0) == 0xE0) {
-            // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
-
-            // 0xC0 == 7 bit, don't store
-            // 0xD0 == 7 bit, store
-            // 0xE0 == UCS-2, store
-
-            if ((mDataCodingScheme & 0xF0) == 0xE0) {
-                encodingType = ENCODING_16BIT;
-            } else {
-                encodingType = ENCODING_7BIT;
-            }
-
-            userDataCompressed = false;
-            boolean active = ((mDataCodingScheme & 0x08) == 0x08);
-            // bit 0x04 reserved
-
-            // VM - If TP-UDH is present, these values will be overwritten
-            if ((mDataCodingScheme & 0x03) == 0x00) {
-                mIsMwi = true; /* Indicates vmail */
-                mMwiSense = active;/* Indicates vmail notification set/clear */
-                mMwiDontStore = ((mDataCodingScheme & 0xF0) == 0xC0);
-
-                /* Set voice mail count based on notification bit */
-                if (active == true) {
-                    mVoiceMailCount = -1; // unknown number of messages waiting
-                } else {
-                    mVoiceMailCount = 0; // no unread messages
-                }
-
-                Rlog.w(LOG_TAG, "MWI in DCS for Vmail. DCS = "
-                        + (mDataCodingScheme & 0xff) + " Dont store = "
-                        + mMwiDontStore + " vmail count = " + mVoiceMailCount);
-
-            } else {
-                mIsMwi = false;
-                Rlog.w(LOG_TAG, "MWI in DCS for fax/email/other: "
-                        + (mDataCodingScheme & 0xff));
-            }
-        } else if ((mDataCodingScheme & 0xC0) == 0x80) {
-            // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
-            // 0x80..0xBF == Reserved coding groups
-            if (mDataCodingScheme == 0x84) {
-                // This value used for KSC5601 by carriers in Korea.
-                encodingType = ENCODING_KSC5601;
-            } else {
-                Rlog.w(LOG_TAG, "5 - Unsupported SMS data coding scheme "
-                        + (mDataCodingScheme & 0xff));
-            }
-        } else {
-            Rlog.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
-                    + (mDataCodingScheme & 0xff));
-        }
-
-        // set both the user data and the user data header.
-        int count = p.constructUserData(hasUserDataHeader,
-                encodingType == ENCODING_7BIT);
-        this.mUserData = p.getUserData();
-        this.mUserDataHeader = p.getUserDataHeader();
-
-        /*
-         * Look for voice mail indication in TP_UDH TS23.040 9.2.3.24
-         * ieid = 1 (0x1) (SPECIAL_SMS_MSG_IND)
-         * ieidl =2 octets
-         * ieda msg_ind_type = 0x00 (voice mail; discard sms )or
-         *                   = 0x80 (voice mail; store sms)
-         * msg_count = 0x00 ..0xFF
-         */
-        if (hasUserDataHeader && (mUserDataHeader.specialSmsMsgList.size() != 0)) {
-            for (SmsHeader.SpecialSmsMsg msg : mUserDataHeader.specialSmsMsgList) {
-                int msgInd = msg.msgIndType & 0xff;
-                /*
-                 * TS 23.040 V6.8.1 Sec 9.2.3.24.2
-                 * bits 1 0 : basic message indication type
-                 * bits 4 3 2 : extended message indication type
-                 * bits 6 5 : Profile id bit 7 storage type
-                 */
-                if ((msgInd == 0) || (msgInd == 0x80)) {
-                    mIsMwi = true;
-                    if (msgInd == 0x80) {
-                        /* Store message because TP_UDH indicates so*/
-                        mMwiDontStore = false;
-                    } else if (mMwiDontStore == false) {
-                        /* Storage bit is not set by TP_UDH
-                         * Check for conflict
-                         * between message storage bit in TP_UDH
-                         * & DCS. The message shall be stored if either of
-                         * the one indicates so.
-                         * TS 23.040 V6.8.1 Sec 9.2.3.24.2
-                         */
-                        if (!((((mDataCodingScheme & 0xF0) == 0xD0)
-                               || ((mDataCodingScheme & 0xF0) == 0xE0))
-                               && ((mDataCodingScheme & 0x03) == 0x00))) {
-                            /* Even DCS did not have voice mail with Storage bit
-                             * 3GPP TS 23.038 V7.0.0 section 4
-                             * So clear this flag*/
-                            mMwiDontStore = true;
-                        }
-                    }
-
-                    mVoiceMailCount = msg.msgCount & 0xff;
-
-                    /*
-                     * In the event of a conflict between message count setting
-                     * and DCS then the Message Count in the TP-UDH shall
-                     * override the indication in the TP-DCS. Set voice mail
-                     * notification based on count in TP-UDH
-                     */
-                    if (mVoiceMailCount > 0)
-                        mMwiSense = true;
-                    else
-                        mMwiSense = false;
-
-                    Rlog.w(LOG_TAG, "MWI in TP-UDH for Vmail. Msg Ind = " + msgInd
-                            + " Dont store = " + mMwiDontStore + " Vmail count = "
-                            + mVoiceMailCount);
-
-                    /*
-                     * There can be only one IE for each type of message
-                     * indication in TP_UDH. In the event they are duplicated
-                     * last occurence will be used. Hence the for loop
-                     */
-                } else {
-                    Rlog.w(LOG_TAG, "TP_UDH fax/email/"
-                            + "extended msg/multisubscriber profile. Msg Ind = " + msgInd);
-                }
-            } // end of for
-        } // end of if UDH
-
-        switch (encodingType) {
-        case ENCODING_UNKNOWN:
-            mMessageBody = null;
-            break;
-
-        case ENCODING_8BIT:
-            //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
-            //that's stored in 8-bit unpacked format) characters.
-            Resources r = Resources.getSystem();
-            if (r.getBoolean(com.android.internal.
-                    R.bool.config_sms_decode_gsm_8bit_data)) {
-                mMessageBody = p.getUserDataGSM8bit(count);
-            } else {
-                mMessageBody = null;
-            }
-            break;
-
-        case ENCODING_7BIT:
-            mMessageBody = p.getUserDataGSM7Bit(count,
-                    hasUserDataHeader ? mUserDataHeader.languageTable : 0,
-                    hasUserDataHeader ? mUserDataHeader.languageShiftTable : 0);
-            break;
-
-        case ENCODING_16BIT:
-            mMessageBody = p.getUserDataUCS2(count);
-            break;
-
-        case ENCODING_KSC5601:
-            mMessageBody = p.getUserDataKSC5601(count);
-            break;
-        }
-
-        if (VDBG) Rlog.v(LOG_TAG, "SMS message body (raw): '" + mMessageBody + "'");
-
-        if (mMessageBody != null) {
-            parseMessageBody();
-        }
-
-        if (!hasMessageClass) {
-            messageClass = MessageClass.UNKNOWN;
-        } else {
-            switch (mDataCodingScheme & 0x3) {
-            case 0:
-                messageClass = MessageClass.CLASS_0;
-                break;
-            case 1:
-                messageClass = MessageClass.CLASS_1;
-                break;
-            case 2:
-                messageClass = MessageClass.CLASS_2;
-                break;
-            case 3:
-                messageClass = MessageClass.CLASS_3;
-                break;
-            }
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public MessageClass getMessageClass() {
-        return messageClass;
-    }
-
-    /**
-     * Returns true if this is a (U)SIM data download type SM.
-     * See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9.
-     *
-     * @return true if this is a USIM data download message; false otherwise
-     */
-    boolean isUsimDataDownload() {
-        return messageClass == MessageClass.CLASS_2 &&
-                (mProtocolIdentifier == 0x7f || mProtocolIdentifier == 0x7c);
-    }
-
-    public int getNumOfVoicemails() {
-        /*
-         * Order of priority if multiple indications are present is 1.UDH,
-         *      2.DCS, 3.CPHS.
-         * Voice mail count if voice mail present indication is
-         * received
-         *  1. UDH (or both UDH & DCS): mVoiceMailCount = 0 to 0xff. Ref[TS 23. 040]
-         *  2. DCS only: count is unknown mVoiceMailCount= -1
-         *  3. CPHS only: count is unknown mVoiceMailCount = 0xff. Ref[GSM-BTR-1-4700]
-         * Voice mail clear, mVoiceMailCount = 0.
-         */
-        if ((!mIsMwi) && isCphsMwiMessage()) {
-            if (mOriginatingAddress != null
-                    && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet()) {
-                mVoiceMailCount = 0xff;
-            } else {
-                mVoiceMailCount = 0;
-            }
-            Rlog.v(LOG_TAG, "CPHS voice mail message");
-        }
-        return mVoiceMailCount;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index 2df52c7..5257dad 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -184,7 +184,8 @@
 
             @Override
             public void notifyImsFeatureStatus(int featureStatus) throws RemoteException {
-                Log.i(LOG_TAG, "notifyImsFeatureStatus");
+                Log.i(LOG_TAG, "notifyImsFeatureStatus: slot=" + mSlotId + ", feature="
+                        + mFeatureType + ", status=" + featureStatus);
                 sendImsFeatureStatusChanged(mSlotId, mFeatureType, featureStatus);
             }
         };
@@ -283,7 +284,7 @@
     }
 
     /**
-     * Calls {@link IImsServiceController#removeImsFeature(int, int)} on all features that the
+     * Calls {@link IImsServiceController#removeImsFeature} on all features that the
      * ImsService supports and then unbinds the service.
      */
     public void unbind() throws RemoteException {
@@ -458,7 +459,15 @@
             Log.w(LOG_TAG, "removeImsServiceFeature called with null values.");
             return;
         }
-        mIImsServiceController.removeImsFeature(featurePair.first, featurePair.second);
+        ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c ->
+                c.mSlotId == featurePair.first && c.mFeatureType == featurePair.second)
+                .findFirst().orElse(null);
+        // Remove status callbacks from list.
+        if (callbackToRemove != null) {
+            mFeatureStatusCallbacks.remove(callbackToRemove);
+        }
+        mIImsServiceController.removeImsFeature(featurePair.first, featurePair.second,
+                (callbackToRemove != null ? callbackToRemove.getCallback() : null));
         // Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
         mCallbacks.imsServiceFeatureRemoved(featurePair.first, featurePair.second, this);
         // Send callback to ImsServiceProxy to change supported ImsFeatures
@@ -466,9 +475,6 @@
         // ImsManager requests the ImsService while it is being removed in ImsResolver, this
         // callback will clean it up after.
         sendImsFeatureRemovedCallback(featurePair.first, featurePair.second);
-        // Remove status callbacks from list.
-        mFeatureStatusCallbacks.removeIf(c -> c.mSlotId == featurePair.first
-                && c.mFeatureType == featurePair.second);
     }
 
     private void notifyAllFeaturesRemoved() {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index bf9f040..563252a 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -33,17 +33,20 @@
 import android.os.PowerManager;
 import android.os.Registrant;
 import android.os.RegistrantList;
+import android.os.ResultReceiver;
 import android.os.PowerManager.WakeLock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 
 import android.provider.Telephony;
+import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UssdResponse;
 import android.text.TextUtils;
 
 import com.android.ims.ImsCallForwardInfo;
@@ -88,6 +91,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.GsmCdmaPhone;
+import com.android.internal.telephony.MmiCode;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
@@ -366,6 +370,17 @@
         return true;
     }
 
+    @Override
+    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
+        try {
+           dialInternal(ussdRequest, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
+           return true;
+        } catch (Exception e) {
+           Rlog.d(LOG_TAG, "exception" + e);
+           return false;
+        }
+    }
+
     private boolean handleCallWaitingIncallSupplementaryService(
             String dialString) {
         int len = dialString.length();
@@ -544,7 +559,7 @@
     @Override
     public Connection
     dial(String dialString, int videoState) throws CallStateException {
-        return dialInternal(dialString, videoState, null);
+        return dialInternal(dialString, videoState, null, null);
     }
 
     @Override
@@ -552,10 +567,16 @@
     dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
             throws CallStateException {
         // ignore UUSInfo
-        return dialInternal (dialString, videoState, intentExtras);
+        return dialInternal (dialString, videoState, intentExtras, null);
     }
 
-    private Connection dialInternal(String dialString, int videoState, Bundle intentExtras)
+    protected Connection dialInternal(String dialString, int videoState, Bundle intentExtras)
+            throws CallStateException {
+        return dialInternal(dialString, videoState, intentExtras, null);
+    }
+
+    private Connection dialInternal(String dialString, int videoState,
+                                    Bundle intentExtras, ResultReceiver wrappedCallback)
             throws CallStateException {
         // Need to make sure dialString gets parsed properly
         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
@@ -933,8 +954,8 @@
         }
     }
 
-    /* package */
-    void sendErrorResponse(Message onComplete, Throwable e) {
+    @VisibleForTesting
+    public void sendErrorResponse(Message onComplete, Throwable e) {
         Rlog.d(LOG_TAG, "sendErrorResponse");
         if (onComplete != null) {
             AsyncResult.forMessage(onComplete, null, getCommandException(e));
@@ -1038,8 +1059,18 @@
          * not on the list.
          */
         if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) {
-            mMmiCompleteRegistrants.notifyRegistrants(
+            ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
+            if (receiverCallback != null) {
+                UssdResponse response = new UssdResponse(mmi.getDialString(), mmi.getMessage());
+                Bundle returnData = new Bundle();
+                returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+                int returnCode = (mmi.getState() ==  MmiCode.State.COMPLETE) ?
+                        TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
+                receiverCallback.send(returnCode, returnData);
+            } else {
+                mMmiCompleteRegistrants.notifyRegistrants(
                     new AsyncResult(null, mmi, null));
+            }
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index 5eeadbe..8228cca 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -26,14 +26,13 @@
 import android.os.WorkSource;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
-import android.telephony.Rlog;
 import android.util.Pair;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 import com.android.internal.telephony.MmiCode;
@@ -42,6 +41,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
 import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.uicc.IccFileHandler;
 
 import java.util.ArrayList;
@@ -427,6 +427,14 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+    }
+
+    @Override
     public void setNetworkSelectionModeAutomatic(Message response) {
     }
 
@@ -483,7 +491,7 @@
     }
 
     @Override
-    public boolean isDataConnectivityPossible() {
+    public boolean isDataAllowed() {
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 0bb6f1e..d9317d5 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -580,10 +580,25 @@
      */
     private boolean mShouldUpdateImsConfigOnDisconnect = false;
 
-    private ImsServiceProxy.INotifyStatusChanged mNotifyFeatureRemovedCallback = () -> {
+    // Callback fires when ImsManager MMTel Feature changes state
+    private ImsServiceProxy.INotifyStatusChanged mNotifyStatusChangedCallback = () -> {
         try {
-            if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) {
-                retryGetImsService();
+            int status = mImsManager.getImsServiceStatus();
+            log("Status Changed: " + status);
+            switch(status) {
+                case ImsFeature.STATE_READY: {
+                    startListeningForCalls();
+                    break;
+                }
+                case ImsFeature.STATE_INITIALIZING:
+                    // fall through
+                case ImsFeature.STATE_NOT_AVAILABLE: {
+                    stopListeningForCalls();
+                    break;
+                }
+                default: {
+                    Log.w(LOG_TAG, "Unexpected State!");
+                }
             }
         } catch (ImsException e) {
             // Could not get the ImsService, retry!
@@ -591,6 +606,24 @@
         }
     };
 
+    @VisibleForTesting
+    public interface IRetryTimeout {
+        int get();
+    }
+
+    /**
+     * Default implementation of interface that calculates the ImsService retry timeout.
+     * Override-able for testing.
+     */
+    @VisibleForTesting
+    public IRetryTimeout mRetryTimeout = () -> {
+        int timeout = (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS;
+        if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) {
+            mImsServiceRetryCount++;
+        }
+        return timeout;
+    };
+
     //***** Events
 
 
@@ -626,13 +659,15 @@
     private void getImsService() throws ImsException {
         if (DBG) log("getImsService");
         mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());
-        // Adding to set, will be safe adding multiple times.
-        mImsManager.addNotifyStatusChangedCallback(mNotifyFeatureRemovedCallback);
-        if (mImsManager.getImsServiceStatus() != ImsFeature.STATE_READY) {
-            // We can not call "open" until the ims service is ready
-            throw new ImsException("getImsServiceStatus()",
-                    ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
-        }
+        // Adding to set, will be safe adding multiple times. If the ImsService is not active yet,
+        // this method will throw an ImsException.
+        mImsManager.addNotifyStatusChangedCallbackIfAvailable(mNotifyStatusChangedCallback);
+        // Wait for ImsService.STATE_READY to start listening for calls.
+        // Call the callback right away for compatibility with older devices that do not use states.
+        mNotifyStatusChangedCallback.notifyStatusChanged();
+    }
+
+    private void startListeningForCalls() throws ImsException {
         mImsServiceRetryCount = 0;
         mServiceId = mImsManager.open(ImsServiceClass.MMTEL,
                 createIncomingCallPendingIntent(),
@@ -647,9 +682,9 @@
             mPhone.exitEmergencyCallbackMode();
         }
         int mPreferredTtyMode = Settings.Secure.getInt(
-            mPhone.getContext().getContentResolver(),
-            Settings.Secure.PREFERRED_TTY_MODE,
-            Phone.TTY_MODE_OFF);
+                mPhone.getContext().getContentResolver(),
+                Settings.Secure.PREFERRED_TTY_MODE,
+                Phone.TTY_MODE_OFF);
         mImsManager.setUiTTYMode(mPhone.getContext(), mPreferredTtyMode, null);
 
         ImsMultiEndpoint multiEndpoint = getMultiEndpointInterface();
@@ -659,6 +694,18 @@
         }
     }
 
+    private void stopListeningForCalls() {
+        try {
+            // Only close on valid session.
+            if (mImsManager != null && mServiceId > 0) {
+                mImsManager.close(mServiceId);
+                mServiceId = -1;
+            }
+        } catch (ImsException e) {
+            // If the binder is unavailable, then the ImsService doesn't need to close.
+        }
+    }
+
     public void dispose() {
         if (DBG) log("dispose");
         mRingingCall.dispose();
@@ -967,6 +1014,7 @@
             loge("dialInternal : " + e);
             conn.setDisconnectCause(DisconnectCause.ERROR_UNSPECIFIED);
             sendEmptyMessageDelayed(EVENT_HANGUP_PENDINGMO, TIMEOUT_HANGUP_PENDINGMO);
+            retryGetImsService();
         } catch (RemoteException e) {
         }
     }
@@ -1291,6 +1339,7 @@
         } catch (ImsException e) {
             loge("setTTYMode : " + e);
             mPhone.sendErrorResponse(onComplete, e);
+            retryGetImsService();
         }
     }
 
@@ -1490,6 +1539,7 @@
         } catch (ImsException e) {
             loge("sendUSSD : " + e);
             mPhone.sendErrorResponse(response, e);
+            retryGetImsService();
         }
     }
 
@@ -2272,16 +2322,19 @@
                     targetAccessTech + ", reasonInfo=" + reasonInfo);
             }
 
-            boolean isHandoverToWifi = srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN &&
-                    targetAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+            // Only consider it a valid handover to WIFI if the source radio tech is known.
+            boolean isHandoverToWifi = srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+                    && srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                    && targetAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
             if (isHandoverToWifi) {
                 // If we handed over to wifi successfully, don't check for failure in the future.
                 removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
             }
 
-            boolean isHandoverFromWifi =
-                    srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN &&
-                            targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+            // Only consider it a handover from WIFI if the source and target radio tech is known.
+            boolean isHandoverFromWifi = srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+                    && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+                    && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
             if (mNotifyHandoverVideoFromWifiToLTE && isHandoverFromWifi && imsCall.isVideoCall()) {
                 log("onCallHandover :: notifying of WIFI to LTE handover.");
                 ImsPhoneConnection conn = findConnection(imsCall);
@@ -2325,6 +2378,34 @@
             }
         }
 
+        @Override
+        public void onRttModifyRequestReceived(ImsCall imsCall) {
+            ImsPhoneConnection conn = findConnection(imsCall);
+            if (conn != null) {
+                conn.onRttModifyRequestReceived();
+            }
+        }
+
+        @Override
+        public void onRttModifyResponseReceived(ImsCall imsCall, int status) {
+            ImsPhoneConnection conn = findConnection(imsCall);
+            if (conn != null) {
+                conn.onRttModifyResponseReceived(status);
+                if (status ==
+                        android.telecom.Connection.RttModifyStatus.SESSION_MODIFY_REQUEST_SUCCESS) {
+                    conn.startRttTextProcessing();
+                }
+            }
+        }
+
+        @Override
+        public void onRttMessageReceived(ImsCall imsCall, String message) {
+            ImsPhoneConnection conn = findConnection(imsCall);
+            if (conn != null) {
+                conn.onRttMessageReceived(message);
+            }
+        }
+
         /**
          * Handles a change to the multiparty state for an {@code ImsCall}.  Notifies the associated
          * {@link ImsPhoneConnection} of the change.
@@ -2834,16 +2915,16 @@
     }
 
     private void retryGetImsService() {
+        // The binder connection is already up. Do not try to get it again.
+        if (mImsManager.isServiceAvailable()) {
+            return;
+        }
         //Leave mImsManager as null, then CallStateException will be thrown when dialing
         mImsManager = null;
         // Exponential backoff during retry, limited to 32 seconds.
         loge("getImsService: Retrying getting ImsService...");
         removeMessages(EVENT_GET_IMS_SERVICE);
-        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE,
-                (1 << mImsServiceRetryCount) * IMS_RETRY_STARTING_TIMEOUT_MS);
-        if (mImsServiceRetryCount <= CEILING_SERVICE_RETRY_COUNT) {
-            mImsServiceRetryCount++;
-        }
+        sendEmptyMessageDelayed(EVENT_GET_IMS_SERVICE, mRetryTimeout.get());
     }
 
     private void setVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall)
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 8d0bbb1..0f6c68d 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.dataconnection.DataProfile;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 
+import java.security.PublicKey;
 import java.util.List;
 
 /**
@@ -333,6 +334,14 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+    }
+
+    @Override
     public void setCallForward(int action, int cfReason, int serviceClass,
                 String number, int timeSeconds, Message response) {
     }
@@ -615,6 +624,11 @@
     }
 
     @Override
+    public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+                                                Message result) {
+    }
+
+    @Override
     public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result) {
     }
 
@@ -631,6 +645,6 @@
     }
 
     @Override
-    public void setSimCardPower(boolean powerUp, Message result) {
+    public void setSimCardPower(int state, Message result) {
     }
 }
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index 2273e43..31e1f78 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -104,6 +104,9 @@
 
     private int mPreciseDisconnectCause = 0;
 
+    private ImsRttTextHandler mRttTextHandler;
+    private android.telecom.Connection.RttTextStream mRttTextStream;
+
     //***** Event Constants
     private static final int EVENT_DTMF_DONE = 1;
     private static final int EVENT_PAUSE_DONE = 2;
@@ -415,8 +418,10 @@
             } else {
                 Rlog.d(LOG_TAG, "onDisconnect: no parent");
             }
-            if (mImsCall != null) mImsCall.close();
-            mImsCall = null;
+            synchronized (this) {
+                if (mImsCall != null) mImsCall.close();
+                mImsCall = null;
+            }
         }
         releaseWakeLock();
         return changed;
@@ -613,7 +618,7 @@
     }
 
     @Override
-    public boolean isMultiparty() {
+    public synchronized boolean isMultiparty() {
         return mImsCall != null && mImsCall.isMultiparty();
     }
 
@@ -626,11 +631,8 @@
      *      {@code false} otherwise.
      */
     @Override
-    public boolean isConferenceHost() {
-        if (mImsCall == null) {
-            return false;
-        }
-        return mImsCall.isConferenceHost();
+    public synchronized boolean isConferenceHost() {
+        return mImsCall != null && mImsCall.isConferenceHost();
     }
 
     @Override
@@ -638,11 +640,11 @@
         return !isConferenceHost();
     }
 
-    public ImsCall getImsCall() {
+    public synchronized ImsCall getImsCall() {
         return mImsCall;
     }
 
-    public void setImsCall(ImsCall imsCall) {
+    public synchronized void setImsCall(ImsCall imsCall) {
         mImsCall = imsCall;
     }
 
@@ -889,6 +891,51 @@
         return changed;
     }
 
+    public void sendRttModifyRequest(android.telecom.Connection.RttTextStream textStream) {
+        getImsCall().sendRttModifyRequest();
+        setCurrentRttTextStream(textStream);
+    }
+
+    /**
+     * Sends the user's response to a remotely-issued RTT upgrade request
+     *
+     * @param textStream A valid {@link android.telecom.Connection.RttTextStream} if the user
+     *                   accepts, {@code null} if not.
+     */
+    public void sendRttModifyResponse(android.telecom.Connection.RttTextStream textStream) {
+        boolean accept = textStream != null;
+        ImsCall imsCall = getImsCall();
+
+        imsCall.sendRttModifyResponse(accept);
+        if (accept) {
+            setCurrentRttTextStream(textStream);
+            startRttTextProcessing();
+        } else {
+            Rlog.e(LOG_TAG, "sendRttModifyResponse: foreground call has no connections");
+        }
+    }
+
+    public void onRttMessageReceived(String message) {
+        getOrCreateRttTextHandler().sendToInCall(message);
+    }
+
+    public void setCurrentRttTextStream(android.telecom.Connection.RttTextStream rttTextStream) {
+        mRttTextStream = rttTextStream;
+    }
+
+    public void startRttTextProcessing() {
+        getOrCreateRttTextHandler().initialize(mRttTextStream);
+    }
+
+    private ImsRttTextHandler getOrCreateRttTextHandler() {
+        if (mRttTextHandler != null) {
+            return mRttTextHandler;
+        }
+        mRttTextHandler = new ImsRttTextHandler(Looper.getMainLooper(),
+                (message) -> getImsCall().sendRttMessage(message));
+        return mRttTextHandler;
+    }
+
     /**
      * Updates the wifi state based on the {@link ImsCallProfile#EXTRA_CALL_RAT_TYPE}.
      * The call is considered to be a WIFI call if the extra value is
@@ -1012,10 +1059,12 @@
         sb.append(" address: ");
         sb.append(Rlog.pii(LOG_TAG, getAddress()));
         sb.append(" ImsCall: ");
-        if (mImsCall == null) {
-            sb.append("null");
-        } else {
-            sb.append(mImsCall);
+        synchronized (this) {
+            if (mImsCall == null) {
+                sb.append("null");
+            } else {
+                sb.append(mImsCall);
+            }
         }
         sb.append("]");
         return sb.toString();
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
index 9c7e875..2387fb1 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ResultReceiver;
 import android.telephony.PhoneNumberUtils;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -176,6 +177,7 @@
     private String mPoundString;         // Entire MMI string up to and including #
     private String mDialingNumber;
     private String mPwd;                 // For password registration
+    private ResultReceiver mCallbackReceiver;
 
     private boolean mIsPendingUSSD;
 
@@ -234,8 +236,12 @@
      * Please see flow chart in TS 22.030 6.5.3.2
      */
 
-    static ImsPhoneMmiCode
-    newFromDialString(String dialString, ImsPhone phone) {
+    static ImsPhoneMmiCode newFromDialString(String dialString, ImsPhone phone) {
+       return newFromDialString(dialString, phone, null);
+    }
+
+    static ImsPhoneMmiCode newFromDialString(String dialString,
+                                             ImsPhone phone, ResultReceiver wrappedCallback) {
         Matcher m;
         ImsPhoneMmiCode ret = null;
 
@@ -252,6 +258,7 @@
             ret.mSic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
             ret.mPwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
             ret.mDialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
+            ret.mCallbackReceiver = wrappedCallback;
             // According to TS 22.030 6.5.2 "Structure of the MMI",
             // the dialing number should not ending with #.
             // The dialing number ending # is treated as unique USSD,
@@ -534,6 +541,11 @@
 
     }
 
+    @Override
+    public String getDialString() {
+        return mPoundString;
+    }
+
     static private boolean
     isTwoDigitShortCode(Context context, String dialString) {
         Rlog.d(LOG_TAG, "isTwoDigitShortCode");
@@ -1631,6 +1643,11 @@
         return sb;
     }
 
+    @Override
+    public ResultReceiver getUssdCallbackReceiver() {
+        return this.mCallbackReceiver;
+    }
+
     /***
      * TODO: It would be nice to have a method here that can take in a dialstring and
      * figure out if there is an MMI code embedded within it.  This code would replace
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
new file mode 100644
index 0000000..68a832b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/imsphone/ImsRttTextHandler.java
@@ -0,0 +1,203 @@
+/*
+ * 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.imsphone;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.telecom.Connection;
+import android.telephony.Rlog;
+
+import java.io.IOException;
+
+public class ImsRttTextHandler extends Handler {
+    public interface NetworkWriter {
+        void write(String s);
+    }
+
+    private static final String LOG_TAG = "ImsRttTextHandler";
+    // RTT buffering and sending tuning constants.
+    // TODO: put this in carrier config?
+
+    // These count Unicode codepoints, not Java char types.
+    public static final int MAX_CODEPOINTS_PER_SECOND = 30;
+    // Assuming that we do not exceed the rate limit, this is the maximum time between when a
+    // piece of text is received and when it is actually sent over the network.
+    public static final int MAX_BUFFERING_DELAY_MILLIS = 200;
+    // Assuming that we do not exceed the rate limit, this is the maximum size we will allow
+    // the buffer to grow to before sending as many as we can.
+    public static final int MAX_BUFFERED_CHARACTER_COUNT = 5;
+    private static final int MILLIS_PER_SECOND = 1000;
+
+    // Messages for the handler.
+    // Initializes the text handler. Should have an RttTextStream set in msg.obj
+    private static final int INITIALIZE = 1;
+    // Appends a string to the buffer to send to the network. Should have the string in msg.obj
+    private static final int APPEND_TO_NETWORK_BUFFER = 2;
+    // Send a string received from the network to the in-call app. Should have the string in
+    // msg.obj.
+    private static final int SEND_TO_INCALL = 3;
+    // Send as many characters as possible, as constrained by the rate limit. No extra data.
+    private static final int ATTEMPT_SEND_TO_NETWORK = 4;
+    // Indicates that N characters were sent a second ago and should be ignored by the rate
+    // limiter. msg.arg1 should be set to N.
+    private static final int EXPIRE_SENT_CODEPOINT_COUNT = 5;
+    // Indicates that the call is over and we should teardown everything we have set up.
+    private static final int TEARDOWN = 6;
+
+    private Connection.RttTextStream mRttTextStream;
+
+    private class InCallReaderThread extends Thread {
+        private final Connection.RttTextStream mReaderThreadRttTextStream;
+
+        public InCallReaderThread(Connection.RttTextStream textStream) {
+            mReaderThreadRttTextStream = textStream;
+        }
+
+        @Override
+        public void run() {
+            while (true) {
+                String charsReceived;
+                try {
+                    charsReceived = mReaderThreadRttTextStream.read();
+                } catch (IOException e) {
+                    Rlog.e(LOG_TAG, "RttReaderThread - IOException encountered " +
+                            "reading from in-call: %s", e);
+                    obtainMessage(TEARDOWN).sendToTarget();
+                    break;
+                }
+                if (charsReceived == null) {
+                    if (Thread.currentThread().isInterrupted()) {
+                        Rlog.i(LOG_TAG, "RttReaderThread - Thread interrupted. Finishing.");
+                        break;
+                    }
+                    Rlog.e(LOG_TAG, "RttReaderThread - Stream closed unexpectedly. Attempt to " +
+                            "reinitialize.");
+                    obtainMessage(TEARDOWN).sendToTarget();
+                    break;
+                }
+                if (charsReceived.length() == 0) {
+                    continue;
+                }
+                obtainMessage(APPEND_TO_NETWORK_BUFFER, charsReceived)
+                        .sendToTarget();
+            }
+        }
+    }
+
+    private int mCodepointsAvailableForTransmission = MAX_CODEPOINTS_PER_SECOND;
+    private StringBuffer mBufferedTextToNetwork = new StringBuffer();
+    private InCallReaderThread mReaderThread;
+    // This is only ever used when the pipes fail and we have to re-setup. Messages received
+    // from the network are buffered here until Telecom gets back to us with the new pipes.
+    private StringBuffer mBufferedTextToIncall = new StringBuffer();
+    private final NetworkWriter mNetworkWriter;
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case INITIALIZE:
+                if (mRttTextStream != null || mReaderThread != null) {
+                    Rlog.e(LOG_TAG, "RTT text stream already initialized. Ignoring.");
+                    return;
+                }
+                mRttTextStream = (Connection.RttTextStream) msg.obj;
+                mReaderThread = new InCallReaderThread(mRttTextStream);
+                mReaderThread.start();
+                break;
+            case SEND_TO_INCALL:
+                String messageToIncall = (String) msg.obj;
+                try {
+                    mRttTextStream.write(messageToIncall);
+                } catch (IOException e) {
+                    Rlog.e(LOG_TAG, "IOException encountered writing to in-call: %s", e);
+                    obtainMessage(TEARDOWN).sendToTarget();
+                    mBufferedTextToIncall.append(messageToIncall);
+                }
+                break;
+            case APPEND_TO_NETWORK_BUFFER:
+                // First, append the text-to-send to the string buffer
+                mBufferedTextToNetwork.append((String) msg.obj);
+                // Check to see how many codepoints we have buffered. If we have more than 5,
+                // send immediately, otherwise, wait until a timeout happens.
+                int numCodepointsBuffered = mBufferedTextToNetwork
+                        .codePointCount(0, mBufferedTextToNetwork.length());
+                if (numCodepointsBuffered >= MAX_BUFFERED_CHARACTER_COUNT) {
+                    sendMessageAtFrontOfQueue(obtainMessage(ATTEMPT_SEND_TO_NETWORK));
+                } else {
+                    sendEmptyMessageDelayed(
+                            ATTEMPT_SEND_TO_NETWORK, MAX_BUFFERING_DELAY_MILLIS);
+                }
+                break;
+            case ATTEMPT_SEND_TO_NETWORK:
+                // Check to see how many codepoints we can send, and send that many.
+                int numCodePointsAvailableInBuffer = mBufferedTextToNetwork.codePointCount(0,
+                        mBufferedTextToNetwork.length());
+                int numCodePointsSent = Math.min(numCodePointsAvailableInBuffer,
+                        mCodepointsAvailableForTransmission);
+                if (numCodePointsSent == 0) {
+                    break;
+                }
+                int endSendIndex = mBufferedTextToNetwork.offsetByCodePoints(0,
+                        numCodePointsSent);
+
+                String stringToSend = mBufferedTextToNetwork.substring(0, endSendIndex);
+
+                mBufferedTextToNetwork.delete(0, endSendIndex);
+                mNetworkWriter.write(stringToSend);
+                mCodepointsAvailableForTransmission -= numCodePointsSent;
+                sendMessageDelayed(
+                        obtainMessage(EXPIRE_SENT_CODEPOINT_COUNT, numCodePointsSent, 0),
+                        MILLIS_PER_SECOND);
+                break;
+            case EXPIRE_SENT_CODEPOINT_COUNT:
+                mCodepointsAvailableForTransmission += msg.arg1;
+                if (mCodepointsAvailableForTransmission > 0) {
+                    sendMessageAtFrontOfQueue(obtainMessage(ATTEMPT_SEND_TO_NETWORK));
+                }
+                break;
+            case TEARDOWN:
+                try {
+                    if (mReaderThread != null) {
+                        mReaderThread.join(1000);
+                    }
+                } catch (InterruptedException e) {
+                    // Ignore and assume it'll finish on its own.
+                }
+                mReaderThread = null;
+                mRttTextStream = null;
+                break;
+        }
+    }
+
+    public ImsRttTextHandler(Looper looper, NetworkWriter networkWriter) {
+        super(looper);
+        mNetworkWriter = networkWriter;
+    }
+
+    public void sendToInCall(String msg) {
+        obtainMessage(SEND_TO_INCALL, msg).sendToTarget();
+    }
+
+    public void initialize(Connection.RttTextStream rttTextStream) {
+        obtainMessage(INITIALIZE, rttTextStream).sendToTarget();
+    }
+
+    public void tearDown() {
+        obtainMessage(TEARDOWN).sendToTarget();
+    }
+}
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 16dbb83..80c37ad 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -16,18 +16,19 @@
 
 package com.android.internal.telephony.metrics;
 
-import android.os.SystemClock;
-
 import static com.android.internal.telephony.TelephonyProto.ImsCapabilities;
 import static com.android.internal.telephony.TelephonyProto.ImsConnectionState;
 import static com.android.internal.telephony.TelephonyProto.RilDataCall;
 import static com.android.internal.telephony.TelephonyProto.TelephonyEvent;
+import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.ModemRestart;
 import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCall;
 import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
 import static com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
 import static com.android.internal.telephony.TelephonyProto.TelephonySettings;
 
+import android.os.SystemClock;
+
 public class TelephonyEventBuilder {
     private final TelephonyEvent mEvent = new TelephonyEvent();
 
@@ -109,4 +110,10 @@
         mEvent.setNitzTimestampMillis(timestamp);
         return this;
     }
+
+    public TelephonyEventBuilder setModemRestart(ModemRestart modemRestart) {
+        mEvent.setType(TelephonyEvent.Type.MODEM_RESTART);
+        mEvent.modemRestart = modemRestart;
+        return this;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index eddb1c0..45df5ae 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -16,18 +16,36 @@
 
 package com.android.internal.telephony.metrics;
 
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_SEND_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
+import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IP;
+import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
+import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV6;
+import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_PPP;
+import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_UNKNOWN;
+
+import android.os.Build;
 import android.os.SystemClock;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyHistogram;
 import android.util.Base64;
-import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsReasonInfo;
 import com.android.ims.internal.ImsCallSession;
-import com.android.internal.telephony.Call;
 import com.android.internal.telephony.GsmCdmaConnection;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RIL;
@@ -39,10 +57,11 @@
 import com.android.internal.telephony.TelephonyProto.RilDataCall;
 import com.android.internal.telephony.TelephonyProto.SmsSession;
 import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState.*;
 import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall;
 import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall.Type.*;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState.*;
 import com.android.internal.telephony.TelephonyProto.TelephonyEvent;
+import com.android.internal.telephony.TelephonyProto.TelephonyEvent.ModemRestart;
 import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
 import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCall;
 import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
@@ -63,25 +82,6 @@
 import java.util.Deque;
 import java.util.List;
 
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_SEND_SMS;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IP;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV6;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_PPP;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_UNKNOWN;
-
 /**
  * Telephony metrics holds all metrics events and convert it into telephony proto buf.
  * @hide
@@ -1627,6 +1627,22 @@
                         .setNITZ(timestamp));
     }
 
+    /**
+     * Write Modem Restart event
+     *
+     * @param phoneId Phone id
+     * @param reason Reason for the modem reset.
+     */
+    public void writeModemRestartEvent(int phoneId, String reason) {
+        final ModemRestart modemRestart = new ModemRestart();
+        String basebandVersion = Build.getRadioVersion();
+        if (basebandVersion != null) modemRestart.setBasebandVersion(basebandVersion);
+        if (reason != null) modemRestart.setReason(reason);
+        TelephonyEvent event = new TelephonyEventBuilder(phoneId).setModemRestart(
+                modemRestart).build();
+        addTelephonyEvent(event);
+    }
+
     //TODO: Expand the proto in the future
     public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {}
     public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {}
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index bd7fae4..e72496a 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -28,6 +28,7 @@
 import com.android.internal.telephony.dataconnection.DataProfile;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 
+import java.security.PublicKey;
 import java.util.List;
 
 /**
@@ -334,6 +335,14 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+    }
+
+    @Override
     public void setCallForward(int action, int cfReason, int serviceClass,
                 String number, int timeSeconds, Message response) {
     }
@@ -617,6 +626,11 @@
     }
 
     @Override
+    public void setCarrierInfoForImsiEncryption(PublicKey carrierPublicKey, String keyIdentifier,
+                                                Message result) {
+    }
+
+    @Override
     public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result) {
     }
 
@@ -633,6 +647,6 @@
     }
 
     @Override
-    public void setSimCardPower(boolean powerUp, Message result) {
+    public void setSimCardPower(int state, Message result) {
     }
 }
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 2a336bf..eff731e 100755
--- a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -23,26 +23,27 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
+import android.os.ResultReceiver;
 import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.telephony.CellLocation;
+import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
-import android.telephony.Rlog;
 
 import com.android.internal.telephony.Call;
 import com.android.internal.telephony.CallStateException;
 import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
 import com.android.internal.telephony.MmiCode;
 import com.android.internal.telephony.OperatorInfo;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.PhoneNotifier;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.dataconnection.DataConnection;
 import com.android.internal.telephony.uicc.IccFileHandler;
 
 import java.util.ArrayList;
@@ -240,6 +241,11 @@
     }
 
     @Override
+    public boolean handleUssdRequest(String dialString, ResultReceiver wrappedCallback) {
+        return false;
+    }
+
+    @Override
     public void sendUssdResponse(String ussdMessge) {
     }
 
@@ -388,6 +394,14 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+    }
+
+    @Override
     public void setNetworkSelectionModeAutomatic(Message response) {
     }
 
@@ -447,7 +461,7 @@
     }
 
     @Override
-    public boolean isDataConnectivityPossible() {
+    public boolean isDataAllowed() {
         return false;
     }
 
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 5a78f29..59d999f 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -53,6 +53,7 @@
 import com.android.internal.telephony.uicc.IccCardStatus;
 import com.android.internal.telephony.uicc.IccIoResult;
 
+import java.security.PublicKey;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -150,6 +151,12 @@
         mPin2Code = DEFAULT_SIM_PIN2_CODE;
     }
 
+    public void dispose() {
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+        }
+    }
+
     private void log(String str) {
         Rlog.d(LOG_TAG, str);
     }
@@ -1354,7 +1361,25 @@
      * ((AsyncResult)response.obj).result  is a List of NetworkInfo objects
      */
     @Override
-    public void getAvailableNetworks(Message result) {unimplemented(result);}
+    public void getAvailableNetworks(Message result) {
+        unimplemented(result);
+    }
+
+    /**
+     * Starts a network scan
+     */
+    @Override
+    public void startNetworkScan(Message result) {
+        unimplemented(result);
+    }
+
+    /**
+     * Stops an ongoing network scan
+     */
+    @Override
+    public void stopNetworkScan(Message result) {
+        unimplemented(result);
+    }
 
     @Override
     public void getBasebandVersion (Message result) {
@@ -1429,6 +1454,16 @@
     }
 
     @Override
+    public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+                                                Message response) {
+        // Just echo back data
+        if (response != null) {
+            AsyncResult.forMessage(response).result = publicKey;
+            response.sendToTarget();
+        }
+    }
+
+    @Override
     public void invokeOemRilRequestStrings(String[] strings, Message response) {
         // Just echo back data
         if (response != null) {
@@ -2105,7 +2140,7 @@
     }
 
     @Override
-    public void setSimCardPower(boolean powerUp, Message result) {
+    public void setSimCardPower(int state, Message result) {
     }
 
     @VisibleForTesting
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index 489da81..c5da1e0 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -27,6 +27,7 @@
 import com.android.internal.telephony.dataconnection.DataProfile;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 
+import java.security.PublicKey;
 import java.util.List;
 
 public class SimulatedCommandsVerifier implements CommandsInterface {
@@ -945,6 +946,16 @@
     }
 
     @Override
+    public void startNetworkScan(Message response) {
+
+    }
+
+    @Override
+    public void stopNetworkScan(Message response) {
+
+    }
+
+    @Override
     public void getBasebandVersion(Message response) {
 
     }
@@ -1338,6 +1349,12 @@
     }
 
     @Override
+    public void setCarrierInfoForImsiEncryption(PublicKey carrierPublicKey, String keyIdentifier,
+                                                Message result) {
+
+    }
+
+    @Override
     public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result) {
 
     }
@@ -1364,6 +1381,22 @@
     }
 
     @Override
-    public void setSimCardPower(boolean powerUp, Message result) {
+    public void setSimCardPower(int state, Message result) {
+    }
+
+    @Override
+    public void registerForCarrierInfoForImsiEncryption(Handler h, int what, Object obj) {
+    }
+
+    @Override
+    public void registerForNetworkScanResult(Handler h, int what, Object obj) {
+    }
+
+    @Override
+    public void unregisterForNetworkScanResult(Handler h) {
+    }
+
+    @Override
+    public void unregisterForCarrierInfoForImsiEncryption(Handler h) {
     }
 }
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
index 2235654..5466402 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 
 import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.CommandsInterface.RadioState;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.IccCardConstants.State;
@@ -107,7 +108,7 @@
     private UiccCardApplication mUiccApplication = null;
     private IccRecords mIccRecords = null;
     private CdmaSubscriptionSourceManager mCdmaSSM = null;
-    private boolean mRadioOn = false;
+    private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE;
     private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
                                         // ACTION_SIM_STATE_CHANGED intents
     private boolean mInitialized = false;
@@ -130,7 +131,6 @@
         ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
 
         resetProperties();
-        setExternalState(State.NOT_READY, false);
     }
 
     public void dispose() {
@@ -211,15 +211,18 @@
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case EVENT_RADIO_OFF_OR_UNAVAILABLE:
-                mRadioOn = false;
-                if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
-                    setExternalState(State.NOT_READY);
-                }
+                mRadioState = mCi.getRadioState();
+                updateExternalState();
                 break;
             case EVENT_RADIO_ON:
-                mRadioOn = true;
+                mRadioState = RadioState.RADIO_ON;
                 if (!mInitialized) {
                     updateQuietMode();
+                } else {
+                    // updateQuietMode() triggers ICC_CHANGED, which eventually
+                    // calls updateExternalState; thus, we don't need this in the
+                    // above case
+                    updateExternalState();
                 }
                 break;
             case EVENT_ICC_CHANGED:
@@ -326,11 +329,9 @@
     private void updateIccAvailability() {
         synchronized (mLock) {
             UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
-            CardState state = CardState.CARDSTATE_ABSENT;
             UiccCardApplication newApp = null;
             IccRecords newRecords = null;
             if (newCard != null) {
-                state = newCard.getCardState();
                 newApp = newCard.getApplication(mCurrentAppType);
                 if (newApp != null) {
                     newRecords = newApp.getIccRecords();
@@ -338,7 +339,7 @@
             }
 
             if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
-                if (DBG) log("Icc changed. Reregestering.");
+                if (DBG) log("Icc changed. Reregistering.");
                 unregisterUiccCardEvents();
                 mUiccCard = newCard;
                 mUiccApplication = newApp;
@@ -368,15 +369,27 @@
         // mUiccCard could be null at bootup, before valid card states have
         // been received from UiccController.
         if (mUiccCard == null) {
-            setExternalState(State.NOT_READY);
+            setExternalState(State.UNKNOWN);
             return;
         }
 
         if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
-            if (mRadioOn) {
-                setExternalState(State.ABSENT);
+            /*
+             * Both IccCardProxy and UiccController are registered for
+             * RadioState changes. When the UiccController receives a radio
+             * state changed to Unknown it will dispose of all of the IccCard
+             * objects, which will then notify the IccCardProxy and the null
+             * object will force the state to unknown. However, because the
+             * IccCardProxy is also registered for RadioState changes, it will
+             * recieve that signal first. By triggering on radio state changes
+             * directly, we reduce the time window during which the modem is
+             * UNAVAILABLE but the IccStatus is reported as something valid.
+             * This is not ideal.
+             */
+            if (mRadioState == RadioState.RADIO_UNAVAILABLE) {
+                setExternalState(State.UNKNOWN);
             } else {
-                setExternalState(State.NOT_READY);
+                setExternalState(State.ABSENT);
             }
             return;
         }
@@ -396,9 +409,20 @@
             return;
         }
 
+        // By process of elimination, the UICC Card State = PRESENT
         switch (mUiccApplication.getState()) {
             case APPSTATE_UNKNOWN:
-                setExternalState(State.UNKNOWN);
+                /*
+                 * APPSTATE_UNKNOWN is a catch-all state reported whenever the app
+                 * is not explicitly in one of the other states. To differentiate the
+                 * case where we know that there is a card present, but the APP is not
+                 * ready, we choose NOT_READY here instead of unknown. This is possible
+                 * in at least two cases:
+                 * 1) A transient during the process of the SIM bringup
+                 * 2) There is no valid App on the SIM to load, which can be the case with an
+                 *    eSIM/soft SIM.
+                 */
+                setExternalState(State.NOT_READY);
                 break;
             case APPSTATE_DETECTED:
                 HandleDetectedState();
@@ -516,15 +540,16 @@
             }
 
             if (!override && newState == mExternalState) {
-                loge("setExternalState: !override and newstate unchanged from " + newState);
+                log("setExternalState: !override and newstate unchanged from " + newState);
                 return;
             }
             mExternalState = newState;
-            loge("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
+            log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
             mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
 
             // For locked states, we should be sending internal broadcast.
-            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
+            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(
+                        getIccStateIntentString(mExternalState))) {
                 broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
                         getIccStateReason(mExternalState));
             } else {
@@ -937,7 +962,7 @@
         pw.println(" mUiccApplication=" + mUiccApplication);
         pw.println(" mIccRecords=" + mIccRecords);
         pw.println(" mCdmaSSM=" + mCdmaSSM);
-        pw.println(" mRadioOn=" + mRadioOn);
+        pw.println(" mRadioState=" + mRadioState);
         pw.println(" mQuietMode=" + mQuietMode);
         pw.println(" mInitialized=" + mInitialized);
         pw.println(" mExternalState=" + mExternalState);
diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java
index 970bf35..0f41f1e 100644
--- a/src/java/com/android/internal/telephony/uicc/IccConstants.java
+++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java
@@ -97,11 +97,6 @@
     //Search interval for higher priority PLMNs
     static final int EF_HPPLMN = 0x6F31;
 
-    // SMS record length from TS 51.011 10.5.3
-    static public final int SMS_RECORD_LENGTH = 176;
-    // SMS record length from C.S0023 3.4.27
-    static public final int CDMA_SMS_RECORD_LENGTH = 255;
-
     static final String MF_SIM = "3F00";
     static final String DF_TELECOM = "7F10";
     static final String DF_PHONEBOOK = "5F3A";
diff --git a/src/java/com/android/internal/telephony/uicc/IccUtils.java b/src/java/com/android/internal/telephony/uicc/IccUtils.java
deleted file mode 100644
index 67de87f..0000000
--- a/src/java/com/android/internal/telephony/uicc/IccUtils.java
+++ /dev/null
@@ -1,570 +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 com.android.internal.telephony.uicc;
-
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.telephony.Rlog;
-
-import com.android.internal.telephony.GsmAlphabet;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Various methods, useful for dealing with SIM data.
- */
-public class IccUtils {
-    static final String LOG_TAG="IccUtils";
-
-    /**
-     * Many fields in GSM SIM's are stored as nibble-swizzled BCD
-     *
-     * Assumes left-justified field that may be padded right with 0xf
-     * values.
-     *
-     * Stops on invalid BCD value, returning string so far
-     */
-    public static String
-    bcdToString(byte[] data, int offset, int length) {
-        StringBuilder ret = new StringBuilder(length*2);
-
-        for (int i = offset ; i < offset + length ; i++) {
-            int v;
-
-            v = data[i] & 0xf;
-            if (v > 9)  break;
-            ret.append((char)('0' + v));
-
-            v = (data[i] >> 4) & 0xf;
-            // Some PLMNs have 'f' as high nibble, ignore it
-            if (v == 0xf) continue;
-            if (v > 9)  break;
-            ret.append((char)('0' + v));
-        }
-
-        return ret.toString();
-    }
-
-    /**
-     * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3
-     * Returns a concatenated string of MCC+MNC, stripping
-     * a trailing character for a 2-digit MNC
-     */
-    public static String bcdPlmnToString(byte[] data, int offset) {
-        if (offset + 3 > data.length) {
-            return null;
-        }
-        byte[] trans = new byte[3];
-        trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF));
-        trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF));
-        trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF));
-        String ret = bytesToHexString(trans);
-
-        // For a 2-digit MNC we trim the trailing 'f'
-        if (ret.endsWith("f")) {
-            ret = ret.substring(0, ret.length() - 1);
-        }
-        return ret;
-    }
-
-    /**
-     * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH
-     */
-    public static String
-    bchToString(byte[] data, int offset, int length) {
-        StringBuilder ret = new StringBuilder(length*2);
-
-        for (int i = offset ; i < offset + length ; i++) {
-            int v;
-
-            v = data[i] & 0xf;
-            ret.append("0123456789abcdef".charAt(v));
-
-            v = (data[i] >> 4) & 0xf;
-            ret.append("0123456789abcdef".charAt(v));
-        }
-
-        return ret.toString();
-    }
-
-    /**
-     * Decode cdma byte into String.
-     */
-    public static String
-    cdmaBcdToString(byte[] data, int offset, int length) {
-        StringBuilder ret = new StringBuilder(length);
-
-        int count = 0;
-        for (int i = offset; count < length; i++) {
-            int v;
-            v = data[i] & 0xf;
-            if (v > 9)  v = 0;
-            ret.append((char)('0' + v));
-
-            if (++count == length) break;
-
-            v = (data[i] >> 4) & 0xf;
-            if (v > 9)  v = 0;
-            ret.append((char)('0' + v));
-            ++count;
-        }
-        return ret.toString();
-    }
-
-    /**
-     * Decodes a GSM-style BCD byte, returning an int ranging from 0-99.
-     *
-     * In GSM land, the least significant BCD digit is stored in the most
-     * significant nibble.
-     *
-     * Out-of-range digits are treated as 0 for the sake of the time stamp,
-     * because of this:
-     *
-     * TS 23.040 section 9.2.3.11
-     * "if the MS receives a non-integer value in the SCTS, it shall
-     * assume the digit is set to 0 but shall store the entire field
-     * exactly as received"
-     */
-    public static int
-    gsmBcdByteToInt(byte b) {
-        int ret = 0;
-
-        // treat out-of-range BCD values as 0
-        if ((b & 0xf0) <= 0x90) {
-            ret = (b >> 4) & 0xf;
-        }
-
-        if ((b & 0x0f) <= 0x09) {
-            ret +=  (b & 0xf) * 10;
-        }
-
-        return ret;
-    }
-
-    /**
-     * Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but
-     * opposite nibble format. The least significant BCD digit
-     * is in the least significant nibble and the most significant
-     * is in the most significant nibble.
-     */
-    public static int
-    cdmaBcdByteToInt(byte b) {
-        int ret = 0;
-
-        // treat out-of-range BCD values as 0
-        if ((b & 0xf0) <= 0x90) {
-            ret = ((b >> 4) & 0xf) * 10;
-        }
-
-        if ((b & 0x0f) <= 0x09) {
-            ret +=  (b & 0xf);
-        }
-
-        return ret;
-    }
-
-    /**
-     * Decodes a string field that's formatted like the EF[ADN] alpha
-     * identifier
-     *
-     * From TS 51.011 10.5.1:
-     *   Coding:
-     *       this alpha tagging shall use either
-     *      -    the SMS default 7 bit coded alphabet as defined in
-     *          TS 23.038 [12] with bit 8 set to 0. The alpha identifier
-     *          shall be left justified. Unused bytes shall be set to 'FF'; or
-     *      -    one of the UCS2 coded options as defined in annex B.
-     *
-     * Annex B from TS 11.11 V8.13.0:
-     *      1)  If the first octet in the alpha string is '80', then the
-     *          remaining octets are 16 bit UCS2 characters ...
-     *      2)  if the first octet in the alpha string is '81', then the
-     *          second octet contains a value indicating the number of
-     *          characters in the string, and the third octet contains an
-     *          8 bit number which defines bits 15 to 8 of a 16 bit
-     *          base pointer, where bit 16 is set to zero and bits 7 to 1
-     *          are also set to zero.  These sixteen bits constitute a
-     *          base pointer to a "half page" in the UCS2 code space, to be
-     *          used with some or all of the remaining octets in the string.
-     *          The fourth and subsequent octets contain codings as follows:
-     *          If bit 8 of the octet is set to zero, the remaining 7 bits
-     *          of the octet contain a GSM Default Alphabet character,
-     *          whereas if bit 8 of the octet is set to one, then the
-     *          remaining seven bits are an offset value added to the
-     *          16 bit base pointer defined earlier...
-     *      3)  If the first octet of the alpha string is set to '82', then
-     *          the second octet contains a value indicating the number of
-     *          characters in the string, and the third and fourth octets
-     *          contain a 16 bit number which defines the complete 16 bit
-     *          base pointer to a "half page" in the UCS2 code space...
-     */
-    public static String
-    adnStringFieldToString(byte[] data, int offset, int length) {
-        if (length == 0) {
-            return "";
-        }
-        if (length >= 1) {
-            if (data[offset] == (byte) 0x80) {
-                int ucslen = (length - 1) / 2;
-                String ret = null;
-
-                try {
-                    ret = new String(data, offset + 1, ucslen * 2, "utf-16be");
-                } catch (UnsupportedEncodingException ex) {
-                    Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException",
-                          ex);
-                }
-
-                if (ret != null) {
-                    // trim off trailing FFFF characters
-
-                    ucslen = ret.length();
-                    while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF')
-                        ucslen--;
-
-                    return ret.substring(0, ucslen);
-                }
-            }
-        }
-
-        boolean isucs2 = false;
-        char base = '\0';
-        int len = 0;
-
-        if (length >= 3 && data[offset] == (byte) 0x81) {
-            len = data[offset + 1] & 0xFF;
-            if (len > length - 3)
-                len = length - 3;
-
-            base = (char) ((data[offset + 2] & 0xFF) << 7);
-            offset += 3;
-            isucs2 = true;
-        } else if (length >= 4 && data[offset] == (byte) 0x82) {
-            len = data[offset + 1] & 0xFF;
-            if (len > length - 4)
-                len = length - 4;
-
-            base = (char) (((data[offset + 2] & 0xFF) << 8) |
-                            (data[offset + 3] & 0xFF));
-            offset += 4;
-            isucs2 = true;
-        }
-
-        if (isucs2) {
-            StringBuilder ret = new StringBuilder();
-
-            while (len > 0) {
-                // UCS2 subset case
-
-                if (data[offset] < 0) {
-                    ret.append((char) (base + (data[offset] & 0x7F)));
-                    offset++;
-                    len--;
-                }
-
-                // GSM character set case
-
-                int count = 0;
-                while (count < len && data[offset + count] >= 0)
-                    count++;
-
-                ret.append(GsmAlphabet.gsm8BitUnpackedToString(data,
-                           offset, count));
-
-                offset += count;
-                len -= count;
-            }
-
-            return ret.toString();
-        }
-
-        Resources resource = Resources.getSystem();
-        String defaultCharset = "";
-        try {
-            defaultCharset =
-                    resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset);
-        } catch (NotFoundException e) {
-            // Ignore Exception and defaultCharset is set to a empty string.
-        }
-        return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
-    }
-
-    static int
-    hexCharToInt(char c) {
-        if (c >= '0' && c <= '9') return (c - '0');
-        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
-        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
-
-        throw new RuntimeException ("invalid hex char '" + c + "'");
-    }
-
-    /**
-     * Converts a hex String to a byte array.
-     *
-     * @param s A string of hexadecimal characters, must be an even number of
-     *          chars long
-     *
-     * @return byte array representation
-     *
-     * @throws RuntimeException on invalid format
-     */
-    public static byte[]
-    hexStringToBytes(String s) {
-        byte[] ret;
-
-        if (s == null) return null;
-
-        int sz = s.length();
-
-        ret = new byte[sz/2];
-
-        for (int i=0 ; i <sz ; i+=2) {
-            ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
-                                | hexCharToInt(s.charAt(i+1)));
-        }
-
-        return ret;
-    }
-
-
-    /**
-     * Converts a byte array into a String of hexadecimal characters.
-     *
-     * @param bytes an array of bytes
-     *
-     * @return hex string representation of bytes array
-     */
-    public static String
-    bytesToHexString(byte[] bytes) {
-        if (bytes == null) return null;
-
-        StringBuilder ret = new StringBuilder(2*bytes.length);
-
-        for (int i = 0 ; i < bytes.length ; i++) {
-            int b;
-
-            b = 0x0f & (bytes[i] >> 4);
-
-            ret.append("0123456789abcdef".charAt(b));
-
-            b = 0x0f & bytes[i];
-
-            ret.append("0123456789abcdef".charAt(b));
-        }
-
-        return ret.toString();
-    }
-
-
-    /**
-     * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string
-     * "offset" points to "octet 3", the coding scheme byte
-     * empty string returned on decode error
-     */
-    public static String
-    networkNameToString(byte[] data, int offset, int length) {
-        String ret;
-
-        if ((data[offset] & 0x80) != 0x80 || length < 1) {
-            return "";
-        }
-
-        switch ((data[offset] >>> 4) & 0x7) {
-            case 0:
-                // SMS character set
-                int countSeptets;
-                int unusedBits = data[offset] & 7;
-                countSeptets = (((length - 1) * 8) - unusedBits) / 7 ;
-                ret =  GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets);
-            break;
-            case 1:
-                // UCS2
-                try {
-                    ret = new String(data,
-                            offset + 1, length - 1, "utf-16");
-                } catch (UnsupportedEncodingException ex) {
-                    ret = "";
-                    Rlog.e(LOG_TAG,"implausible UnsupportedEncodingException", ex);
-                }
-            break;
-
-            // unsupported encoding
-            default:
-                ret = "";
-            break;
-        }
-
-        // "Add CI"
-        // "The MS should add the letters for the Country's Initials and
-        //  a separator (e.g. a space) to the text string"
-
-        if ((data[offset] & 0x40) != 0) {
-            // FIXME(mkf) add country initials here
-
-        }
-
-        return ret;
-    }
-
-    /**
-     * Convert a TS 131.102 image instance of code scheme '11' into Bitmap
-     * @param data The raw data
-     * @param length The length of image body
-     * @return The bitmap
-     */
-    public static Bitmap parseToBnW(byte[] data, int length){
-        int valueIndex = 0;
-        int width = data[valueIndex++] & 0xFF;
-        int height = data[valueIndex++] & 0xFF;
-        int numOfPixels = width*height;
-
-        int[] pixels = new int[numOfPixels];
-
-        int pixelIndex = 0;
-        int bitIndex = 7;
-        byte currentByte = 0x00;
-        while (pixelIndex < numOfPixels) {
-            // reassign data and index for every byte (8 bits).
-            if (pixelIndex % 8 == 0) {
-                currentByte = data[valueIndex++];
-                bitIndex = 7;
-            }
-            pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01);
-        }
-
-        if (pixelIndex != numOfPixels) {
-            Rlog.e(LOG_TAG, "parse end and size error");
-        }
-        return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
-    }
-
-    private static int bitToRGB(int bit){
-        if(bit == 1){
-            return Color.WHITE;
-        } else {
-            return Color.BLACK;
-        }
-    }
-
-    /**
-     * a TS 131.102 image instance of code scheme '11' into color Bitmap
-     *
-     * @param data The raw data
-     * @param length the length of image body
-     * @param transparency with or without transparency
-     * @return The color bitmap
-     */
-    public static Bitmap parseToRGB(byte[] data, int length,
-            boolean transparency) {
-        int valueIndex = 0;
-        int width = data[valueIndex++] & 0xFF;
-        int height = data[valueIndex++] & 0xFF;
-        int bits = data[valueIndex++] & 0xFF;
-        int colorNumber = data[valueIndex++] & 0xFF;
-        int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
-                | (data[valueIndex++] & 0xFF);
-
-        int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
-        if (true == transparency) {
-            colorIndexArray[colorNumber - 1] = Color.TRANSPARENT;
-        }
-
-        int[] resultArray = null;
-        if (0 == (8 % bits)) {
-            resultArray = mapTo2OrderBitColor(data, valueIndex,
-                    (width * height), colorIndexArray, bits);
-        } else {
-            resultArray = mapToNon2OrderBitColor(data, valueIndex,
-                    (width * height), colorIndexArray, bits);
-        }
-
-        return Bitmap.createBitmap(resultArray, width, height,
-                Bitmap.Config.RGB_565);
-    }
-
-    private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex,
-            int length, int[] colorArray, int bits) {
-        if (0 != (8 % bits)) {
-            Rlog.e(LOG_TAG, "not event number of color");
-            return mapToNon2OrderBitColor(data, valueIndex, length, colorArray,
-                    bits);
-        }
-
-        int mask = 0x01;
-        switch (bits) {
-        case 1:
-            mask = 0x01;
-            break;
-        case 2:
-            mask = 0x03;
-            break;
-        case 4:
-            mask = 0x0F;
-            break;
-        case 8:
-            mask = 0xFF;
-            break;
-        }
-
-        int[] resultArray = new int[length];
-        int resultIndex = 0;
-        int run = 8 / bits;
-        while (resultIndex < length) {
-            byte tempByte = data[valueIndex++];
-            for (int runIndex = 0; runIndex < run; ++runIndex) {
-                int offset = run - runIndex - 1;
-                resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits))
-                        & mask];
-            }
-        }
-        return resultArray;
-    }
-
-    private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex,
-            int length, int[] colorArray, int bits) {
-        if (0 == (8 % bits)) {
-            Rlog.e(LOG_TAG, "not odd number of color");
-            return mapTo2OrderBitColor(data, valueIndex, length, colorArray,
-                    bits);
-        }
-
-        int[] resultArray = new int[length];
-        // TODO fix me:
-        return resultArray;
-    }
-
-    private static int[] getCLUT(byte[] rawData, int offset, int number) {
-        if (null == rawData) {
-            return null;
-        }
-
-        int[] result = new int[number];
-        int endIndex = offset + (number * 3); // 1 color use 3 bytes
-        int valueIndex = offset;
-        int colorIndex = 0;
-        int alpha = 0xff << 24;
-        do {
-            result[colorIndex++] = alpha
-                    | ((rawData[valueIndex++] & 0xFF) << 16)
-                    | ((rawData[valueIndex++] & 0xFF) << 8)
-                    | ((rawData[valueIndex++] & 0xFF));
-        } while (valueIndex < endIndex);
-        return result;
-    }
-}
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
index 8248c08..acd4e19 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
@@ -43,6 +43,8 @@
     @Mock
     private IImsFeatureStatusCallback mTestStatusCallback;
     @Mock
+    private IImsFeatureStatusCallback mTestStatusCallback2;
+    @Mock
     private ImsFeature.INotifyFeatureRemoved mTestRemovedCallback;
 
     private class TestImsFeature extends ImsFeature {
@@ -73,19 +75,23 @@
     @Test
     @SmallTest
     public void testSetCallbackAndNotify() throws Exception {
-        mTestImsService.setImsFeatureStatusCallback(mTestStatusCallback);
+        mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback);
+        mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback2);
 
         verify(mTestStatusCallback).notifyImsFeatureStatus(eq(ImsFeature.STATE_NOT_AVAILABLE));
+        verify(mTestStatusCallback2).notifyImsFeatureStatus(eq(ImsFeature.STATE_NOT_AVAILABLE));
     }
 
     @Test
     @SmallTest
     public void testSetFeatureAndCheckCallback() throws Exception {
-        mTestImsService.setImsFeatureStatusCallback(mTestStatusCallback);
+        mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback);
+        mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback2);
 
         mTestImsService.testSetFeatureState(ImsFeature.STATE_READY);
 
         verify(mTestStatusCallback).notifyImsFeatureStatus(eq(ImsFeature.STATE_READY));
+        verify(mTestStatusCallback2).notifyImsFeatureStatus(eq(ImsFeature.STATE_READY));
         assertEquals(ImsFeature.STATE_READY, mTestImsService.getFeatureState());
     }
 
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
index cdb95a3..dab0237 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
@@ -98,7 +98,7 @@
                 mTestImsService.getImsFeatureFromType(features, ImsFeature.MMTEL));
         // Verify that upon creating a feature, we assign the callback and get the set feature state
         // when querying it.
-        verify(mTestImsService.mSpyMMTelFeature).setImsFeatureStatusCallback(eq(mTestCallback));
+        verify(mTestImsService.mSpyMMTelFeature).addImsFeatureStatusCallback(eq(mTestCallback));
         assertEquals(ImsFeature.STATE_READY, mTestImsServiceBinder.getFeatureStatus(TEST_SLOT_0,
                 ImsFeature.MMTEL));
     }
@@ -108,10 +108,10 @@
     public void testRemoveMMTelFeature() throws RemoteException {
         mTestImsServiceBinder.createImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
 
-        mTestImsServiceBinder.removeImsFeature(TEST_SLOT_0, ImsFeature.MMTEL);
+        mTestImsServiceBinder.removeImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
 
         verify(mTestImsService.mSpyMMTelFeature).notifyFeatureRemoved(eq(0));
-        verify(mTestImsService.mSpyMMTelFeature).setImsFeatureStatusCallback(null);
+        verify(mTestImsService.mSpyMMTelFeature).removeImsFeatureStatusCallback(mTestCallback);
         SparseArray<ImsFeature> features = mTestImsService.getImsFeatureMap(TEST_SLOT_0);
         assertNull(mTestImsService.getImsFeatureFromType(features, ImsFeature.MMTEL));
     }
@@ -184,14 +184,11 @@
         mTestImsService.mSpyMMTelFeature.sendSetFeatureState(ImsFeature.STATE_READY);
 
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockContext, times(2)).sendBroadcast(intentCaptor.capture());
+        verify(mMockContext).sendBroadcast(intentCaptor.capture());
         try {
-            // IMS_SERVICE_DOWN is always sent when createImsFeature completes
-            assertNotNull(intentCaptor.getAllValues().get(0));
-            verifyServiceDownSent(intentCaptor.getAllValues().get(0));
             // Verify IMS_SERVICE_UP is sent
-            assertNotNull(intentCaptor.getAllValues().get(1));
-            verifyServiceUpSent(intentCaptor.getAllValues().get(1));
+            assertNotNull(intentCaptor.getValue());
+            verifyServiceUpSent(intentCaptor.getValue());
         } catch (IndexOutOfBoundsException e) {
             fail("Did not receive all intents");
         }
@@ -209,37 +206,16 @@
         mTestImsService.mSpyMMTelFeature.sendSetFeatureState(ImsFeature.STATE_INITIALIZING);
 
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockContext, times(2)).sendBroadcast(intentCaptor.capture());
+        verify(mMockContext).sendBroadcast(intentCaptor.capture());
         try {
-            // IMS_SERVICE_DOWN is always sent when createImsFeature completes.
-            assertNotNull(intentCaptor.getAllValues().get(0));
-            verifyServiceDownSent(intentCaptor.getAllValues().get(0));
             // IMS_SERVICE_DOWN is sent when the service is STATE_INITIALIZING.
-            assertNotNull(intentCaptor.getAllValues().get(1));
-            verifyServiceDownSent(intentCaptor.getAllValues().get(1));
+            assertNotNull(intentCaptor.getValue());
+            verifyServiceDownSent(intentCaptor.getValue());
         } catch (IndexOutOfBoundsException e) {
             fail("Did not receive all intents");
         }
     }
 
-    /**
-     * Tests that the new ImsService still sends the IMS_SERVICE_DOWN broadcast when the feature is
-     * set to not available.
-     */
-    @Test
-    @SmallTest
-    public void testImsServiceDownSentCompatNotAvailable() throws RemoteException {
-        mTestImsServiceBinder.createImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
-
-        // The ImsService will send the STATE_NOT_AVAILABLE status as soon as the feature is
-        // created.
-
-        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockContext).sendBroadcast(intentCaptor.capture());
-        assertNotNull(intentCaptor.getValue());
-        verifyServiceDownSent(intentCaptor.getValue());
-    }
-
     private void verifyServiceDownSent(Intent testIntent) {
         assertEquals(ImsManager.ACTION_IMS_SERVICE_DOWN, testIntent.getAction());
         assertEquals(TEST_SLOT_0, testIntent.getIntExtra(ImsManager.EXTRA_PHONE_ID, -1));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
index a255f26..8231d06 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
@@ -122,7 +122,7 @@
     @After
     public void tearDown() throws Exception {
         CallManager.getInstance().unregisterPhone(mPhone);
-        mCallManagerHandlerThread.quitSafely();
+        mCallManagerHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
index bac3dd1..7b6c2b7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
@@ -15,10 +15,12 @@
  */
 package com.android.internal.telephony;
 
+import static org.junit.Assert.assertEquals;
+
 import android.test.suitebuilder.annotation.SmallTest;
+
 import org.junit.After;
 import org.junit.Test;
-import static org.junit.Assert.assertEquals;
 
 public class CallStateExceptionTest {
     private CallStateException mCallStateException;
@@ -39,9 +41,9 @@
     @Test
     @SmallTest
     public void testCallStateExceptionWithErrCode() {
-        mCallStateException = new CallStateException(mCallStateException.ERROR_DISCONNECTED,
+        mCallStateException = new CallStateException(mCallStateException.ERROR_OUT_OF_SERVICE,
                                                      "sanity test with err code");
         assertEquals("sanity test with err code", mCallStateException.getMessage());
-        assertEquals(mCallStateException.ERROR_DISCONNECTED, mCallStateException.getError());
+        assertEquals(mCallStateException.ERROR_OUT_OF_SERVICE, mCallStateException.getError());
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java
new file mode 100644
index 0000000..711c84e
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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 com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+public class CarrierActionAgentTest extends TelephonyTest {
+    private CarrierActionAgent mCarrierActionAgentUT;
+    private FakeContentResolver mFakeContentResolver;
+    private FakeContentProvider mFakeContentProvider;
+    private static int DATA_CARRIER_ACTION_EVENT = 0;
+    private static int RADIO_CARRIER_ACTION_EVENT = 1;
+    private CarrierActionAgentHandler mCarrierActionAgentHandler;
+    @Mock
+    private Handler mDataActionHandler;
+    @Mock
+    private Handler mRadioActionHandler;
+
+    private class FakeContentResolver extends MockContentResolver {
+        @Override
+        public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+            super.notifyChange(uri, observer, syncToNetwork);
+            logd("onChanged(uri=" + uri + ")" + observer);
+            if (observer != null) {
+                observer.dispatchChange(false, uri);
+            } else {
+                mCarrierActionAgentUT.getContentObserver().dispatchChange(false, uri);
+            }
+        }
+    }
+
+    private class FakeContentProvider extends MockContentProvider {
+        private int mExpectedValue;
+        public void simulateChange(Uri uri) {
+            mFakeContentResolver.notifyChange(uri, null);
+        }
+        @Override
+        public Bundle call(String method, String request, Bundle args) {
+            Bundle result = new Bundle();
+            if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
+                result.putString(Settings.NameValueTable.VALUE, Integer.toString(mExpectedValue));
+            } else {
+                mExpectedValue = Integer.parseInt(args.getString(Settings.NameValueTable.VALUE));
+            }
+            return result;
+        }
+    }
+
+    private class CarrierActionAgentHandler extends HandlerThread {
+
+        private CarrierActionAgentHandler(String name) {
+            super(name);
+        }
+
+        @Override
+        public void onLooperPrepared() {
+            mCarrierActionAgentUT = new CarrierActionAgent(mPhone);
+            mCarrierActionAgentUT.registerForCarrierAction(
+                    CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, mDataActionHandler,
+                    DATA_CARRIER_ACTION_EVENT, null, false);
+            mCarrierActionAgentUT.registerForCarrierAction(
+                    CarrierActionAgent.CARRIER_ACTION_SET_RADIO_ENABLED, mRadioActionHandler,
+                    RADIO_CARRIER_ACTION_EVENT, null, false);
+            setReady(true);
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        logd("CarrierActionAgentTest +Setup!");
+        super.setUp(getClass().getSimpleName());
+        mFakeContentResolver = new FakeContentResolver();
+        mFakeContentProvider = new FakeContentProvider();
+        mFakeContentResolver.addProvider(Settings.AUTHORITY, mFakeContentProvider);
+        doReturn(mFakeContentResolver).when(mContext).getContentResolver();
+        mCarrierActionAgentHandler = new CarrierActionAgentHandler(getClass().getSimpleName());
+        mCarrierActionAgentHandler.start();
+        waitUntilReady();
+        logd("CarrierActionAgentTest -Setup!");
+    }
+
+    @Test
+    @SmallTest
+    public void testCarrierActionResetOnAPM() {
+        Settings.Global.putInt(mFakeContentResolver, Settings.Global.AIRPLANE_MODE_ON, 1);
+        mFakeContentProvider.simulateChange(
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON));
+        waitForMs(200);
+        ArgumentCaptor<Message> message = ArgumentCaptor.forClass(Message.class);
+
+        verify(mDataActionHandler).sendMessageAtTime(message.capture(), anyLong());
+        assertEquals(DATA_CARRIER_ACTION_EVENT, message.getValue().what);
+
+        verify(mRadioActionHandler).sendMessageAtTime(message.capture(), anyLong());
+        assertEquals(RADIO_CARRIER_ACTION_EVENT, message.getValue().what);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        Settings.Global.putInt(mFakeContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
+        mCarrierActionAgentHandler.quit();
+        super.tearDown();
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
index 7e9b7db..6635c08 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServicesSmsFilterTest.java
@@ -73,7 +73,7 @@
         super.setUp(getClass().getSimpleName());
         mCarrierServicesSmsFilterUT = new CarrierServicesSmsFilter(
                 mContext, mPhone, new byte[][]{SMS_PDU},
-                0, null, mFilterCallback, getClass().getSimpleName());
+                0, "3gpp", mFilterCallback, getClass().getSimpleName());
     }
 
     @After
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index 3f6cd4a..5299b3f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -266,11 +266,11 @@
 
     @Test @SmallTest
     public void testNotifyOtaspChanged() throws Exception {
-        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, ServiceStateTracker.OTASP_NEEDED);
-        verify(mTelephonyRegisteryMock).notifyOtaspChanged(ServiceStateTracker.OTASP_NEEDED);
+        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_NEEDED);
+        verify(mTelephonyRegisteryMock).notifyOtaspChanged(TelephonyManager.OTASP_NEEDED);
 
-        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, ServiceStateTracker.OTASP_UNKNOWN);
-        verify(mTelephonyRegisteryMock).notifyOtaspChanged(ServiceStateTracker.OTASP_UNKNOWN);
+        mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_UNKNOWN);
+        verify(mTelephonyRegisteryMock).notifyOtaspChanged(TelephonyManager.OTASP_UNKNOWN);
     }
 
     @Test @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 0745092..5d89d08 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -71,7 +71,7 @@
     @After
     public void tearDown() throws Exception {
         mDeviceStateMonitor = null;
-        mDeviceStateMonitorTestHandler.quitSafely();
+        mDeviceStateMonitorTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
index 077610b..bc43aae 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
@@ -85,7 +85,7 @@
     @After
     public void tearDown() throws Exception {
         mCTUT = null;
-        mGsmCdmaCTHandlerThread.quitSafely();
+        mGsmCdmaCTHandlerThread.quit();
         super.tearDown();
     }
 
@@ -150,6 +150,7 @@
         assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
     }
 
+    @FlakyTest
     @Test
     @MediumTest
     public void testMOCallDialPickUpHangup() {
@@ -282,6 +283,7 @@
 
     }
 
+    @FlakyTest
     @Test
     @MediumTest
     public void testMOCallSwitchHangupForeGround() {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 39fdf13..6301d54 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -132,7 +132,7 @@
     public void tearDown() throws Exception {
         mPhoneUT.removeCallbacksAndMessages(null);
         mPhoneUT = null;
-        mGsmCdmaPhoneTestHandler.quitSafely();
+        mGsmCdmaPhoneTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
index 24c1283..be829ef 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
@@ -95,7 +95,7 @@
     @After
     public void tearDown() throws Exception {
         mImsSmsDispatcher = null;
-        mImsSmsDispatcherTestHandler.quitSafely();
+        mImsSmsDispatcherTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
index b63dc71..f49fffd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
@@ -18,7 +18,7 @@
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.telephony.NeighboringCellInfo;
-import android.test. suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
 import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
new file mode 100644
index 0000000..fe75088
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.NetworkScanRequest;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.EutranBands;
+import android.telephony.RadioNetworkConstants.GeranBands;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
+
+import org.junit.Test;
+
+/** Unit tests for {@link NetworkScanRequest}. */
+
+public class NetworkScanRequestTest {
+
+    @Test
+    @SmallTest
+    public void testParcel() {
+        int ranGsm = RadioAccessNetworks.GERAN;
+        int[] gsmBands = {GeranBands.BAND_T380, GeranBands.BAND_T410};
+        int[] gsmChannels = {1, 2, 3, 4};
+        RadioAccessSpecifier gsm = new RadioAccessSpecifier(ranGsm, gsmBands, gsmChannels);
+        int ranLte = RadioAccessNetworks.EUTRAN;
+        int[] lteBands = {EutranBands.BAND_10, EutranBands.BAND_11};
+        int[] lteChannels = {5, 6, 7, 8};
+        RadioAccessSpecifier lte = new RadioAccessSpecifier(ranLte, lteBands, lteChannels);
+        RadioAccessSpecifier[] ras = {gsm, lte};
+        NetworkScanRequest nsq = new NetworkScanRequest(NetworkScanRequest.SCAN_TYPE_ONE_SHOT, ras);
+
+        Parcel p = Parcel.obtain();
+        nsq.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        NetworkScanRequest newNsq = NetworkScanRequest.CREATOR.createFromParcel(p);
+        assertEquals(nsq, newNsq);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
new file mode 100644
index 0000000..f149211
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+/** Unit tests for {@link NetworkScanResult}. */
+
+public class NetworkScanResultTest {
+
+    @Test
+    @SmallTest
+    public void testParcel() {
+        ArrayList<CellInfo> infos = new ArrayList<CellInfo>();
+
+        CellIdentityGsm cig = new CellIdentityGsm(310, 310, 1, 2, 3, 4);
+        CellSignalStrengthGsm cssg = new CellSignalStrengthGsm();
+        cssg.initialize(5, 6, 7);
+        CellInfoGsm gsm = new CellInfoGsm();
+        gsm.setRegistered(true);
+        gsm.setTimeStampType(8);
+        gsm.setTimeStamp(9);
+        gsm.setCellIdentity(cig);
+        gsm.setCellSignalStrength(cssg);
+        infos.add(gsm);
+
+        CellIdentityLte cil = new CellIdentityLte(320, 320, 11, 12, 13, 14);
+        CellSignalStrengthLte cssl = new CellSignalStrengthLte();
+        cssl.initialize(15, 16, 17, 18, 19, 20);
+        CellInfoLte lte = new CellInfoLte();
+        lte.setRegistered(false);
+        lte.setTimeStampType(21);
+        lte.setTimeStamp(22);
+        lte.setCellIdentity(cil);
+        lte.setCellSignalStrength(cssl);
+        infos.add(lte);
+
+        NetworkScanResult nsr = new NetworkScanResult(0, 0, infos);
+
+        Parcel p = Parcel.obtain();
+        nsr.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        NetworkScanResult newNsr = NetworkScanResult.CREATOR.createFromParcel(p);
+        assertEquals(nsr, newNsr);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
index 4a17199..fdda80f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
@@ -60,7 +60,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mPhoneStateListenerHandler.quitSafely();
+        mPhoneStateListenerHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index e68262f..b5ec320 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -388,6 +388,12 @@
 //        }
 //        if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
 //        if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
+
+        for (int i = 0; i < numPhones; i++) {
+            commandsInterfaces[i].dispose();
+        }
+
+        connectivityServiceMock.die();
         testHandler.die();
         handlerThread.quit();
     }
@@ -468,6 +474,11 @@
         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
         if (commandsInterfaces[1].isDataAllowed() == false) fail("data not allowed");
 
+        for (int i = 0; i < numPhones; i++) {
+            commandsInterfaces[i].dispose();
+        }
+
+        connectivityServiceMock.die();
         testHandler.die();
         handlerThread.quit();
     }
@@ -537,6 +548,11 @@
         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
 
+        for (int i = 0; i < numPhones; i++) {
+            commandsInterfaces[i].dispose();
+        }
+
+        connectivityServiceMock.die();
         testHandler.die();
         handlerThread.quit();
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
new file mode 100644
index 0000000..653c357
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.GeranBands;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
+
+import org.junit.Test;
+
+/** Unit tests for {@link RadioAccessSpecifier}. */
+
+public class RadioAccessSpecifierTest {
+
+    @Test
+    @SmallTest
+    public void testParcel() {
+        int ranGsm = RadioAccessNetworks.GERAN;
+        int[] gsmBands = {GeranBands.BAND_T380, GeranBands.BAND_T410};
+        int[] gsmChannels = {1, 2, 3, 4};
+        RadioAccessSpecifier ras = new RadioAccessSpecifier(ranGsm, gsmBands, gsmChannels);
+
+        Parcel p = Parcel.obtain();
+        ras.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        RadioAccessSpecifier newRas = RadioAccessSpecifier.CREATOR.createFromParcel(p);
+        assertEquals(ras, newRas);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 3be623c..c8d459a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.nullable;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.spy;
@@ -70,6 +71,7 @@
 import org.mockito.Mock;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 
 public class ServiceStateTrackerTest extends TelephonyTest {
@@ -88,13 +90,15 @@
 
     private static final int EVENT_REGISTERED_TO_NETWORK = 1;
     private static final int EVENT_SUBSCRIPTION_INFO_READY = 2;
-    private static final int EVENT_ROAMING_ON = 3;
-    private static final int EVENT_ROAMING_OFF = 4;
+    private static final int EVENT_DATA_ROAMING_ON = 3;
+    private static final int EVENT_DATA_ROAMING_OFF = 4;
     private static final int EVENT_DATA_CONNECTION_ATTACHED = 5;
     private static final int EVENT_DATA_CONNECTION_DETACHED = 6;
     private static final int EVENT_DATA_RAT_CHANGED = 7;
     private static final int EVENT_PS_RESTRICT_ENABLED = 8;
     private static final int EVENT_PS_RESTRICT_DISABLED = 9;
+    private static final int EVENT_VOICE_ROAMING_ON = 10;
+    private static final int EVENT_VOICE_ROAMING_OFF = 11;
 
     private class ServiceStateTrackerTestHandler extends HandlerThread {
 
@@ -146,7 +150,7 @@
     @After
     public void tearDown() throws Exception {
         sst = null;
-        mSSTTestHandler.quitSafely();
+        mSSTTestHandler.quit();
         super.tearDown();
     }
 
@@ -326,7 +330,6 @@
         assertFalse(sst.isImsRegistered());
     }
 
-    @FlakyTest
     @Test
     @MediumTest
     public void testSignalStrength() {
@@ -360,14 +363,15 @@
         sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
 
         mSimulatedCommands.notifySignalStrength();
-        waitForMs(200);
+        waitForMs(300);
         assertEquals(sst.getSignalStrength(), ss);
         assertEquals(sst.getSignalStrength().isGsm(), true);
 
         // notify signal strength again, but this time data RAT is not LTE
+        sst.mSS.setRilVoiceRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
         sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
         mSimulatedCommands.notifySignalStrength();
-        waitForMs(200);
+        waitForMs(300);
         assertEquals(sst.getSignalStrength(), ss);
         assertEquals(sst.getSignalStrength().isGsm(), false);
     }
@@ -439,7 +443,7 @@
     @Test
     @MediumTest
     public void testRegAndUnregForVoiceRoamingOn() throws Exception {
-        sst.registerForVoiceRoamingOn(mTestHandler, EVENT_ROAMING_ON, null);
+        sst.registerForVoiceRoamingOn(mTestHandler, EVENT_DATA_ROAMING_ON, null);
 
         // Enable roaming and trigger events to notify handler registered
         doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -452,7 +456,7 @@
         // verify if registered handler has message posted to it
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
-        assertEquals(EVENT_ROAMING_ON, messageArgumentCaptor.getValue().what);
+        assertEquals(EVENT_DATA_ROAMING_ON, messageArgumentCaptor.getValue().what);
 
         // Disable roaming
         mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_HOME);
@@ -486,7 +490,7 @@
 
         waitForMs(100);
 
-        sst.registerForVoiceRoamingOff(mTestHandler, EVENT_ROAMING_OFF, null);
+        sst.registerForVoiceRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null);
 
         // Disable roaming
         doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -499,7 +503,7 @@
         // verify if registered handler has message posted to it
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
-        assertEquals(EVENT_ROAMING_OFF, messageArgumentCaptor.getValue().what);
+        assertEquals(EVENT_DATA_ROAMING_OFF, messageArgumentCaptor.getValue().what);
 
         // Enable roaming
         mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
@@ -525,7 +529,7 @@
     @Test
     @MediumTest
     public void testRegAndUnregForDataRoamingOn() throws Exception {
-        sst.registerForDataRoamingOn(mTestHandler, EVENT_ROAMING_ON, null);
+        sst.registerForDataRoamingOn(mTestHandler, EVENT_DATA_ROAMING_ON, null);
 
         // Enable roaming and trigger events to notify handler registered
         doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -538,7 +542,7 @@
         // verify if registered handler has message posted to it
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
-        assertEquals(EVENT_ROAMING_ON, messageArgumentCaptor.getValue().what);
+        assertEquals(EVENT_DATA_ROAMING_ON, messageArgumentCaptor.getValue().what);
 
         // Disable roaming
         mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_HOME);
@@ -572,7 +576,7 @@
 
         waitForMs(100);
 
-        sst.registerForDataRoamingOff(mTestHandler, EVENT_ROAMING_OFF, null);
+        sst.registerForDataRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null);
 
         // Disable roaming
         doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -585,7 +589,7 @@
         // verify if registered handler has message posted to it
         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
-        assertEquals(EVENT_ROAMING_OFF, messageArgumentCaptor.getValue().what);
+        assertEquals(EVENT_DATA_ROAMING_OFF, messageArgumentCaptor.getValue().what);
 
         // Enable roaming
         mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
@@ -978,6 +982,40 @@
     }
 
     @Test
+    @MediumTest
+    public void testRoamingPhoneTypeSwitch() {
+        // Enable roaming
+        doReturn(true).when(mPhone).isPhoneTypeGsm();
+
+        mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
+        mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
+        mSimulatedCommands.notifyNetworkStateChanged();
+
+        waitForMs(200);
+
+        sst.registerForDataRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null);
+        sst.registerForVoiceRoamingOff(mTestHandler, EVENT_VOICE_ROAMING_OFF, null);
+        sst.registerForDataConnectionDetached(mTestHandler, EVENT_DATA_CONNECTION_DETACHED, null);
+
+        // Call functions which would trigger posting of message on test handler
+        doReturn(false).when(mPhone).isPhoneTypeGsm();
+        sst.updatePhoneType();
+
+        // verify if registered handler has message posted to it
+        ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+        verify(mTestHandler, atLeast(3)).sendMessageAtTime(
+                messageArgumentCaptor.capture(), anyLong());
+        HashSet<Integer> messageSet = new HashSet<>();
+        for (Message m : messageArgumentCaptor.getAllValues()) {
+            messageSet.add(m.what);
+        }
+
+        assertTrue(messageSet.contains(EVENT_DATA_ROAMING_OFF));
+        assertTrue(messageSet.contains(EVENT_VOICE_ROAMING_OFF));
+        assertTrue(messageSet.contains(EVENT_DATA_CONNECTION_DETACHED));
+    }
+
+    @Test
     @SmallTest
     public void testGetDesiredPowerState() {
         sst.setRadioPower(true);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimActivationTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SimActivationTrackerTest.java
index 4545b4a..b99736f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimActivationTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimActivationTrackerTest.java
@@ -52,7 +52,7 @@
         // verify activated state is set successfully
         try {
             mSAT.setVoiceActivationState(SIM_ACTIVATION_STATE_ACTIVATED);
-        } catch (InvalidParameterException ex) {
+        } catch (IllegalArgumentException ex) {
             fail("Exception in setVoiceActivationState: " + ex);
         }
 
@@ -65,7 +65,7 @@
             mSAT.setVoiceActivationState(SIM_ACTIVATION_STATE_RESTRICTED);
             fail("Expect exception in setVoiceActivationState with wrong state: "
                     + SIM_ACTIVATION_STATE_RESTRICTED);
-        } catch (InvalidParameterException ex) {
+        } catch (IllegalArgumentException ex) {
             //test pass
         }
         assertEquals(SIM_ACTIVATION_STATE_ACTIVATED, mSAT.getVoiceActivationState());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
index 7c8c15c..cbc56ae 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
@@ -67,7 +67,7 @@
     @After
     public void tearDown() throws Exception {
         mSmsStorageMonitor = null;
-        mSmsStorageMonitorTestHandler.quitSafely();
+        mSmsStorageMonitorTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index 4960e72..ea2f17d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -128,7 +128,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mSubscriptionInfoUpdaterHandlerThread.quitSafely();
+        mSubscriptionInfoUpdaterHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 8c7feff..df4f0ee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -41,6 +41,7 @@
 import android.os.RegistrantList;
 import android.os.ServiceManager;
 import android.provider.BlockedNumberContract;
+import android.provider.Settings;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -80,10 +81,14 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public abstract class TelephonyTest {
     protected static String TAG;
 
+    private static final int MAX_INIT_WAIT_MS = 30000; // 30 seconds
+
     @Mock
     protected GsmCdmaPhone mPhone;
     @Mock
@@ -222,11 +227,14 @@
     }
 
     protected void waitUntilReady() {
-        while (true) {
-            synchronized (mLock) {
-                if (mReady) {
-                    break;
-                }
+        synchronized (mLock) {
+            try {
+                mLock.wait(MAX_INIT_WAIT_MS);
+            } catch (InterruptedException ie) {
+            }
+
+            if (!mReady) {
+                fail("Telephony tests failed to initialize");
             }
         }
     }
@@ -234,6 +242,7 @@
     protected void setReady(boolean ready) {
         synchronized (mLock) {
             mReady = ready;
+            mLock.notifyAll();
         }
     }
 
@@ -351,7 +360,7 @@
         doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory)
                 .makeImsExternalCallTracker(nullable(ImsPhone.class));
         doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory)
-                .makeCarrierActionAgent(nullable(Phone.class));
+                .makeCarrierSignalAgent(nullable(Phone.class));
         doReturn(mCarrierActionAgent).when(mTelephonyComponentFactory)
                 .makeCarrierActionAgent(nullable(Phone.class));
         doReturn(mDeviceStateMonitor).when(mTelephonyComponentFactory)
@@ -433,11 +442,16 @@
         mSST.mSS = mServiceState;
         mServiceManagerMockedServices.put("connectivity_metrics_logger", mConnMetLoggerBinder);
 
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1);
+
         setReady(false);
     }
 
     protected void tearDown() throws Exception {
 
+        mSimulatedCommands.dispose();
+
         SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0);
         sharedPreferences.edit().clear().commit();
 
@@ -476,4 +490,28 @@
         doReturn(mPackageInfo).when(mPackageManager).getPackageInfoAsUser(
                 eq(TAG), anyInt(), anyInt());
     }
+
+    protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
+        final CountDownLatch lock = new CountDownLatch(1);
+        h.post(lock::countDown);
+        while (lock.getCount() > 0) {
+            try {
+                lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+        }
+    }
+
+    protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) {
+        final CountDownLatch lock = new CountDownLatch(1);
+        h.postDelayed(lock::countDown, delayMs);
+        while (lock.getCount() > 0) {
+            try {
+                lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+        }
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
index 8c6b24f..198beab 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
@@ -43,7 +43,7 @@
                 .build();
 
         Mockito.when(telephonyManager
-                .getVisualVoicemailSmsFilterSettings(Mockito.anyString(), Mockito.anyInt()))
+                .getVisualVoicemailSmsFilterSettings(Mockito.anyInt()))
                 .thenReturn(settings);
 
         byte[][] pdus = {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
index 82169d4..a26741f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
@@ -159,7 +159,7 @@
         assertFalse(mCdmaInboundSmsHandler.getWakeLock().isHeld());
         mCdmaInboundSmsHandler = null;
         mContentProvider.shutdown();
-        mCdmaInboundSmsHandlerTestHandler.quitSafely();
+        mCdmaInboundSmsHandlerTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
index 5cd55b6..5833cc6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
@@ -27,6 +27,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.cdma.SmsMessageConverter;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
@@ -121,7 +122,7 @@
         for (byte b : bearerData) {
             msg.bearerData.add(b);
         }
-        SmsMessage message = SmsMessage.newFromRil(msg);
+        SmsMessage message = SmsMessageConverter.newCdmaSmsMessageFromRil(msg);
         return message;
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
index e3ba4ff..a308762 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
@@ -72,7 +72,7 @@
     @After
     public void tearDown() throws Exception {
         mCdmaSmsDispatcher = null;
-        mCdmaSmsDispatcherTestHandler.quitSafely();
+        mCdmaSmsDispatcherTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index 92d8c34..d22fe6f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -16,15 +16,29 @@
 
 package com.android.internal.telephony.dataconnection;
 
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_ALL;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_DEFAULT;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_HIPRI;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_IA;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_MMS;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_SUPL;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyTest;
 
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -33,22 +47,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_ALL;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_DEFAULT;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_HIPRI;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_IA;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_MMS;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_SUPL;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.junit.Assert.assertEquals;
-
-
 public class ApnSettingTest extends TelephonyTest {
 
     private PersistableBundle mBundle;
-    private boolean isRoaming = false;
 
     @Before
     public void setUp() throws Exception {
@@ -61,15 +62,15 @@
         super.tearDown();
     }
 
-    private ApnSetting createApnSetting(String[] apnTypes) {
+    static ApnSetting createApnSetting(String[] apnTypes) {
         return createApnSettingInternal(apnTypes, true);
     }
 
-    private ApnSetting createDisabledApnSetting(String[] apnTypes) {
+    private static ApnSetting createDisabledApnSetting(String[] apnTypes) {
         return createApnSettingInternal(apnTypes, false);
     }
 
-    private ApnSetting createApnSettingInternal(String[] apnTypes, boolean carrierEnabled) {
+    private static ApnSetting createApnSettingInternal(String[] apnTypes, boolean carrierEnabled) {
         return new ApnSetting(
                 2163,                   // id
                 "44010",                // numeric
@@ -229,63 +230,52 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
 
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(1).when(mPhone).getSubId();
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
-                mContext, 1, isRoaming));
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI,
-                mContext, 1, isRoaming));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
 
         // Carrier config settings changes.
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT});
 
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
-                mContext, 1, isRoaming));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
     }
 
     @Test
@@ -293,50 +283,93 @@
     public void testIsRoamingMetered() throws Exception {
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
-        isRoaming = true;
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(1).when(mPhone).getSubId();
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 1, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 1, isRoaming));
+                isMetered(mPhone));
 
         // Carrier config settings changes.
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_FOTA});
 
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
-                mContext, 1, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
-                mContext, 1, isRoaming));
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
-                mContext, 1, isRoaming));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+    }
+
+    @Test
+    @SmallTest
+    public void testIsIwlanMetered() throws Exception {
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+                .getRilDataRadioTechnology();
+        doReturn(1).when(mPhone).getSubId();
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL})
+                .isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS})
+                .isMetered(mPhone));
+
+        // Carrier config settings changes.
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_FOTA});
+
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
     }
 
     @Test
@@ -345,38 +378,35 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
 
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(1).when(mPhone).getSubId();
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 2, isRoaming));
-
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
     }
 
     @Test
@@ -384,56 +414,91 @@
     public void testIsRoamingMeteredAnother() throws Exception {
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
-        isRoaming = true;
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(2).when(mPhone).getSubId();
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_SUPL}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 2, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 2, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
 
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL,
-                mContext, 2, isRoaming));
-        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA,
-                mContext, 2, isRoaming));
-        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI,
-                mContext, 2, isRoaming));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
+    }
 
+    @Test
+    @SmallTest
+    public void testIsIwlanMeteredAnother() throws Exception {
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+                .getRilDataRadioTechnology();
+        doReturn(2).when(mPhone).getSubId();
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS})
+                .isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
+
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+        assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+        assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
     }
 
     @Test
@@ -442,21 +507,22 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{});
 
-        assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 3, isRoaming));
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(3).when(mPhone).getSubId();
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 3, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA}).
-                isMetered(mContext, 3, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS})
+                .isMetered(mPhone));
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 3, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA})
+                .isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
     }
 
     @Test
@@ -464,23 +530,48 @@
     public void testIsRoamingMeteredNothingCharged() throws Exception {
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{});
-        isRoaming = true;
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(3).when(mPhone).getSubId();
 
         assertFalse(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_IMS}).
-                isMetered(mContext, 3, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 3, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA}).
-                isMetered(mContext, 3, isRoaming));
+                isMetered(mPhone));
 
         assertFalse(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 3, isRoaming));
+                isMetered(mPhone));
+    }
+
+    @Test
+    @SmallTest
+    public void testIsIwlanMeteredNothingCharged() throws Exception {
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{});
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+                .getRilDataRadioTechnology();
+        doReturn(3).when(mPhone).getSubId();
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS})
+                .isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA})
+                .isMetered(mPhone));
+
+        assertFalse(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
     }
 
     @Test
@@ -489,21 +580,24 @@
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_ALL});
 
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(4).when(mPhone).getSubId();
+
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
     }
 
@@ -512,23 +606,51 @@
     public void testIsRoamingMeteredNothingFree() throws Exception {
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_ALL});
-        isRoaming = true;
+
+        doReturn(true).when(mServiceState).getDataRoaming();
+        doReturn(4).when(mPhone).getSubId();
 
         assertTrue(createApnSetting(
-                new String[]{PhoneConstants.APN_TYPE_ALL}).
-                isMetered(mContext, 4, isRoaming));
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS})
+                .isMetered(mPhone));
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN})
+                .isMetered(mPhone));
+    }
+
+    @Test
+    @SmallTest
+    public void testIsIwlanMeteredNothingFree() throws Exception {
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_ALL});
+
+        doReturn(false).when(mServiceState).getDataRoaming();
+        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+                .getRilDataRadioTechnology();
+        doReturn(4).when(mPhone).getSubId();
+
+        assertTrue(createApnSetting(
+                new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
 
         assertTrue(createApnSetting(
                 new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}).
-                isMetered(mContext, 4, isRoaming));
+                isMetered(mPhone));
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 21ba173..1e34910 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -164,7 +164,7 @@
         logd("tearDown");
         mDc = null;
         mDcc = null;
-        mDataConnectionTestHandler.quitSafely();
+        mDataConnectionTestHandler.quit();
         super.tearDown();
     }
 
@@ -278,8 +278,8 @@
         return (NetworkInfo) f.get(mDc);
     }
 
-    private NetworkCapabilities getCopyNetworkCapabilities() throws Exception {
-        Method method = DataConnection.class.getDeclaredMethod("getCopyNetworkCapabilities");
+    private NetworkCapabilities getNetworkCapabilities() throws Exception {
+        Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities");
         method.setAccessible(true);
         return (NetworkCapabilities) method.invoke(mDc);
     }
@@ -294,8 +294,8 @@
 
         testConnectEvent();
 
-        assertFalse(getCopyNetworkCapabilities().
-                hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        assertFalse(getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
         assertTrue(getNetworkInfo().isMetered());
     }
 
@@ -310,8 +310,8 @@
 
         testConnectEvent();
 
-        assertTrue(getCopyNetworkCapabilities().
-                hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        assertTrue(getNetworkCapabilities()
+                .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
         assertFalse(getNetworkInfo().isMetered());
     }
 }
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
index f2661f6..d209639 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
@@ -114,7 +114,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mDcControllerTestHandler.quitSafely();
+        mDcControllerTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index c1d0403..3a8cf61 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.dataconnection;
 
 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
@@ -61,6 +62,7 @@
 import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.LocalLog;
 
 import com.android.internal.telephony.DctConstants;
@@ -69,7 +71,6 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.TestApplication;
-import com.android.internal.telephony.dataconnection.DcTracker.DataAllowFailReason;
 
 import org.junit.After;
 import org.junit.Before;
@@ -114,6 +115,12 @@
     NetworkRequest mNetworkRequest;
     @Mock
     SubscriptionInfo mSubscriptionInfo;
+    @Mock
+    ApnContext mApnContext;
+    @Mock
+    ApnSetting mApnSetting;
+    @Mock
+    DcAsyncChannel mDcac;
 
     private DcTracker mDct;
     private DcTrackerTestHandler mDcTrackerTestHandler;
@@ -338,6 +345,8 @@
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mBundle = mContextFixture.getCarrierConfigBundle();
 
+        mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
+
         mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName());
         mDcTrackerTestHandler.start();
         waitUntilReady();
@@ -350,7 +359,7 @@
         logd("DcTrackerTest -tearDown");
         mDct.removeCallbacksAndMessages(null);
         mDct = null;
-        mDcTrackerTestHandler.quitSafely();
+        mDcTrackerTestHandler.quit();
         super.tearDown();
     }
 
@@ -392,7 +401,6 @@
 
         assertEquals(apnSetting, mDct.getActiveApnString(PhoneConstants.APN_TYPE_DEFAULT));
         assertArrayEquals(new String[]{PhoneConstants.APN_TYPE_DEFAULT}, mDct.getActiveApnTypes());
-        assertTrue(mDct.getAnyDataEnabled());
 
         assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
         assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
@@ -406,12 +414,12 @@
         assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress());
     }
 
-    private boolean isDataAllowed(DataAllowFailReason dataAllowFailReasons) {
+    private boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) {
         try {
             Method method = DcTracker.class.getDeclaredMethod("isDataAllowed",
-                    DataAllowFailReason.class);
+                    DataConnectionReasons.class);
             method.setAccessible(true);
-            return (boolean) method.invoke(mDct, dataAllowFailReasons);
+            return (boolean) method.invoke(mDct, dataConnectionReasons);
         } catch (Exception e) {
             fail(e.toString());
             return false;
@@ -427,9 +435,9 @@
 
         mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
 
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-        boolean allowed = isDataAllowed(failureReason);
-        assertFalse(failureReason.getDataAllowFailReason(), allowed);
+        DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+        boolean allowed = isDataAllowed(dataConnectionReasons);
+        assertFalse(dataConnectionReasons.toString(), allowed);
 
         logd("Sending EVENT_RECORDS_LOADED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -465,9 +473,9 @@
         mDct.setEnabled(0, true);
         waitForMs(200);
 
-        failureReason.clearAllReasons();
-        allowed = isDataAllowed(failureReason);
-        assertTrue(failureReason.getDataAllowFailReason(), allowed);
+        dataConnectionReasons = new DataConnectionReasons();
+        allowed = isDataAllowed(dataConnectionReasons);
+        assertTrue(dataConnectionReasons.toString(), allowed);
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
@@ -492,9 +500,9 @@
         // Simulate RIL fails the data call setup
         mSimulatedCommands.setDataCallResponse(false, dcResponse);
 
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-        boolean allowed = isDataAllowed(failureReason);
-        assertFalse(failureReason.getDataAllowFailReason(), allowed);
+        DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+        boolean allowed = isDataAllowed(dataConnectionReasons);
+        assertFalse(dataConnectionReasons.toString(), allowed);
 
         logd("Sending EVENT_RECORDS_LOADED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -531,9 +539,9 @@
         waitForMs(200);
 
 
-        failureReason.clearAllReasons();
-        allowed = isDataAllowed(failureReason);
-        assertTrue(failureReason.getDataAllowFailReason(), allowed);
+        dataConnectionReasons = new DataConnectionReasons();
+        allowed = isDataAllowed(dataConnectionReasons);
+        assertTrue(dataConnectionReasons.toString(), allowed);
 
         ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
         // Verify if RIL command was sent properly.
@@ -626,7 +634,7 @@
         //step 4: only tear down metered data connections.
 
         //set Default and MMS to be metered in the CarrierConfigManager
-        boolean roamingEnabled = mDct.getDataOnRoamingEnabled();
+        boolean roamingEnabled = mDct.getDataRoamingEnabled();
         boolean dataEnabled = mDct.getDataEnabled();
 
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
@@ -655,7 +663,7 @@
         //user is in roaming
         doReturn(true).when(mServiceState).getDataRoaming();
         logd("Sending DISABLE_ROAMING_CMD");
-        mDct.setDataOnRoamingEnabled(false);
+        mDct.setDataRoamingEnabled(false);
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON));
         waitForMs(200);
 
@@ -667,12 +675,11 @@
         assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_IMS));
 
         // reset roaming settings / data enabled settings at end of this test
-        mDct.setDataOnRoamingEnabled(roamingEnabled);
+        mDct.setDataRoamingEnabled(roamingEnabled);
         mDct.setDataEnabled(dataEnabled);
         waitForMs(200);
     }
 
-    @FlakyTest
     @Test
     @MediumTest
     public void testDataCallOnUserDisableRoaming() throws Exception {
@@ -680,18 +687,21 @@
         //step 2: user toggled data settings on
         //step 3: only non-metered data call is established
 
-        boolean roamingEnabled = mDct.getDataOnRoamingEnabled();
+        boolean roamingEnabled = mDct.getDataRoamingEnabled();
         boolean dataEnabled = mDct.getDataEnabled();
+        doReturn(true).when(mServiceState).getDataRoaming();
 
         //set Default and MMS to be metered in the CarrierConfigManager
         mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
                 new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
         mDct.setEnabled(5, true);
         mDct.setEnabled(0, true);
-        doReturn(true).when(mServiceState).getDataRoaming();
+
+        logd("Sending DATA_ENABLED_CMD");
+        mDct.setDataEnabled(true);
 
         logd("Sending DISABLE_ROAMING_CMD");
-        mDct.setDataOnRoamingEnabled(false);
+        mDct.setDataRoamingEnabled(false);
 
         logd("Sending EVENT_RECORDS_LOADED");
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -701,9 +711,6 @@
         mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
         waitForMs(200);
 
-        logd("Sending DATA_ENABLED_CMD");
-        mDct.setDataEnabled(true);
-
         waitForMs(200);
         verify(mSimulatedCommandsVerifier, times(1)).setInitialAttachApn(any(DataProfile.class),
                 eq(true), nullable(Message.class));
@@ -731,9 +738,9 @@
 
         mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
 
-        DataAllowFailReason failureReason = new DataAllowFailReason();
-        boolean allowed = isDataAllowed(failureReason);
-        assertFalse(failureReason.getDataAllowFailReason(), allowed);
+        DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+        boolean allowed = isDataAllowed(dataConnectionReasons);
+        assertFalse(dataConnectionReasons.toString(), allowed);
 
         ArgumentCaptor<Integer> intArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
         verify(mUiccController, times(1)).registerForIccChanged(eq(mDct),
@@ -774,9 +781,9 @@
         waitForMs(200);
 
         // Data should not be allowed since auto attach flag has been reset.
-        failureReason.clearAllReasons();
-        allowed = isDataAllowed(failureReason);
-        assertFalse(failureReason.getDataAllowFailReason(), allowed);
+        dataConnectionReasons = new DataConnectionReasons();
+        allowed = isDataAllowed(dataConnectionReasons);
+        assertFalse(dataConnectionReasons.toString(), allowed);
     }
 
     // Test for API carrierActionSetMeteredApnsEnabled.
@@ -828,4 +835,187 @@
         mDct.setDataEnabled(dataEnabled);
         waitForMs(200);
     }
+
+    private void initApns(String targetApn, String[] canHandleTypes) {
+        doReturn(targetApn).when(mApnContext).getApnType();
+        doReturn(true).when(mApnContext).isConnectable();
+        ApnSetting apnSetting = createApnSetting(canHandleTypes);
+        doReturn(apnSetting).when(mApnContext).getNextApnSetting();
+        doReturn(apnSetting).when(mApnContext).getApnSetting();
+        doReturn(mDcac).when(mApnContext).getDcAc();
+        doReturn(true).when(mApnContext).isEnabled();
+        doReturn(true).when(mApnContext).getDependencyMet();
+        doReturn(true).when(mApnContext).isReady();
+        doReturn(true).when(mApnContext).hasNoRestrictedRequests(eq(true));
+    }
+
+    // Test the emergency APN setup.
+    @Test
+    @SmallTest
+    public void testTrySetupDataEmergencyApn() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_EMERGENCY, new String[]{PhoneConstants.APN_TYPE_ALL});
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+                eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), any(DataProfile.class),
+                eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the unmetered APN setup when data is disabled.
+    @Test
+    @SmallTest
+    public void testTrySetupDataUnmeteredDataDisabled() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_FOTA, new String[]{PhoneConstants.APN_TYPE_ALL});
+        mDct.setDataEnabled(false);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+                eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), any(DataProfile.class),
+                eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the metered APN setup when data is disabled.
+    @Test
+    @SmallTest
+    public void testTrySetupMeteredDataDisabled() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        mDct.setDataEnabled(false);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+                anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the restricted data request when data is disabled.
+    @Test
+    @SmallTest
+    public void testTrySetupRestrictedDataDisabled() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        doReturn(false).when(mApnContext).hasNoRestrictedRequests(eq(true));
+
+        mDct.setDataEnabled(false);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+                anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the default data when data is not connectable.
+    @Test
+    @SmallTest
+    public void testTrySetupNotConnectable() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        doReturn(false).when(mApnContext).isConnectable();
+        mDct.setDataEnabled(true);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+                anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the default data on IWLAN.
+    @Test
+    @SmallTest
+    public void testTrySetupDefaultOnIWLAN() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+                .getRilDataRadioTechnology();
+        mDct.setDataEnabled(true);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+                anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+    }
+
+    // Test the default data when the phone is in ECBM.
+    @Test
+    @SmallTest
+    public void testTrySetupDefaultInECBM() throws Exception {
+        initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+        doReturn(true).when(mPhone).isInEcm();
+        mDct.setDataEnabled(true);
+
+        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+                new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+        logd("Sending EVENT_RECORDS_LOADED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+        waitForMs(200);
+
+        logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+        waitForMs(200);
+
+        mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+        waitForMs(200);
+
+        verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+                anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index e377600..a60b502 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -98,6 +98,7 @@
         }
 
         void die() {
+            connectivityServiceMock.die();
             looper.quit();
             handlerThread.quit();
         }
@@ -139,7 +140,7 @@
 
         TestSetup ts = new TestSetup(numberOfPhones);
 
-        TelephonyNetworkFactory tnf = makeTnf(phoneId, ts);
+        makeTnf(phoneId, ts);
 
         ts.subscriptionControllerMock.setDefaultDataSubId(subId);
         ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
@@ -234,7 +235,7 @@
 
         TestSetup ts = new TestSetup(numberOfPhones);
 
-        TelephonyNetworkFactory tnf = makeTnf(phoneId, ts);
+        makeTnf(phoneId, ts);
 
         ts.subscriptionControllerMock.setDefaultDataSubId(subId);
         ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
@@ -272,7 +273,7 @@
             fail("test 5, LiveRequests != 0");
         }
 
-        NetworkRequest subSpecificMms = makeSubSpecificMmsRequest(ts, subId);
+        makeSubSpecificMmsRequest(ts, subId);
         waitABit();
         if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
             fail("test 6,  LiveRequests != 1");
@@ -285,7 +286,7 @@
             fail("test 7,  LiveRequests != 0");
         }
 
-        NetworkRequest subSpecificDefault = makeSubSpecificDefaultRequest(ts, subId);
+        makeSubSpecificDefaultRequest(ts, subId);
         waitABit();
         if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
             fail("test 8, LiveRequests != 0");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
index 20cefb9..2575cac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
@@ -95,7 +95,7 @@
     @After
     public void tearDown() throws Exception {
         mGsmCellBroadcastHandler = null;
-        mGsmCellBroadcastHandlerTestHandler.quitSafely();
+        mGsmCellBroadcastHandlerTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 340ff35..92f2bf6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -187,7 +187,7 @@
         assertFalse(mGsmInboundSmsHandler.getWakeLock().isHeld());
         mGsmInboundSmsHandler = null;
         mContentProvider.shutdown();
-        mGsmInboundSmsHandlerTestHandler.quitSafely();
+        mGsmInboundSmsHandlerTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index fc06962..6da7ca9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -91,7 +91,7 @@
     @After
     public void tearDown() throws Exception {
         mGsmSmsDispatcher = null;
-        mGsmSmsDispatcherTestHandler.quitSafely();
+        mGsmSmsDispatcherTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java b/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
index 564e284..0e22be1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
@@ -52,7 +52,8 @@
         }
 
         @Override
-        public void removeImsFeature(int slotId, int feature) throws RemoteException {
+        public void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+                throws RemoteException {
             TestImsServiceControllerAdapter.this.removeImsFeature(slotId, feature);
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 357d50e..db1dcf1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -15,9 +15,30 @@
  */
 package com.android.internal.telephony.imsphone;
 
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.support.test.filters.FlakyTest;
@@ -29,6 +50,7 @@
 import com.android.ims.ImsCallProfile;
 import com.android.ims.ImsConfig;
 import com.android.ims.ImsConnectionStateListener;
+import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
 import com.android.ims.ImsReasonInfo;
 import com.android.ims.ImsServiceClass;
@@ -41,27 +63,12 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.isNull;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
 public class ImsPhoneCallTrackerTest extends TelephonyTest {
     private ImsPhoneCallTracker mCTUT;
     private ImsCTHandlerThread mImsCTHandlerThread;
@@ -73,6 +80,7 @@
     private int mServiceId;
     @Mock
     private ImsCallSession mImsCallSession;
+    private Handler mCTHander;
 
     private class ImsCTHandlerThread extends HandlerThread {
 
@@ -87,6 +95,7 @@
                     ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
             mCTUT.addReasonCodeRemapping(510, "Call answered elsewhere.",
                     ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
+            mCTHander = new Handler(mCTUT.getLooper());
             setReady(true);
         }
     }
@@ -191,14 +200,14 @@
 
         waitUntilReady();
         logd("ImsPhoneCallTracker initiated");
-        /* Make sure getImsService is triggered on a separate thread */
-        waitForMs(100);
+        /* Make sure getImsService is triggered on handler */
+        waitForHandlerAction(mCTHander, 100);
     }
 
     @After
     public void tearDown() throws Exception {
         mCTUT = null;
-        mImsCTHandlerThread.quitSafely();
+        mImsCTHandlerThread.quit();
         super.tearDown();
     }
 
@@ -357,6 +366,8 @@
         assertEquals(Call.State.ALERTING, mCTUT.mForegroundCall.getState());
     }
 
+    @FlakyTest
+    @Ignore
     @Test
     @SmallTest
     public void testImsMTActiveMODial() {
@@ -436,4 +447,51 @@
         assertEquals(90210, mCTUT.maybeRemapReasonCode(new ImsReasonInfo(90210, 1,
                 "Call answered elsewhere.")));
     }
+
+
+    @Test
+    @SmallTest
+    public void testDialImsServiceUnavailable() throws ImsException {
+        doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when(
+                mImsManager).createCallProfile(anyInt(), anyInt(), anyInt());
+        mCTUT.mRetryTimeout = () -> 0; //ms
+        assertEquals(Call.State.IDLE, mCTUT.mForegroundCall.getState());
+        assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
+
+        try {
+            mCTUT.dial("+17005554141", ImsCallProfile.CALL_TYPE_VOICE, null);
+        } catch (Exception e) {
+            Assert.fail();
+        }
+
+        // wait for handler to process ImsService connection retry
+        waitForHandlerAction(mCTHander, 1000); // 1 second timeout
+        verify(mImsManager, never()).makeCall(anyInt(), nullable(ImsCallProfile.class),
+                eq(new String[]{"+17005554141"}), nullable(ImsCall.Listener.class));
+        // Make sure that open is called in ImsPhoneCallTracker when it was first connected and
+        // again after retry.
+        verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class),
+                nullable(ImsConnectionStateListener.class));
+    }
+
+    @FlakyTest
+    @Ignore
+    @Test
+    @SmallTest
+    public void testTTYImsServiceUnavailable() throws ImsException {
+        doThrow(new ImsException("Test Exception", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN)).when(
+                mImsManager).setUiTTYMode(nullable(Context.class), anyInt(),
+                nullable(Message.class));
+        // Remove retry timeout delay
+        mCTUT.mRetryTimeout = () -> 0; //ms
+
+        mCTUT.setUiTTYMode(0, new Message());
+
+        // wait for handler to process ImsService connection retry
+        waitForHandlerAction(mCTHander, 100);
+        // Make sure that open is called in ImsPhoneCallTracker to re-establish connection to
+        // ImsService
+        verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class),
+                nullable(ImsConnectionStateListener.class));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
index 8a7c53a..c31541e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
@@ -60,7 +60,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mImsPhoneFactoryHandler.quitSafely();
+        mImsPhoneFactoryHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index de0c8ce..fc3c296 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -141,7 +141,7 @@
     @After
     public void tearDown() throws Exception {
         mImsPhoneUT = null;
-        mImsPhoneTestHandler.quitSafely();
+        mImsPhoneTestHandler.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java
new file mode 100644
index 0000000..7ace8cb
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRttTextHandlerTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.imsphone;
+
+import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
+import android.telecom.Connection;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+public class ImsRttTextHandlerTest extends TelephonyTest {
+    private static final int TEST_TIMEOUT = 1000;
+    private static final int READ_BUFFER_SIZE = 1000;
+    private static final String LONG_TEXT = "No Soldier shall, in time of peace be quartered in " +
+            "any house, without the consent of the Owner, nor in time of war, but in a manner to " +
+            "be prescribed by law.";
+
+    char[] buffer = new char[READ_BUFFER_SIZE];
+
+    public class MockNetworkWriter implements ImsRttTextHandler.NetworkWriter {
+        private String totalWritten = "";
+        private int numWrites = 0;
+
+        @Override
+        public synchronized void write(String s) {
+            totalWritten += s;
+            numWrites += 1;
+        }
+
+        public synchronized void reset() {
+            totalWritten = "";
+            numWrites = 0;
+        }
+
+        public synchronized String getContents() {
+            return totalWritten;
+        }
+
+        public synchronized int getNumWrites() {
+            return numWrites;
+        }
+    }
+
+    Connection.RttTextStream mRttTextStream;
+    MockNetworkWriter mNetworkWriter = new MockNetworkWriter();
+    ImsRttTextHandler mRttTextHandler;
+    HandlerThread mHandlerThread;
+
+    OutputStreamWriter mPipeToHandler;
+    InputStreamReader mPipeFromHandler;
+    InputStreamReader mHandlerSideOfPipeToHandler;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(getClass().getSimpleName());
+        mNetworkWriter.reset();
+        mHandlerThread = new HandlerThread("TestImsRttTextHandler");
+        mHandlerThread.start();
+        mRttTextHandler = new ImsRttTextHandler(mHandlerThread.getLooper(), mNetworkWriter);
+
+        // Construct some pipes to use
+        ParcelFileDescriptor[] toTextHandler = ParcelFileDescriptor.createReliablePipe();
+        ParcelFileDescriptor[] fromTextHandler = ParcelFileDescriptor.createReliablePipe();
+        mRttTextStream = new Connection.RttTextStream(fromTextHandler[1],toTextHandler[0]);
+
+        mRttTextHandler.initialize(mRttTextStream);
+
+        mPipeFromHandler = new InputStreamReader(
+                new ParcelFileDescriptor.AutoCloseInputStream(fromTextHandler[0]));
+        mPipeToHandler = new OutputStreamWriter(
+                new ParcelFileDescriptor.AutoCloseOutputStream(toTextHandler[1]));
+        mHandlerSideOfPipeToHandler = new InputStreamReader(
+                new ParcelFileDescriptor.AutoCloseInputStream(toTextHandler[1]));
+    }
+
+    /**
+     * Test that the text handler won't send characters before a timeout or enough characters
+     * have accumulated.
+     */
+    @Test
+    public void testProperCharacterBuffering() throws Exception {
+        // Send four characters
+        mPipeToHandler.write("abcd");
+        mPipeToHandler.flush();
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        // make sure at it hasn't been sent.
+        Assert.assertEquals("", mNetworkWriter.getContents());
+        // Wait for 300ms
+        waitForHandlerActionDelayed(mRttTextHandler, TEST_TIMEOUT,
+                ImsRttTextHandler.MAX_BUFFERING_DELAY_MILLIS + 100);
+        // make sure that it has been sent and check that it's correct
+        Assert.assertEquals("abcd", mNetworkWriter.getContents());
+    }
+
+    /**
+     * Test that the text handler sends after enough characters have been sent from in-call
+     * @throws Exception
+     */
+    @Test
+    public void testSendAfterEnoughChars() throws Exception {
+        // Send four characters
+        mPipeToHandler.write("abcd");
+        mPipeToHandler.flush();
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        // make sure at it hasn't been sent.
+        Assert.assertEquals("", mNetworkWriter.getContents());
+        Thread.sleep(10);
+        // Send four more characters
+        mPipeToHandler.write("efgh");
+        mPipeToHandler.flush();
+        // Wait for the stream to consume the characters
+        int count = 0;
+        while (mHandlerSideOfPipeToHandler.ready()) {
+            Thread.sleep(10);
+            count += 1;
+            if (count >= 5) {
+                break;
+            }
+        }
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        // make sure that all characters were sent.
+        Assert.assertEquals("abcdefgh", mNetworkWriter.getContents());
+    }
+
+    /**
+     * Test that the text handler sends its characters as a batch after enough of them have been
+     * buffered.
+     * @throws Exception
+     */
+    @Test
+    public void testBufferedCharactersSentAsBatch() throws Exception {
+        // Send 5 characters, one at a time, pausing for 10ms between each one.
+        char[] characters = new char[] {'a', 'b', 'c', 'd', 'e'};
+        for (char c : characters) {
+            mPipeToHandler.write(String.valueOf(c));
+            mPipeToHandler.flush();
+            Thread.sleep(10);
+        }
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+
+        // Make sure that the ordering is correct and that there was only one write
+        Assert.assertEquals("abcde", mNetworkWriter.getContents());
+        Assert.assertEquals(1, mNetworkWriter.getNumWrites());
+    }
+
+    @Test
+    public void testProperThrottling() throws Exception {
+        // Send a lot of characters in rapid succession, 3 at a time
+        char[] characters = LONG_TEXT.toCharArray();
+        for (int i = 0; i < characters.length; i += 3) {
+            String toSend = new String(characters, i, Math.min(3, characters.length - i));
+            mPipeToHandler.write(toSend);
+            mPipeToHandler.flush();
+            Thread.sleep(10);
+        }
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+
+        // Wait one second and see how many characters are sent in that time.
+        int numCharsSoFar = mNetworkWriter.getContents().length();
+        Thread.sleep(1000);
+        int numCharsInOneSec = mNetworkWriter.getContents().length() - numCharsSoFar;
+        Assert.assertTrue(numCharsInOneSec <= ImsRttTextHandler.MAX_CODEPOINTS_PER_SECOND);
+
+        // Wait 5 seconds for all the chars to make it through
+        Thread.sleep(5000);
+        Assert.assertEquals(LONG_TEXT, mNetworkWriter.getContents());
+    }
+
+    @Test
+    public void testProperTransmissionFromNetworkToInCall() throws Exception {
+        // Make sure that nothing is in the pipe from the network to incall (us)
+        Assert.assertFalse(mPipeFromHandler.ready());
+        // Send a chunk of text
+        mRttTextHandler.sendToInCall(LONG_TEXT);
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        // Make sure we get it immediately
+        Assert.assertEquals(LONG_TEXT, readAll(mPipeFromHandler));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mPipeFromHandler.close();
+        mPipeToHandler.close();
+        mRttTextHandler.tearDown();
+        waitForHandlerAction(mRttTextHandler, TEST_TIMEOUT);
+        mHandlerThread.quit();
+        super.tearDown();
+    }
+
+    private String readAll(InputStreamReader inputStreamReader) throws IOException {
+        if (!inputStreamReader.ready()) {
+            return null;
+        }
+        int len = inputStreamReader.read(buffer, 0, READ_BUFFER_SIZE);
+        return new String(buffer, 0, len);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
index e33a605..b72b79b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -35,7 +35,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
 
-import android.support.test.filters.FlakyTest;
 import android.telephony.ServiceState;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Base64;
@@ -166,6 +165,21 @@
         assertEquals(3, log.events[0].getDataStallAction());
     }
 
+    // Test write modem restart event
+    @Test
+    @SmallTest
+    public void testModemRestartEvent() throws Exception {
+        mMetrics.writeModemRestartEvent(mPhone.getPhoneId(), "Test");
+        TelephonyLog log = buildProto();
+
+        assertEquals(1, log.events.length);
+        assertEquals(0, log.callSessions.length);
+        assertEquals(0, log.smsSessions.length);
+        assertTrue(log.events[0].hasPhoneId());
+        assertEquals(mPhone.getPhoneId(), log.events[0].getPhoneId());
+        assertEquals("Test", log.events[0].modemRestart.getReason());
+    }
+
     // Test write on IMS call start
     @Test
     @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index 7169d2c..43763ec 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -127,6 +127,9 @@
 
     public void die() {
         // clean up threads/handlers
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+        }
     }
 
     private class InternalHandler extends Handler {
@@ -518,15 +521,19 @@
         throw new RuntimeException("not implemented");
     }
 
+    public void startCaptivePortalApp(Network network) {
+        throw new RuntimeException("not implemented");
+    }
+
     public int getMultipathPreference(Network network) {
         throw new RuntimeException("not implemented");
     }
 
-    public int tether(String iface) {
+    public int tether(String iface, String callerPkg) {
         throw new RuntimeException("not implemented");
     }
 
-    public int untether(String iface) {
+    public int untether(String iface, String callerPkg) {
         throw new RuntimeException("not implemented");
     }
 
@@ -546,7 +553,7 @@
         throw new RuntimeException("not implemented");
     }
 
-    public int setUsbTethering(boolean enable) {
+    public int setUsbTethering(boolean enable, String callerPkg) {
         throw new RuntimeException("not implemented");
     }
 
@@ -572,12 +579,13 @@
     }
 
     @Override
-    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
+    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
+            String callerPkg) {
         throw new RuntimeException("not implemented");
     }
 
     @Override
-    public void stopTethering(int type) {
+    public void stopTethering(int type, String callerPkg) {
         throw new RuntimeException("not implemented");
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
index 7cc2870..6d0e327 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
@@ -20,7 +20,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.util.LocalLog;
 
@@ -62,10 +61,6 @@
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public boolean isDataPossible(String apnType) {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
     public LinkProperties getLinkProperties(String apnType) {
         throw new RuntimeException("Not Implemented");
     }
@@ -90,10 +85,6 @@
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public boolean getAnyDataEnabled() {
-        throw new RuntimeException("Not Implemented");
-    }
-    @Override
     public boolean hasMatchedTetherApnSetting() {
         throw new RuntimeException("Not Implemented");
     }
@@ -106,11 +97,11 @@
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public void setDataOnRoamingEnabled(boolean enabled) {
+    public void setDataRoamingEnabled(boolean enabled) {
         throw new RuntimeException("Not Implemented");
     }
     @Override
-    public boolean getDataOnRoamingEnabled() {
+    public boolean getDataRoamingEnabled() {
         throw new RuntimeException("Not Implemented");
     }
     @Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
index 454a96e..6cecec7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
@@ -17,16 +17,16 @@
 package com.android.internal.telephony;
 
 import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Messenger;
 import android.os.Registrant;
 import android.os.RegistrantList;
+import android.os.ResultReceiver;
 import android.os.WorkSource;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
 import android.service.carrier.CarrierIdentifier;
 import android.telephony.CellInfo;
 import android.telephony.CellLocation;
@@ -159,6 +159,11 @@
         throw new RuntimeException("not implemented");
     }
 
+    @Override
+    public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
+        throw new RuntimeException("not implemented");
+    }
+
     public ArrayList<Connection> getHandoverConnection() {
         throw new RuntimeException("not implemented");
     }
@@ -796,11 +801,7 @@
         throw new RuntimeException("not implemented");
     }
 
-    public boolean isDataConnectivityPossible() {
-        throw new RuntimeException("not implemented");
-    }
-
-    public boolean isDataConnectivityPossible(String apnType) {
+    public boolean isDataAllowed() {
         throw new RuntimeException("not implemented");
     }
 
@@ -1157,6 +1158,10 @@
         throw new RuntimeException("not implemented");
     }
 
+    public boolean handleUssdServiceCall(String dialString, Callback wrappedCallback) {
+        throw new RuntimeException("not implemented");
+    }
+
     public boolean handleInCallMmiCommands(String command) throws CallStateException {
         throw new RuntimeException("not implemented");
     }
@@ -1230,6 +1235,14 @@
         throw new RuntimeException("not implemented");
     }
 
+    public void startNetworkScan(Message response) {
+        throw new RuntimeException("not implemented");
+    }
+
+    public void stopNetworkScan(Message response) {
+        throw new RuntimeException("not implemented");
+    }
+
     public void getNeighboringCids(Message response) {
         throw new RuntimeException("not implemented");
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
new file mode 100644
index 0000000..b211218
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.uicc;
+
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
+import com.android.internal.telephony.uicc.IccCardStatus.CardState;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public class IccCardProxyTest extends TelephonyTest {
+    private IccCardProxy mIccCardProxyUT;
+    // private UiccCard mUiccCard;
+    private IccCardProxyHandlerThread mIccCardProxyHandlerThread;
+    private static final int PHONE_ID = 0;
+    private static final int PHONE_COUNT = 1;
+
+    private static final int SCARY_SLEEP_MS = 200;
+    // Must match IccCardProxy.EVENT_ICC_CHANGED
+    private static final int EVENT_ICC_CHANGED = 3;
+
+    @Mock private Handler mMockedHandler;
+    @Mock private IccCardStatus mIccCardStatus;
+    @Mock private UiccCard mUiccCard;
+    @Mock private UiccCardApplication mUiccCardApplication;
+
+    private class IccCardProxyHandlerThread extends HandlerThread {
+
+        private IccCardProxyHandlerThread(String name) {
+            super(name);
+        }
+
+        @Override
+        public void onLooperPrepared() {
+            /* create a new UICC Controller associated with the simulated Commands */
+            mIccCardProxyUT = new IccCardProxy(mContext, mSimulatedCommands, PHONE_ID);
+            setReady(true);
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(this.getClass().getSimpleName());
+        doReturn(PHONE_COUNT).when(mTelephonyManager).getPhoneCount();
+        doReturn(PHONE_COUNT).when(mTelephonyManager).getSimCount();
+        mSimulatedCommands.setIccCardStatus(mIccCardStatus);
+        mIccCardProxyHandlerThread = new IccCardProxyHandlerThread(TAG);
+        mIccCardProxyHandlerThread.start();
+        waitUntilReady();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mIccCardProxyHandlerThread.quitSafely();
+        super.tearDown();
+    }
+
+    @Test
+    @SmallTest
+    public void testInitialCardState() {
+        assertEquals(mIccCardProxyUT.getState(), State.UNKNOWN);
+    }
+
+    @Test
+    @SmallTest
+    public void testPowerOn() {
+        mSimulatedCommands.setRadioPower(true, null);
+        mSimulatedCommands.notifyRadioOn();
+        when(mUiccController.getUiccCard(anyInt())).thenReturn(mUiccCard);
+        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+        waitForMs(SCARY_SLEEP_MS);
+        assertEquals(CommandsInterface.RadioState.RADIO_ON, mSimulatedCommands.getRadioState());
+        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+        logd("IccCardProxy state = " + mIccCardProxyUT.getState());
+    }
+
+    @Test
+    @SmallTest
+    public void testCardLoaded() {
+        testPowerOn();
+        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+        waitForMs(SCARY_SLEEP_MS);
+        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+    }
+
+    @Test
+    @SmallTest
+    public void testAppNotLoaded() {
+        testPowerOn();
+        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+        when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_UNKNOWN);
+        when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);
+
+        waitForMs(SCARY_SLEEP_MS);
+        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+    }
+
+    @Test
+    @SmallTest
+    public void testAppReady() {
+        testPowerOn();
+        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+        when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_READY);
+        when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);
+
+        waitForMs(SCARY_SLEEP_MS);
+        assertEquals(mIccCardProxyUT.getState(), State.READY);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
index c99bd75..9510619 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
@@ -89,7 +89,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mIccPhoneBookInterfaceManagerHandler.quitSafely();
+        mIccPhoneBookInterfaceManagerHandler.quit();
         super.tearDown();
     }
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
index 1a5daeb..60f5f6f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
@@ -110,7 +110,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mTestHandlerThread.quitSafely();
+        mTestHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
index 9a24a86..e090c25 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
@@ -134,7 +134,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mTestHandlerThread.quitSafely();
+        mTestHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index 12c2690..e62700a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -96,7 +96,7 @@
 
     @After
     public void tearDown() throws Exception {
-        mUiccControllerHandlerThread.quitSafely();
+        mUiccControllerHandlerThread.quit();
         super.tearDown();
     }