am ddeba83b: Merge "Consider EF-SMS for both gsm and cdma"

* commit 'ddeba83b6c611b3c408df12ae6de8a22a4311047':
  Consider EF-SMS for both gsm and cdma
diff --git a/src/java/android/provider/Telephony.java b/src/java/android/provider/Telephony.java
index 3ec38b2..82ad215 100644
--- a/src/java/android/provider/Telephony.java
+++ b/src/java/android/provider/Telephony.java
@@ -42,6 +42,64 @@
 /**
  * The Telephony provider contains data related to phone operation, specifically SMS and MMS
  * messages and access to the APN list, including the MMSC to use.
+ *
+ * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered
+ * devices. If your app depends on telephony features such as for managing SMS messages, include
+ * a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;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";
@@ -606,7 +664,7 @@
              * the user. The intent will have the following extra values:</p>
              *
              * <ul>
-             *   <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
              *   that make up the message.</li>
              * </ul>
              *
@@ -615,6 +673,12 @@
              *
              * <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
+             * &lt;receiver>}</a> tag.
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String SMS_DELIVER_ACTION =
@@ -628,7 +692,7 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
              *   that make up the message.</li>
              * </ul>
              *
@@ -649,7 +713,7 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>pdus</em> - An Object[] of byte[]s containing the PDUs
+             *   <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
              *   that make up the message.</li>
              * </ul>
              *
@@ -670,12 +734,12 @@
              * the user. The intent will have the following extra values:</p>
              *
              * <ul>
-             *   <li><em>transactionId (Integer)</em> - The WAP transaction ID</li>
-             *   <li><em>pduType (Integer)</em> - The WAP PDU type</li>
-             *   <li><em>header (byte[])</em> - The header of the message</li>
-             *   <li><em>data (byte[])</em> - The data payload of the message</li>
-             *   <li><em>contentTypeParameters (HashMap&lt;String,String&gt;)</em>
-             *   - Any parameters associated with the content type
+             *   <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>
              *
@@ -688,6 +752,12 @@
              * <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 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
+             * &lt;receiver>}</a> tag.
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
             public static final String WAP_PUSH_DELIVER_ACTION =
@@ -701,12 +771,12 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>transactionId (Integer)</em> - The WAP transaction ID</li>
-             *   <li><em>pduType (Integer)</em> - The WAP PDU type</li>
-             *   <li><em>header (byte[])</em> - The header of the message</li>
-             *   <li><em>data (byte[])</em> - The data payload of the message</li>
-             *   <li><em>contentTypeParameters (HashMap&lt;String,String&gt;)</em>
-             *   - Any parameters associated with the content type
+             *   <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>
              *
@@ -730,7 +800,7 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>message</em> - An SmsCbMessage object containing the broadcast message
+             *   <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>
              *
@@ -750,7 +820,7 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>message</em> - An SmsCbMessage object containing the broadcast message
+             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
              *   data, including ETWS or CMAS warning notification info if present.</li>
              * </ul>
              *
@@ -770,7 +840,7 @@
              * have the following extra values:</p>
              *
              * <ul>
-             *   <li><em>operations</em> - An array of CdmaSmsCbProgramData objects containing
+             *   <li><em>"operations"</em> - An array of CdmaSmsCbProgramData objects containing
              *   the service category operations (add/delete/clear) to perform.</li>
              * </ul>
              *
@@ -800,7 +870,7 @@
              * following extra value:</p>
              *
              * <ul>
-             *   <li><em>result</em> - An int result code, e.g. {@link #RESULT_SMS_OUT_OF_MEMORY}
+             *   <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>
              */
diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java
index aa0e85b..b73cb49 100644
--- a/src/java/android/telephony/SmsManager.java
+++ b/src/java/android/telephony/SmsManager.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -40,7 +39,10 @@
 
 /**
  * Manages SMS operations such as sending data, text, and pdu SMS messages.
- * Get this object by calling the static method SmsManager.getDefault().
+ * 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 {
     /** Singleton object constructed during class initialization. */
@@ -49,6 +51,16 @@
     /**
      * 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
@@ -116,6 +128,15 @@
      * 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
@@ -181,6 +202,9 @@
     /**
      * 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
diff --git a/src/java/android/telephony/SmsMessage.java b/src/java/android/telephony/SmsMessage.java
index d9e85d2..12d6949 100644
--- a/src/java/android/telephony/SmsMessage.java
+++ b/src/java/android/telephony/SmsMessage.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -35,6 +34,7 @@
 
 /**
  * A Short Message Service message.
+ * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
  */
 public class SmsMessage {
     private static final String LOG_TAG = "SmsMessage";
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index c4536d0..ca3d761 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
index 678f3e0..f7e0e3a 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
@@ -30,15 +30,13 @@
  * completes and our result receiver is called.
  */
 public class CellBroadcastHandler extends WakeLockStateMachine {
-    private final Context mContext;
 
     private CellBroadcastHandler(Context context) {
-        this("CellBroadcastHandler", context);
+        this("CellBroadcastHandler", context, null);
     }
 
-    protected CellBroadcastHandler(String debugTag, Context context) {
-        super(debugTag, context);
-        mContext = context;
+    protected CellBroadcastHandler(String debugTag, Context context, PhoneBase phone) {
+        super(debugTag, context, phone);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 252bc77..22c0fc3 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -113,11 +112,11 @@
     /**
      * response.obj.result is an int[2]
      *
-     * response.obj.result[0] is registration state
+     * response.obj.result[0] is IMS registration state
      *                        0 - Not registered
      *                        1 - Registered
-     * response.obj.result[1] is of type const RIL_IMS_SMS_Format,
-     *                        corresponds to sms format used for SMS over IMS.
+     * response.obj.result[1] is of type RILConstants.GSM_PHONE or
+     *                                    RILConstants.CDMA_PHONE
      */
     void getImsRegistrationState(Message result);
 
@@ -574,6 +573,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC will be PUK locked.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -590,6 +592,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC will be PUK locked.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -604,6 +609,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC is permanently disabled.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -614,12 +622,14 @@
      *
      *  AID (Application ID), See ETSI 102.221 8.1 and 101.220 4
      *
-     *  returned message
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC is permanently disabled.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -636,6 +646,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC will be PUK locked.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -654,6 +667,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC will be PUK locked.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -670,6 +686,9 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC is permanently disabled.
+     *
      * ar.exception and ar.result are null on success
      */
 
@@ -688,11 +707,15 @@
      *  This exception is CommandException with an error of PASSWORD_INCORRECT
      *  if the password is incorrect
      *
+     *  ar.result is an optional array of integers where the first entry
+     *  is the number of attempts remaining before the ICC is permanently disabled.
+     *
      * ar.exception and ar.result are null on success
      */
 
     void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result);
 
+    // TODO: Add java doc and indicate that msg.arg1 contains the number of attempts remaining.
     void changeIccPin(String oldPin, String newPin, Message result);
     void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result);
     void changeIccPin2(String oldPin2, String newPin2, Message result);
diff --git a/src/java/com/android/internal/telephony/IccCard.java b/src/java/com/android/internal/telephony/IccCard.java
index 1ec4f18..e5b34e2 100644
--- a/src/java/com/android/internal/telephony/IccCard.java
+++ b/src/java/com/android/internal/telephony/IccCard.java
@@ -108,6 +108,13 @@
     public void supplyPuk2 (String puk2, String newPin2, Message onComplete);
 
     /**
+     * Check whether fdn (fixed dialing number) service is available.
+     * @return true if ICC fdn service available
+     *         false if ICC fdn service not available
+    */
+    public boolean getIccFdnAvailable();
+
+    /**
      * Supply Network depersonalization code to the RIL
      */
     public void supplyNetworkDepersonalization (String pin, Message onComplete);
@@ -214,4 +221,14 @@
      * @return true if a ICC card is present
      */
     public boolean hasIccCard();
+
+    /**
+     * @return true if ICC card is PIN2 blocked
+     */
+    public boolean getIccPin2Blocked();
+
+    /**
+     * @return true if ICC card is PUK2 blocked
+     */
+    public boolean getIccPuk2Blocked();
 }
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index a9b0409..938fd38 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2013, The Linux Foundation. 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.
@@ -90,8 +89,7 @@
                     ar = (AsyncResult)msg.obj;
                     synchronized (mLock) {
                         if (ar.exception == null) {
-                            mSms  = (List<SmsRawData>)
-                                    buildValidRawData((ArrayList<byte[]>) ar.result);
+                            mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
                             //Mark SMS as read after importing it from card.
                             markMessagesAsRead((ArrayList<byte[]>) ar.result);
                         } else {
@@ -160,10 +158,6 @@
         }
     }
 
-    public void dispose() {
-        mDispatcher.dispose();
-    }
-
     protected void updatePhoneObject(PhoneBase phone) {
         mPhone = phone;
         mDispatcher.updatePhoneObject(phone);
diff --git a/src/java/com/android/internal/telephony/ImsSMSDispatcher.java b/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
index 28919a0..07bce94 100644
--- a/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSMSDispatcher.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -42,8 +41,9 @@
     private SMSDispatcher mCdmaDispatcher;
     private SMSDispatcher mGsmDispatcher;
 
-    GsmInboundSmsHandler mGsmInboundSmsHandler;
-    CdmaInboundSmsHandler mCdmaInboundSmsHandler;
+    private GsmInboundSmsHandler mGsmInboundSmsHandler;
+    private CdmaInboundSmsHandler mCdmaInboundSmsHandler;
+
 
     /** true if IMS is registered and sms is supported, false otherwise.*/
     private boolean mIms = false;
@@ -51,19 +51,17 @@
 
     public ImsSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
             SmsUsageMonitor usageMonitor) {
-        super(phone, usageMonitor);
+        super(phone, usageMonitor, null);
         Rlog.d(TAG, "ImsSMSDispatcher created");
 
-        // Create dispatchers, inbound SMS handlers and broadcast
-        // undelivered messages in raw table.
-        mCdmaDispatcher = new CdmaSMSDispatcher(phone,
-                storageMonitor, usageMonitor, this);
+        // Create dispatchers, inbound SMS handlers and
+        // broadcast undelivered messages in raw table.
+        mCdmaDispatcher = new CdmaSMSDispatcher(phone, usageMonitor, this);
         mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
                 storageMonitor, phone);
         mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(),
                 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher);
-        mGsmDispatcher = new GsmSMSDispatcher(phone,
-                storageMonitor, usageMonitor, this, mGsmInboundSmsHandler);
+        mGsmDispatcher = new GsmSMSDispatcher(phone, usageMonitor, this, mGsmInboundSmsHandler);
         Thread broadcastThread = new Thread(new SmsBroadcastUndelivered(phone.getContext(),
                 mGsmInboundSmsHandler, mCdmaInboundSmsHandler));
         broadcastThread.start();
@@ -79,6 +77,8 @@
         super.updatePhoneObject(phone);
         mCdmaDispatcher.updatePhoneObject(phone);
         mGsmDispatcher.updatePhoneObject(phone);
+        mGsmInboundSmsHandler.updatePhoneObject(phone);
+        mCdmaInboundSmsHandler.updatePhoneObject(phone);
     }
 
     public void dispose() {
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 4288fcc..95a650f 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -114,6 +114,9 @@
     /** Sent by {@link SmsBroadcastUndelivered} after cleaning the raw table. */
     static final int EVENT_START_ACCEPTING_SMS = 6;
 
+    /** Update phone object */
+    static final int EVENT_UPDATE_PHONE_OBJECT = 7;
+
     /** Wakelock release delay when returning to idle state. */
     private static final int WAKELOCK_TIMEOUT = 3000;
 
@@ -145,21 +148,29 @@
     final WaitingState mWaitingState = new WaitingState();
 
     /** Helper class to check whether storage is available for incoming messages. */
-    protected final SmsStorageMonitor mStorageMonitor;
+    protected SmsStorageMonitor mStorageMonitor;
 
     private final boolean mSmsReceiveDisabled;
 
+    protected PhoneBase mPhone;
+
+    protected CellBroadcastHandler mCellBroadcastHandler;
+
+
     /**
      * Create a new SMS broadcast helper.
      * @param name the class name for logging
      * @param context the context of the phone app
      * @param storageMonitor the SmsStorageMonitor to check for storage availability
      */
-    protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor) {
+    protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor,
+            PhoneBase phone, CellBroadcastHandler cellBroadcastHandler) {
         super(name);
 
         mContext = context;
         mStorageMonitor = storageMonitor;
+        mPhone = phone;
+        mCellBroadcastHandler = cellBroadcastHandler;
         mResolver = context.getContentResolver();
         mWapPush = new WapPushOverSms(context);
 
@@ -190,6 +201,13 @@
     }
 
     /**
+     * Update the phone object when it changes.
+     */
+    public void updatePhoneObject(PhoneBase phone) {
+        sendMessage(EVENT_UPDATE_PHONE_OBJECT, phone);
+    }
+
+    /**
      * Dispose of the WAP push object and release the wakelock.
      */
     @Override
@@ -208,13 +226,22 @@
     class DefaultState extends State {
         @Override
         public boolean processMessage(Message msg) {
-            String errorText = "processMessage: unhandled message type " + msg.what;
-            if (Build.IS_DEBUGGABLE) {
-                throw new RuntimeException(errorText);
-              } else {
-                loge(errorText);
-                return HANDLED;
-              }
+            switch (msg.what) {
+                case EVENT_UPDATE_PHONE_OBJECT: {
+                    onUpdatePhoneObject((PhoneBase) msg.obj);
+                    break;
+                }
+                default: {
+                    String errorText = "processMessage: unhandled message type " + msg.what;
+                    if (Build.IS_DEBUGGABLE) {
+                        throw new RuntimeException(errorText);
+                    } else {
+                        loge(errorText);
+                    }
+                    break;
+                }
+            }
+            return HANDLED;
         }
     }
 
@@ -455,6 +482,19 @@
             int result, Message response);
 
     /**
+     * Called when the phone changes the default method updates mPhone
+     * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject.
+     * Override if different or other behavior is desired.
+     *
+     * @param phone
+     */
+    protected void onUpdatePhoneObject(PhoneBase phone) {
+        mPhone = phone;
+        mStorageMonitor = mPhone.mSmsStorageMonitor;
+        log("onUpdatePhoneObject: phone=" + mPhone.getClass().getSimpleName());
+    }
+
+    /**
      * Notify interested apps if the framework has rejected an incoming SMS,
      * and send an acknowledge message to the network.
      * @param success indicates that last message was successfully received.
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 5613709..c57a8c4 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -429,7 +429,7 @@
                 sTable.add(new MccEntry(294,"mk",2));   //The Former Yugoslav Republic of Macedonia
 		sTable.add(new MccEntry(295,"li",2));	//Liechtenstein (Principality of)
                 sTable.add(new MccEntry(297,"me",2));    //Montenegro (Republic of)
-		sTable.add(new MccEntry(302,"ca",3,""));	//Canada
+		sTable.add(new MccEntry(302,"ca",3,"en"));	//Canada
 		sTable.add(new MccEntry(308,"pm",2));	//Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)
 		sTable.add(new MccEntry(310,"us",3,"en"));	//United States of America
 		sTable.add(new MccEntry(311,"us",3,"en"));	//United States of America
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 20927b9..f4e26ea 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -103,6 +103,7 @@
     static final String REASON_DATA_DEPENDENCY_UNMET = "dependencyUnmet";
     static final String REASON_LOST_DATA_CONNECTION = "lostDataConnection";
     static final String REASON_CONNECTED = "connected";
+    static final String REASON_SINGLE_PDN_ARBITRATION = "SinglePdnArbitration";
 
     // Used for band mode selection methods
     static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
diff --git a/src/java/com/android/internal/telephony/PhoneBase.java b/src/java/com/android/internal/telephony/PhoneBase.java
index 0ec5152..3e5bc4a 100644
--- a/src/java/com/android/internal/telephony/PhoneBase.java
+++ b/src/java/com/android/internal/telephony/PhoneBase.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2007 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index b9a6975..d7b4c8f 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -147,6 +147,9 @@
                 }
                 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);
 
+                // Set up monitor to watch for changes to SMS packages
+                SmsApplication.initSmsPackageMonitor(context);
+
                 sMadeDefaults = true;
             }
         }
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9b9408b..268174d 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -193,7 +192,7 @@
 
         if (RIL.RILJ_LOGD) Rlog.d(LOG_TAG, serialString() + "< "
             + RIL.requestToString(mRequest)
-            + " error: " + ex);
+            + " error: " + ex + " ret=" + RIL.retToString(mRequest, ret));
 
         if (mResult != null) {
             AsyncResult.forMessage(mResult, ret, ex);
@@ -1269,7 +1268,7 @@
             Message result) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result);
 
-        rr.mParcel.writeInt(1); //RIL_IMS_SMS_Format.FORMAT_3GPP
+        rr.mParcel.writeInt(RILConstants.GSM_PHONE);
         rr.mParcel.writeByte((byte)retry);
         rr.mParcel.writeInt(messageRef);
 
@@ -1284,7 +1283,7 @@
     sendImsCdmaSms(byte[] pdu, int retry, int messageRef, Message result) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_SEND_SMS, result);
 
-        rr.mParcel.writeInt(2); //RIL_IMS_SMS_Format.FORMAT_3GPP2
+        rr.mParcel.writeInt(RILConstants.CDMA_PHONE);
         rr.mParcel.writeByte((byte)retry);
         rr.mParcel.writeInt(messageRef);
 
@@ -2505,7 +2504,7 @@
         return rr;
     }
 
-    private String
+    static String
     retToString(int req, Object ret) {
         if (ret == null) return "";
         switch (req) {
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index b760d37..9cd5b70 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -59,6 +58,7 @@
 
 import com.android.internal.R;
 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.ImsSMSDispatcher;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -128,7 +128,6 @@
     protected final Context mContext;
     protected final ContentResolver mResolver;
     protected final CommandsInterface mCi;
-    protected SmsStorageMonitor mStorageMonitor;
     protected final TelephonyManager mTelephonyManager;
 
     /** Maximum number of times to retry sending a failed SMS. */
@@ -151,6 +150,8 @@
     /** Outgoing message counter. Shared by all dispatchers. */
     private SmsUsageMonitor mUsageMonitor;
 
+    private ImsSMSDispatcher mImsSMSDispatcher;
+
     /** Number of outgoing SmsTrackers waiting for user confirmation. */
     private int mPendingTrackerCount;
 
@@ -170,8 +171,10 @@
      * @param phone the Phone to use
      * @param usageMonitor the SmsUsageMonitor to use
      */
-    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor) {
+    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
+            ImsSMSDispatcher imsSMSDispatcher) {
         mPhone = phone;
+        mImsSMSDispatcher = imsSMSDispatcher;
         mContext = phone.getContext();
         mResolver = mContext.getContentResolver();
         mCi = phone.mCi;
@@ -211,7 +214,6 @@
 
     protected void updatePhoneObject(PhoneBase phone) {
         mPhone = phone;
-        mStorageMonitor = phone.mSmsStorageMonitor;
         mUsageMonitor = phone.mSmsUsageMonitor;
         Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
     }
@@ -341,11 +343,10 @@
         if (ar.exception == null) {
             if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
 
-            String defaultSmsPackage = Sms.getDefaultSmsPackage(mContext);
-            if (defaultSmsPackage == null ||
-                    !defaultSmsPackage.equals(tracker.mAppInfo.applicationInfo.packageName)) {
-                // Someone other than the default SMS app sent this message. Persist it into the
-                // SMS database as a sent message so the user can see it in their default app.
+            if (SmsApplication.shouldWriteMessageForPackage(
+                    tracker.mAppInfo.applicationInfo.packageName, mContext)) {
+                // Persist it into the SMS database as a sent message
+                // so the user can see it in their default app.
                 tracker.writeSentMessage(mContext);
             }
 
@@ -945,7 +946,14 @@
      *
      * @param tracker holds the SMS message to send
      */
-    public abstract void sendRetrySms(SmsTracker tracker);
+    public void sendRetrySms(SmsTracker tracker) {
+        // re-routing to ImsSMSDispatcher
+        if (mImsSMSDispatcher != null) {
+            mImsSMSDispatcher.sendRetrySms(tracker);
+        } else {
+            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
+        }
+    }
 
     /**
      * Send the multi-part SMS based on multipart Sms tracker
@@ -1060,7 +1068,7 @@
         }
     }
 
-    protected SmsTracker SmsTrackerFactory(HashMap<String, Object> data, PendingIntent sentIntent,
+    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
             PendingIntent deliveryIntent, String format) {
         // Get calling app package name via UID from Binder call
         PackageManager pm = mContext.getPackageManager();
@@ -1082,7 +1090,7 @@
         return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format);
     }
 
-    protected HashMap SmsTrackerMapFactory(String destAddr, String scAddr,
+    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
             String text, SmsMessageBase.SubmitPduBase pdu) {
         HashMap<String, Object> map = new HashMap<String, Object>();
         map.put("destAddr", destAddr);
@@ -1093,12 +1101,12 @@
         return map;
     }
 
-    protected HashMap SmsTrackerMapFactory(String destAddr, String scAddr,
+    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
             int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
         HashMap<String, Object> map = new HashMap<String, Object>();
         map.put("destAddr", destAddr);
         map.put("scAddr", scAddr);
-        map.put("destPort", Integer.valueOf(destPort));
+        map.put("destPort", destPort);
         map.put("data", data);
         map.put("smsc", pdu.encodedScAddress);
         map.put("pdu", pdu.encodedMessage);
@@ -1190,7 +1198,21 @@
         }
     }
 
-    public abstract boolean isIms();
+    public boolean isIms() {
+        if (mImsSMSDispatcher != null) {
+            return mImsSMSDispatcher.isIms();
+        } else {
+            Rlog.e(TAG, mImsSMSDispatcher + " is null");
+            return false;
+        }
+    }
 
-    public abstract String getImsSmsFormat();
+    public String getImsSmsFormat() {
+        if (mImsSMSDispatcher != null) {
+            return mImsSMSDispatcher.getImsSmsFormat();
+        } else {
+            Rlog.e(TAG, mImsSMSDispatcher + " is null");
+            return null;
+        }
+    }
 }
diff --git a/src/java/com/android/internal/telephony/SmsApplication.java b/src/java/com/android/internal/telephony/SmsApplication.java
index dc0bf29..80ae2b8 100644
--- a/src/java/com/android/internal/telephony/SmsApplication.java
+++ b/src/java/com/android/internal/telephony/SmsApplication.java
@@ -21,6 +21,7 @@
 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.PackageInfo;
 import android.content.pm.PackageManager;
@@ -33,6 +34,7 @@
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
+import com.android.internal.content.PackageMonitor;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -46,6 +48,14 @@
 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 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 SmsPackageMonitor sSmsPackageMonitor = null;
 
     public static class SmsApplicationData {
         /**
@@ -167,7 +177,7 @@
 
         // Update any existing entries with respond via message intent class.
         intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
-                Uri.fromParts("smsto", "", null));
+                Uri.fromParts(SCHEME_SMSTO, "", null));
         List<ResolveInfo> respondServices = packageManager.queryIntentServices(intent, 0);
         for (ResolveInfo resolveInfo : respondServices) {
             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -186,7 +196,7 @@
 
         // Update any existing entries with supports send to.
         intent = new Intent(Intent.ACTION_SENDTO,
-                Uri.fromParts("smsto", "", null));
+                Uri.fromParts(SCHEME_SMSTO, "", null));
         List<ResolveInfo> sendToActivities = packageManager.queryIntentActivities(intent, 0);
         for (ResolveInfo resolveInfo : sendToActivities) {
             final ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -308,10 +318,17 @@
                 }
             }
 
-            // We can only verify the phone app's permissions from a privileged caller
+            // We can only verify the phone and BT app's permissions from a privileged caller
             if (updateIfNeeded) {
-                // Verify that the phone app has permissions
+                // 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));
+
+                // Verify that the phone and BT app has permissions
                 try {
                     PackageInfo info = packageManager.getPackageInfo(PHONE_PACKAGE_NAME, 0);
                     int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
@@ -326,6 +343,20 @@
                     Rlog.e(LOG_TAG, "Phone package not found: " + PHONE_PACKAGE_NAME);
                     applicationData = null;
                 }
+
+                try {
+                    PackageInfo info = packageManager.getPackageInfo(BLUETOOTH_PACKAGE_NAME, 0);
+                    int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
+                            BLUETOOTH_PACKAGE_NAME);
+                    if (mode != AppOpsManager.MODE_ALLOWED) {
+                        Rlog.e(LOG_TAG, BLUETOOTH_PACKAGE_NAME + " lost OP_WRITE_SMS:  (fixing)");
+                        appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
+                                BLUETOOTH_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+                    }
+                } catch (NameNotFoundException e) {
+                    // No BT app on this device
+                    Rlog.e(LOG_TAG, "Bluetooth package not found: " + BLUETOOTH_PACKAGE_NAME);
+                }
             }
         }
         return applicationData;
@@ -373,6 +404,10 @@
             Settings.Secure.putString(context.getContentResolver(),
                     Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName);
 
+            // Configure this as the preferred activity for SENDTO sms/mms intents
+            configurePreferredActivity(packageManager, new ComponentName(
+                    applicationData.mPackageName, applicationData.mSendToClass));
+
             // Allow OP_WRITE_SMS for the newly configured default SMS app.
             appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
                     applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
@@ -386,10 +421,99 @@
                 // No phone app on this device (unexpected, even for non-phone devices)
                 Rlog.e(LOG_TAG, "Phone package not found: " + PHONE_PACKAGE_NAME);
             }
+
+            // BT needs to always have this permission to write to the sms database
+            try {
+                PackageInfo info = packageManager.getPackageInfo(BLUETOOTH_PACKAGE_NAME, 0);
+                appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
+                        BLUETOOTH_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+            } catch (NameNotFoundException e) {
+                // No BT app on this device
+                Rlog.e(LOG_TAG, "Bluetooth package not found: " + BLUETOOTH_PACKAGE_NAME);
+            }
         }
     }
 
     /**
+     * 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(packageName);
+        }
+
+        @Override
+        public void onPackageAppeared(String packageName, int reason) {
+            onPackageChanged(packageName);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            onPackageChanged(packageName);
+        }
+
+        private void onPackageChanged(String packageName) {
+            PackageManager packageManager = mContext.getPackageManager();
+            // Ensure this component is still configured as the preferred activity
+            ComponentName componentName = getDefaultSendToApplication(mContext, true);
+            if (componentName != null) {
+                configurePreferredActivity(packageManager, componentName);
+            }
+        }
+    }
+
+    public static void initSmsPackageMonitor(Context context) {
+        sSmsPackageMonitor = new SmsPackageMonitor(context);
+        sSmsPackageMonitor.register(context, context.getMainLooper(), false);
+    }
+
+    private static void configurePreferredActivity(PackageManager packageManager,
+            ComponentName componentName) {
+        // Add the four activity preferences we want to direct to this app.
+        replacePreferredActivity(packageManager, componentName, SCHEME_SMS);
+        replacePreferredActivity(packageManager, componentName, SCHEME_SMSTO);
+        replacePreferredActivity(packageManager, componentName, SCHEME_MMS);
+        replacePreferredActivity(packageManager, componentName, SCHEME_MMSTO);
+    }
+
+    /**
+     * Updates the ACTION_SENDTO activity to the specified component for the specified scheme.
+     */
+    private static void replacePreferredActivity(PackageManager packageManager,
+            ComponentName componentName, 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.queryIntentActivities(
+                intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER);
+
+        // 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.replacePreferredActivity(intentFilter,
+                IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL,
+                set, componentName);
+    }
+
+    /**
      * Returns SmsApplicationData for this package if this package is capable of being set as the
      * default SMS application.
      */
@@ -463,4 +587,25 @@
         }
         return component;
     }
+
+    /**
+     * Returns whether need to write the SMS message to SMS database for this package.
+     */
+    public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
+        if (packageName == null) return true;
+
+        String defaultSmsPackage = null;
+        ComponentName component = getDefaultSmsApplication(context, false);
+        if (component != null) {
+            defaultSmsPackage = component.getPackageName();
+        }
+
+        if ((defaultSmsPackage == null || !defaultSmsPackage.equals(packageName)) &&
+                !packageName.equals(BLUETOOTH_PACKAGE_NAME)) {
+            // To write the message for someone other than the default SMS and BT app
+            return true;
+        }
+
+        return false;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/WakeLockStateMachine.java b/src/java/com/android/internal/telephony/WakeLockStateMachine.java
index ef1b68e..404b0cc 100644
--- a/src/java/com/android/internal/telephony/WakeLockStateMachine.java
+++ b/src/java/com/android/internal/telephony/WakeLockStateMachine.java
@@ -48,6 +48,12 @@
     /** Release wakelock after a short timeout when returning to idle state. */
     static final int EVENT_RELEASE_WAKE_LOCK = 3;
 
+    static final int EVENT_UPDATE_PHONE_OBJECT = 4;
+
+    protected PhoneBase mPhone;
+
+    protected Context mContext;
+
     /** Wakelock release delay when returning to idle state. */
     private static final int WAKE_LOCK_TIMEOUT = 3000;
 
@@ -55,9 +61,12 @@
     private final IdleState mIdleState = new IdleState();
     private final WaitingState mWaitingState = new WaitingState();
 
-    protected WakeLockStateMachine(String debugTag, Context context) {
+    protected WakeLockStateMachine(String debugTag, Context context, PhoneBase phone) {
         super(debugTag);
 
+        mContext = context;
+        mPhone = phone;
+
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, debugTag);
         mWakeLock.acquire();    // wake lock released after we enter idle state
@@ -68,6 +77,10 @@
         setInitialState(mIdleState);
     }
 
+    public void updatePhoneObject(PhoneBase phone) {
+        sendMessage(EVENT_UPDATE_PHONE_OBJECT, phone);
+    }
+
     /**
      * Tell the state machine to quit after processing all messages.
      */
@@ -98,13 +111,23 @@
     class DefaultState extends State {
         @Override
         public boolean processMessage(Message msg) {
-            String errorText = "processMessage: unhandled message type " + msg.what;
-            if (Build.IS_DEBUGGABLE) {
-                throw new RuntimeException(errorText);
-              } else {
-                loge(errorText);
-                return HANDLED;
-              }
+            switch (msg.what) {
+                case EVENT_UPDATE_PHONE_OBJECT: {
+                    mPhone = (PhoneBase) msg.obj;
+                    log("updatePhoneObject: phone=" + mPhone.getClass().getSimpleName());
+                    break;
+                }
+                default: {
+                    String errorText = "processMessage: unhandled message type " + msg.what;
+                    if (Build.IS_DEBUGGABLE) {
+                        throw new RuntimeException(errorText);
+                    } else {
+                        loge(errorText);
+                    }
+                    break;
+                }
+            }
+            return HANDLED;
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 1f9368a..3b6856d 100644
--- a/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -1,6 +1,5 @@
 /* 
- * Copyrigh (C) 2011 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2011 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.
@@ -196,6 +195,27 @@
 
     }
 
+
+    /**
+     * Sets the "current" field in the telephony provider according to the
+     * build-time operator numeric property
+     *
+     * @return true for success; false otherwise.
+     */
+    @Override
+    boolean updateCurrentCarrierInProvider(String operatorNumeric) {
+        boolean retVal;
+        if (mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP) == null) {
+            if (DBG) log("updateCurrentCarrierInProvider APP_FAM_3GPP == null");
+            retVal = super.updateCurrentCarrierInProvider(operatorNumeric);
+        } else {
+            if (DBG) log("updateCurrentCarrierInProvider not updated");
+            retVal = true;
+        }
+        if (DBG) log("updateCurrentCarrierInProvider X retVal=" + retVal);
+        return retVal;
+    }
+
     @Override
     public boolean updateCurrentCarrierInProvider() {
         if (mSimRecords != null) {
diff --git a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 38524df..ccffeae 100644
--- a/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/src/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -196,22 +195,24 @@
         mCarrierOtaSpNumSchema = SystemProperties.get(
                 TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,"");
 
-        // Sets operator alpha property by retrieving from build-time system property
+        // Sets operator properties by retrieving from build-time system property
         String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha");
-        setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
-
-        // Sets operator numeric property by retrieving from build-time system property
         String operatorNumeric = SystemProperties.get(PROPERTY_CDMA_HOME_OPERATOR_NUMERIC);
-        if (!TextUtils.isEmpty(operatorNumeric) &&
-            (mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP) == null)) {
-            log("CDMAPhone: init set 'gsm.sim.operator.numeric' to operator='" +
-                    operatorNumeric + "'");
-            setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
+        log("init: operatorAlpha='" + operatorAlpha
+                + "' operatorNumeric='" + operatorNumeric + "'");
+        if (mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP) == null) {
+            log("init: APP_FAM_3GPP == NULL");
+            if (!TextUtils.isEmpty(operatorAlpha)) {
+                log("init: set 'gsm.sim.operator.alpha' to operator='" + operatorAlpha + "'");
+                setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, operatorAlpha);
+            }
+            if (!TextUtils.isEmpty(operatorNumeric)) {
+                log("init: set 'gsm.sim.operator.numeric' to operator='" + operatorNumeric + "'");
+                setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operatorNumeric);
+            }
+            setIsoCountryProperty(operatorNumeric);
         }
 
-        // Sets iso country property by retrieving from build-time system property
-        setIsoCountryProperty(operatorNumeric);
-
         // Sets current entry in the telephony carrier table
         updateCurrentCarrierInProvider(operatorNumeric);
 
@@ -575,12 +576,12 @@
 
     @Override
     public boolean handlePinMmi(String dialString) {
-        CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this);
+        CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
 
         if (mmi == null) {
             Rlog.e(LOG_TAG, "Mmi is NULL!");
             return false;
-        } else if (mmi.isPukCommand()) {
+        } else if (mmi.isPinPukCommand()) {
             mPendingMmis.add(mmi);
             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
             mmi.processCode();
@@ -1544,6 +1545,7 @@
      */
     private void setIsoCountryProperty(String operatorNumeric) {
         if (TextUtils.isEmpty(operatorNumeric)) {
+            log("setIsoCountryProperty: clear 'gsm.sim.operator.iso-country'");
             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
         } else {
             String iso = "";
@@ -1551,11 +1553,12 @@
                 iso = MccTable.countryCodeForMcc(Integer.parseInt(
                         operatorNumeric.substring(0,3)));
             } catch (NumberFormatException ex) {
-                Rlog.w(LOG_TAG, "countryCodeForMcc error" + ex);
+                loge("setIsoCountryProperty: countryCodeForMcc error", ex);
             } catch (StringIndexOutOfBoundsException ex) {
-                Rlog.w(LOG_TAG, "countryCodeForMcc error" + ex);
+                loge("setIsoCountryProperty: countryCodeForMcc error", ex);
             }
 
+            log("setIsoCountryProperty: set 'gsm.sim.operator.iso-country' to iso=" + iso);
             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
         }
     }
@@ -1567,6 +1570,7 @@
      * @return true for success; false otherwise.
      */
     boolean updateCurrentCarrierInProvider(String operatorNumeric) {
+        log("CDMAPhone: updateCurrentCarrierInProvider called");
         if (!TextUtils.isEmpty(operatorNumeric)) {
             try {
                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
@@ -1632,6 +1636,11 @@
             Rlog.d(LOG_TAG, s);
     }
 
+    protected void loge(String s, Exception e) {
+        if (DBG)
+            Rlog.e(LOG_TAG, s, e);
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("CDMAPhone extends:");
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
index 99e790f..9352639 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
@@ -45,9 +45,7 @@
  */
 public class CdmaInboundSmsHandler extends InboundSmsHandler {
 
-    private final PhoneBase mPhone;
     private final CdmaSMSDispatcher mSmsDispatcher;
-    private final CellBroadcastHandler mCellBroadcastHandler;
     private final CdmaServiceCategoryProgramHandler mServiceCategoryProgramHandler;
 
     private byte[] mLastDispatchedSmsFingerprint;
@@ -61,12 +59,11 @@
      */
     private CdmaInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor,
             PhoneBase phone, CdmaSMSDispatcher smsDispatcher) {
-        super("CdmaInboundSmsHandler", context, storageMonitor);
+        super("CdmaInboundSmsHandler", context, storageMonitor, phone,
+                CellBroadcastHandler.makeCellBroadcastHandler(context));
         mSmsDispatcher = smsDispatcher;
-        mCellBroadcastHandler = CellBroadcastHandler.makeCellBroadcastHandler(context);
         mServiceCategoryProgramHandler = CdmaServiceCategoryProgramHandler.makeScpHandler(context,
                 phone.mCi);
-        mPhone = phone;
         phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null);
     }
 
@@ -214,6 +211,19 @@
     }
 
     /**
+     * Called when the phone changes the default method updates mPhone
+     * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject.
+     * Override if different or other behavior is desired.
+     *
+     * @param phone
+     */
+    @Override
+    protected void onUpdatePhoneObject(PhoneBase phone) {
+        super.onUpdatePhoneObject(phone);
+        mCellBroadcastHandler.updatePhoneObject(phone);
+    }
+
+    /**
      * Convert Android result code to CDMA SMS failure cause.
      * @param rc the Android SMS intent result value
      * @return 0 for success, or a CDMA SMS failure cause value
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
index 4c58709..3cb8bc7 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 
 import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.uicc.UiccCardApplication;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
 import com.android.internal.telephony.MmiCode;
 
 import android.os.AsyncResult;
@@ -43,8 +45,11 @@
     // From TS 22.030 6.5.2
     static final String ACTION_REGISTER = "**";
 
-    // Supp Service codes from TS 22.030 Annex B
+    // Supplementary Service codes for PIN/PIN2/PUK/PUK2 from TS 22.030 Annex B
+    static final String SC_PIN          = "04";
+    static final String SC_PIN2         = "042";
     static final String SC_PUK          = "05";
+    static final String SC_PUK2         = "052";
 
     // Event Constant
 
@@ -54,6 +59,7 @@
 
     CDMAPhone mPhone;
     Context mContext;
+    UiccCardApplication mUiccApplication;
 
     String mAction;              // ACTION_REGISTER
     String mSc;                  // Service Code
@@ -98,7 +104,7 @@
      */
 
     public static CdmaMmiCode
-    newFromDialString(String dialString, CDMAPhone phone) {
+    newFromDialString(String dialString, CDMAPhone phone, UiccCardApplication app) {
         Matcher m;
         CdmaMmiCode ret = null;
 
@@ -106,7 +112,7 @@
 
         // Is this formatted like a standard supplementary service code?
         if (m.matches()) {
-            ret = new CdmaMmiCode(phone);
+            ret = new CdmaMmiCode(phone,app);
             ret.mPoundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
             ret.mAction = makeEmptyNull(m.group(MATCH_GROUP_ACTION));
             ret.mSc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
@@ -135,10 +141,11 @@
 
     // Constructor
 
-    CdmaMmiCode (CDMAPhone phone) {
+    CdmaMmiCode (CDMAPhone phone, UiccCardApplication app) {
         super(phone.getHandler().getLooper());
         mPhone = phone;
         mContext = phone.getContext();
+        mUiccApplication = app;
     }
 
     // MmiCode implementation
@@ -178,9 +185,10 @@
     /**
      * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
      */
-    boolean isPukCommand() {
-        return mSc != null && mSc.equals(SC_PUK);
-     }
+    boolean isPinPukCommand() {
+        return mSc != null && (mSc.equals(SC_PIN) || mSc.equals(SC_PIN2)
+                              || mSc.equals(SC_PUK) || mSc.equals(SC_PUK2));
+    }
 
     boolean isRegister() {
         return mAction != null && mAction.equals(ACTION_REGISTER);
@@ -194,31 +202,56 @@
 
     /** Process a MMI PUK code */
     void
-    processCode () {
+    processCode() {
         try {
-            if (isPukCommand()) {
-                // sia = old PUK
+            if (isPinPukCommand()) {
+                // TODO: This is the same as the code in GsmMmiCode.java,
+                // MmiCode should be an abstract or base class and this and
+                // other common variables and code should be promoted.
+
+                // sia = old PIN or PUK
                 // sib = new PIN
                 // sic = new PIN
                 String oldPinOrPuk = mSia;
-                String newPin = mSib;
-                int pinLen = newPin.length();
+                String newPinOrPuk = mSib;
+                int pinLen = newPinOrPuk.length();
                 if (isRegister()) {
-                    if (!newPin.equals(mSic)) {
+                    if (!newPinOrPuk.equals(mSic)) {
                         // password mismatch; return error
                         handlePasswordError(com.android.internal.R.string.mismatchPin);
                     } else if (pinLen < 4 || pinLen > 8 ) {
                         // invalid length
                         handlePasswordError(com.android.internal.R.string.invalidPin);
+                    } else if (mSc.equals(SC_PIN)
+                            && mUiccApplication != null
+                            && mUiccApplication.getState() == AppState.APPSTATE_PUK) {
+                        // Sim is puk-locked
+                        handlePasswordError(com.android.internal.R.string.needPuk);
+                    } else if (mUiccApplication != null) {
+                        Rlog.d(LOG_TAG, "process mmi service code using UiccApp sc=" + mSc);
+
+                        // We have an app and the pre-checks are OK
+                        if (mSc.equals(SC_PIN)) {
+                            mUiccApplication.changeIccLockPassword(oldPinOrPuk, newPinOrPuk,
+                                    obtainMessage(EVENT_SET_COMPLETE, this));
+                        } else if (mSc.equals(SC_PIN2)) {
+                            mUiccApplication.changeIccFdnPassword(oldPinOrPuk, newPinOrPuk,
+                                    obtainMessage(EVENT_SET_COMPLETE, this));
+                        } else if (mSc.equals(SC_PUK)) {
+                            mUiccApplication.supplyPuk(oldPinOrPuk, newPinOrPuk,
+                                    obtainMessage(EVENT_SET_COMPLETE, this));
+                        } else if (mSc.equals(SC_PUK2)) {
+                            mUiccApplication.supplyPuk2(oldPinOrPuk, newPinOrPuk,
+                                    obtainMessage(EVENT_SET_COMPLETE, this));
+                        } else {
+                            throw new RuntimeException("Unsupported service code=" + mSc);
+                        }
                     } else {
-                        mPhone.mCi.supplyIccPuk(oldPinOrPuk, newPin,
-                                obtainMessage(EVENT_SET_COMPLETE, this));
+                        throw new RuntimeException("No application mUiccApplicaiton is null");
                     }
                 } else {
-                    throw new RuntimeException ("Invalid or Unsupported MMI Code");
+                    throw new RuntimeException ("Ivalid register/action=" + mAction);
                 }
-            } else {
-                throw new RuntimeException ("Invalid or Unsupported MMI Code");
             }
         } catch (RuntimeException exc) {
             mState = State.FAILED;
@@ -243,7 +276,7 @@
 
         if (msg.what == EVENT_SET_COMPLETE) {
             ar = (AsyncResult) (msg.obj);
-            onSetComplete(ar);
+            onSetComplete(msg, ar);
         } else {
             Rlog.e(LOG_TAG, "Unexpected reply");
         }
@@ -252,7 +285,7 @@
 
     private CharSequence getScString() {
         if (mSc != null) {
-            if (isPukCommand()) {
+            if (isPinPukCommand()) {
                 return mContext.getText(com.android.internal.R.string.PinMmi);
             }
         }
@@ -261,7 +294,7 @@
     }
 
     private void
-    onSetComplete(AsyncResult ar){
+    onSetComplete(Message msg, AsyncResult ar){
         StringBuilder sb = new StringBuilder(getScString());
         sb.append("\n");
 
@@ -270,13 +303,42 @@
             if (ar.exception instanceof CommandException) {
                 CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
                 if (err == CommandException.Error.PASSWORD_INCORRECT) {
-                    if (isPukCommand()) {
-                        sb.append(mContext.getText(
-                                com.android.internal.R.string.badPuk));
+                    if (isPinPukCommand()) {
+                        // look specifically for the PUK commands and adjust
+                        // the message accordingly.
+                        if (mSc.equals(SC_PUK) || mSc.equals(SC_PUK2)) {
+                            sb.append(mContext.getText(
+                                    com.android.internal.R.string.badPuk));
+                        } else {
+                            sb.append(mContext.getText(
+                                    com.android.internal.R.string.badPin));
+                        }
+                        // Get the No. of retries remaining to unlock PUK/PUK2
+                        int attemptsRemaining = msg.arg1;
+                        if (attemptsRemaining <= 0) {
+                            Rlog.d(LOG_TAG, "onSetComplete: PUK locked,"
+                                    + " cancel as lock screen will handle this");
+                            mState = State.CANCELLED;
+                        } else if (attemptsRemaining > 0) {
+                            Rlog.d(LOG_TAG, "onSetComplete: attemptsRemaining="+attemptsRemaining);
+                            sb.append(mContext.getResources().getQuantityString(
+                                    com.android.internal.R.plurals.pinpuk_attempts,
+                                    attemptsRemaining, attemptsRemaining));
+                        }
                     } else {
                         sb.append(mContext.getText(
                                 com.android.internal.R.string.passwordIncorrect));
                     }
+                } else if (err == CommandException.Error.SIM_PUK2) {
+                    sb.append(mContext.getText(
+                            com.android.internal.R.string.badPin));
+                    sb.append("\n");
+                    sb.append(mContext.getText(
+                            com.android.internal.R.string.needPuk2));
+                } else if (err == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                    if (mSc.equals(SC_PIN)) {
+                        sb.append(mContext.getText(com.android.internal.R.string.enablePin));
+                    }
                 } else {
                     sb.append(mContext.getText(
                             com.android.internal.R.string.mmiError));
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 147a310..f168180 100755
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -28,12 +27,11 @@
 import android.telephony.SmsManager;
 
 import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsConstants;
+import com.android.internal.telephony.ImsSMSDispatcher;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.SMSDispatcher;
-import com.android.internal.telephony.ImsSMSDispatcher;
+import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsStorageMonitor;
 import com.android.internal.telephony.SmsUsageMonitor;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.sms.UserData;
@@ -43,15 +41,18 @@
 public class CdmaSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "CdmaSMSDispatcher";
     private static final boolean VDBG = false;
-    private ImsSMSDispatcher mImsSMSDispatcher;
 
-    public CdmaSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
-            SmsUsageMonitor usageMonitor, ImsSMSDispatcher imsSMSDispatcher) {
-        super(phone, usageMonitor);
-        mImsSMSDispatcher = imsSMSDispatcher;
+    public CdmaSMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
+            ImsSMSDispatcher imsSMSDispatcher) {
+        super(phone, usageMonitor, imsSMSDispatcher);
         Rlog.d(TAG, "CdmaSMSDispatcher created");
     }
 
+    @Override
+    protected String getFormat() {
+        return SmsConstants.FORMAT_3GPP2;
+    }
+
     /**
      * Send the SMS status report to the dispatcher thread to process.
      * @param sms the CDMA SMS message containing the status report
@@ -71,10 +72,6 @@
         }
     }
 
-    protected String getFormat() {
-        return SmsConstants.FORMAT_3GPP2;
-    }
-
     /**
      * Called from parent class to handle status report from {@code CdmaInboundSmsHandler}.
      * @param sms the CDMA SMS message to process
@@ -106,8 +103,8 @@
             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, destPort, data, (deliveryIntent != null));
-        HashMap map =  SmsTrackerMapFactory(destAddr, scAddr, destPort, data, pdu);
-        SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent,
+        HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
+        SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,
                 getFormat());
         sendSubmitPdu(tracker);
     }
@@ -118,8 +115,8 @@
             PendingIntent sentIntent, PendingIntent deliveryIntent) {
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, text, (deliveryIntent != null), null);
-        HashMap map =  SmsTrackerMapFactory(destAddr, scAddr, text, pdu);
-        SmsTracker tracker = SmsTrackerFactory(map, sentIntent,
+        HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
+        SmsTracker tracker = getSmsTracker(map, sentIntent,
                 deliveryIntent, getFormat());
         sendSubmitPdu(tracker);
     }
@@ -153,9 +150,9 @@
         SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress,
                 uData, (deliveryIntent != null) && lastPart);
 
-        HashMap map =  SmsTrackerMapFactory(destinationAddress, scAddress,
+        HashMap map = getSmsTrackerMap(destinationAddress, scAddress,
                 message, submitPdu);
-        SmsTracker tracker = SmsTrackerFactory(map, sentIntent,
+        SmsTracker tracker = getSmsTracker(map, sentIntent,
                 deliveryIntent, getFormat());
         sendSubmitPdu(tracker);
     }
@@ -205,20 +202,4 @@
             tracker.mImsRetry++;
         }
     }
-
-    @Override
-    public void sendRetrySms(SmsTracker tracker) {
-        //re-routing to ImsSMSDispatcher
-        mImsSMSDispatcher.sendRetrySms(tracker);
-    }
-
-    @Override
-    public boolean isIms() {
-        return mImsSMSDispatcher.isIms();
-    }
-
-    @Override
-    public String getImsSmsFormat() {
-        return mImsSMSDispatcher.getImsSmsFormat();
-    }
 }
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java
index f11c681..bb9f9d5 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaServiceCategoryProgramHandler.java
@@ -45,14 +45,13 @@
  */
 public final class CdmaServiceCategoryProgramHandler extends WakeLockStateMachine {
 
-    private final Context mContext;
     final CommandsInterface mCi;
 
     /**
      * Create a new CDMA inbound SMS handler.
      */
     CdmaServiceCategoryProgramHandler(Context context, CommandsInterface commandsInterface) {
-        super("CdmaServiceCategoryProgramHandler", context);
+        super("CdmaServiceCategoryProgramHandler", context, null);
         mContext = context;
         mCi = commandsInterface;
     }
@@ -159,7 +158,7 @@
                 dos.writeInt(0); //servicePresent
                 dos.writeInt(0); //serviceCategory
                 CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
-                        PhoneNumberUtils.cdmaCheckAndProcessPlusCode(sender));
+                        PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(sender));
                 dos.write(destAddr.digitMode);
                 dos.write(destAddr.numberMode);
                 dos.write(destAddr.ton); // number_type
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessage.java b/src/java/com/android/internal/telephony/cdma/SmsMessage.java
index 8459aca..2d5dda7 100644
--- a/src/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/src/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -856,7 +855,7 @@
          * Convert + code to 011 and dial out for international SMS
          */
         CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
-                PhoneNumberUtils.cdmaCheckAndProcessPlusCode(destAddrStr));
+                PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(destAddrStr));
         if (destAddr == null) return null;
 
         BearerData bearerData = new BearerData();
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 312d033..16aad87 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.content.Context;
+import android.net.NetworkConfig;
 import android.telephony.Rlog;
 
 import com.android.internal.R;
@@ -47,6 +48,8 @@
 
     private ArrayList<ApnSetting> mWaitingApns = null;
 
+    public final int priority;
+
     /** A zero indicates that all waiting APNs had a permanent error */
     private AtomicInteger mWaitingApnsPermanentFailureCountDown;
 
@@ -68,14 +71,15 @@
      */
     AtomicBoolean mDependencyMet;
 
-    public ApnContext(Context context, String apnType, String logTag) {
+    public ApnContext(Context context, String apnType, String logTag, NetworkConfig config) {
         mContext = context;
         mApnType = apnType;
         mState = DctConstants.State.IDLE;
         setReason(Phone.REASON_DATA_ENABLED);
         mDataEnabled = new AtomicBoolean(false);
-        mDependencyMet = new AtomicBoolean(true);
+        mDependencyMet = new AtomicBoolean(config.dependencyMet);
         mWaitingApnsPermanentFailureCountDown = new AtomicInteger(0);
+        priority = config.priority;
         LOG_TAG = logTag;
     }
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 517cb92..9cfed88 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -1197,7 +1197,6 @@
                                 + "RefCount=" + mApnContexts.size());
                     }
                     mInactiveState.setEnterNotificationParams(DcFailCause.LOST_CONNECTION);
-                    deferMessage(msg);
                     transitionTo(mInactiveState);
                     retVal = HANDLED;
                     break;
@@ -1474,7 +1473,6 @@
                         log("DcActiveState EVENT_DISCONNECT clearing apn contexts,"
                                 + " dc=" + DataConnection.this);
                     }
-                    mApnContexts.clear();
                     DisconnectParams dp = (DisconnectParams) msg.obj;
                     mDisconnectParams = dp;
                     mConnectionParams = null;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 2db30f9..9e6140f 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -35,6 +35,7 @@
 import android.net.ProxyProperties;
 import android.net.Uri;
 import android.os.AsyncResult;
+import android.os.Build;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.SystemClock;
@@ -190,6 +191,7 @@
 
         mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver);
         mApnContexts.clear();
+        mPrioritySortedApnContexts.clear();
 
         destroyDataConnections();
     }
@@ -230,9 +232,9 @@
     }
 
     private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
-        ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
-        apnContext.setDependencyMet(networkConfig.dependencyMet);
+        ApnContext apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG, networkConfig);
         mApnContexts.put(type, apnContext);
+        mPrioritySortedApnContexts.add(apnContext);
         return apnContext;
     }
 
@@ -596,7 +598,10 @@
     }
 
     private void setupDataOnConnectableApns(String reason) {
-        for (ApnContext apnContext : mApnContexts.values()) {
+        if (DBG) log("setupDataOnConnectableApns: " + reason);
+
+        for (ApnContext apnContext : mPrioritySortedApnContexts) {
+            if (DBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
             if (apnContext.getState() == DctConstants.State.FAILED) {
                 apnContext.setState(DctConstants.State.IDLE);
             }
@@ -608,28 +613,6 @@
         }
     }
 
-    private boolean trySetupData(String reason, String type) {
-        if (DBG) {
-            log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
-                    + " isPsRestricted=" + mIsPsRestricted);
-        }
-
-        if (type == null) {
-            type = PhoneConstants.APN_TYPE_DEFAULT;
-        }
-
-        ApnContext apnContext = mApnContexts.get(type);
-
-        if (apnContext == null ){
-            if (DBG) log("trySetupData new apn context for type:" + type);
-            apnContext = new ApnContext(mPhone.getContext(), type, LOG_TAG);
-            mApnContexts.put(type, apnContext);
-        }
-        apnContext.setReason(reason);
-
-        return trySetupData(apnContext);
-    }
-
     private boolean trySetupData(ApnContext apnContext) {
         if (DBG) {
             log("trySetupData for type:" + apnContext.getApnType() +
@@ -720,11 +703,16 @@
      * @param tearDown true if the underlying DataConnection should be
      * disconnected.
      * @param reason reason for the clean up.
+     * @return boolean - true if we did cleanup any connections, false if they
+     *                   were already all disconnected.
      */
-    protected void cleanUpAllConnections(boolean tearDown, String reason) {
+    protected boolean cleanUpAllConnections(boolean tearDown, String reason) {
         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
+        boolean didDisconnect = false;
 
         for (ApnContext apnContext : mApnContexts.values()) {
+            if (apnContext.isDisconnected() == false) didDisconnect = true;
+            // TODO - only do cleanup if not disconnected
             apnContext.setReason(reason);
             cleanUpConnection(tearDown, apnContext);
         }
@@ -734,6 +722,7 @@
 
         // TODO: Do we need mRequestedApnType?
         mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
+        return didDisconnect;
     }
 
     /**
@@ -1033,6 +1022,29 @@
             }
         }
         if (dcac == null) {
+            if (isOnlySingleDcAllowed(radioTech)) {
+                if (isHigherPriorityApnContextActive(apnContext)) {
+                    if (DBG) {
+                        log("setupData: Higher priority ApnContext active.  Ignoring call");
+                    }
+                    return false;
+                }
+
+                // Only lower priority calls left.  Disconnect them all in this single PDP case
+                // so that we can bring up the requested higher priority call (once we receive
+                // repsonse for deactivate request for the calls we are about to disconnect
+                if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
+                    // If any call actually requested to be disconnected, means we can't
+                    // bring up this connection yet as we need to wait for those data calls
+                    // to be disconnected.
+                    if (DBG) log("setupData: Some calls are disconnecting first.  Wait and retry");
+                    return false;
+                }
+
+                // No other calls are active, so proceed
+                if (DBG) log("setupData: Single pdp. Continue setting up data call.");
+            }
+
             dcac = findFreeDataConnection();
 
             if (dcac == null) {
@@ -1166,6 +1178,45 @@
         mActiveApn = null;
     }
 
+    /**
+     * "Active" here means ApnContext isEnabled() and not in FAILED state
+     * @param apnContext to compare with
+     * @return true if higher priority active apn found
+     */
+    private boolean isHigherPriorityApnContextActive(ApnContext apnContext) {
+        for (ApnContext otherContext : mPrioritySortedApnContexts) {
+            if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false;
+            if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Reports if we support multiple connections or not.
+     * This is a combination of factors, based on carrier and RAT.
+     * @param rilRadioTech the RIL Radio Tech currently in use
+     * @return true if only single DataConnection is allowed
+     */
+    private boolean isOnlySingleDcAllowed(int rilRadioTech) {
+        int[] singleDcRats = mPhone.getContext().getResources().getIntArray(
+                com.android.internal.R.array.config_onlySingleDcAllowed);
+        boolean onlySingleDcAllowed = false;
+        if (Build.IS_DEBUGGABLE &&
+                SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
+            onlySingleDcAllowed = true;
+        }
+        if (singleDcRats != null) {
+            for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) {
+                if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true;
+            }
+        }
+
+        if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed);
+        return onlySingleDcAllowed;
+    }
+
     @Override
     protected void restartRadio() {
         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
@@ -1190,10 +1241,13 @@
      * @param reason the reason why data is disconnected
      * @return true if try setup data connection is need for this reason
      */
-    private boolean retryAfterDisconnected(String reason) {
+    private boolean retryAfterDisconnected(ApnContext apnContext) {
         boolean retry = true;
+        String reason = apnContext.getReason();
 
-        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
+        if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
+                (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
+                 && isHigherPriorityApnContextActive(apnContext))) {
             retry = false;
         }
         return retry;
@@ -1505,8 +1559,9 @@
                 log("completeConnection: MOBILE_PROVISIONING_ACTION url="
                         + mProvisioningUrl);
             }
-            Intent newIntent =
-                    new Intent(Intent.ACTION_VIEW, Uri.parse(mProvisioningUrl));
+            Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
+                    Intent.CATEGORY_APP_BROWSER);
+            newIntent.setData(Uri.parse(mProvisioningUrl));
             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
                     Intent.FLAG_ACTIVITY_NEW_TASK);
             try {
@@ -1755,6 +1810,7 @@
         // pending.
         if (isDisconnected()) {
             if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
+                if(DBG) log("onDisconnectDone: radio will be turned off, no retries");
                 // Radio will be turned off. No need to retry data setup
                 apnContext.setApnSetting(null);
                 apnContext.setDataConnectionAc(null);
@@ -1763,16 +1819,29 @@
         }
 
         // If APN is still enabled, try to bring it back up automatically
-        if (mAttached.get() && apnContext.isReady()
-                && retryAfterDisconnected(apnContext.getReason())) {
+        if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
             SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
             // Wait a bit before trying the next APN, so that
             // we're not tying up the RIL command channel.
             // This also helps in any external dependency to turn off the context.
+            if(DBG) log("onDisconnectDone: attached, ready and retry after disconnect");
             startAlarmForReconnect(getApnDelay(), apnContext);
         } else {
+            boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
+                    com.android.internal.R.bool.config_restartRadioAfterProvisioning);
+
+            if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) {
+                log("onDisconnectDone: restartRadio after provisioning");
+                restartRadio();
+            }
             apnContext.setApnSetting(null);
             apnContext.setDataConnectionAc(null);
+            if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) {
+                if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
+                setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
+            } else {
+                if(DBG) log("onDisconnectDone: not retrying");
+            }
         }
     }
 
@@ -2182,7 +2251,16 @@
                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
                         mReregisterOnReconnectFailure = false;
                     }
-                    trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, PhoneConstants.APN_TYPE_DEFAULT);
+                    ApnContext apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_DEFAULT);
+                    if (apnContext != null) {
+                        apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
+                        trySetupData(apnContext);
+                    } else {
+                        loge("**** Default ApnContext not found ****");
+                        if (Build.IS_DEBUGGABLE) {
+                            throw new RuntimeException("Default ApnContext not found");
+                        }
+                    }
                 }
                 break;
 
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
index 9e7702e..a8050a6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTrackerBase.java
@@ -63,12 +63,14 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.PriorityQueue;
 
 /**
  * {@hide}
@@ -251,9 +253,19 @@
                                     new HashMap<String, Integer>();
 
     /** Phone.APN_TYPE_* ===> ApnContext */
-    protected ConcurrentHashMap<String, ApnContext> mApnContexts =
+    protected final ConcurrentHashMap<String, ApnContext> mApnContexts =
                                     new ConcurrentHashMap<String, ApnContext>();
 
+    /** kept in sync with mApnContexts
+     * Higher numbers are higher priority and sorted so highest priority is first */
+    protected final PriorityQueue<ApnContext>mPrioritySortedApnContexts =
+            new PriorityQueue<ApnContext>(5,
+            new Comparator<ApnContext>() {
+                public int compare(ApnContext c1, ApnContext c2) {
+                    return c2.priority - c1.priority;
+                }
+            } );
+
     /* Currently active APN */
     protected ApnSetting mActiveApn;
 
@@ -604,8 +616,12 @@
                 Settings.Global.TETHER_DUN_APN);
         ApnSetting dunSetting = ApnSetting.fromString(apnData);
         if (dunSetting != null) {
-            if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
-            return dunSetting;
+            IccRecords r = mIccRecords.get();
+            String operator = (r != null) ? r.getOperatorNumeric() : "";
+            if (dunSetting.numeric.equals(operator)) {
+                if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
+                return dunSetting;
+            }
         }
 
         apnData = c.getResources().getString(R.string.config_tether_apndata);
diff --git a/src/java/com/android/internal/telephony/gsm/GSMPhone.java b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
index 97cf994..2b435b5 100644
--- a/src/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/src/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -119,8 +118,6 @@
     private String mImeiSv;
     private String mVmNumber;
 
-    GsmInboundSmsHandler mGsmInboundSmsHandler;
-
     // Create Cfu (Call forward unconditional) so that dialling number &
     // mOnComplete (Message object passed by client) can be packed &
     // given as a single Cfu object as user data to RIL.
@@ -216,7 +213,12 @@
     @Override
     public ServiceState
     getServiceState() {
-        return mSST.mSS;
+        if (mSST != null) {
+            return mSST.mSS;
+        } else {
+            // avoid potential NPE in EmergencyCallHelper during Phone switch
+            return new ServiceState();
+        }
     }
 
     @Override
@@ -714,7 +716,7 @@
     public boolean handlePinMmi(String dialString) {
         GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
 
-        if (mmi != null && mmi.isPinCommand()) {
+        if (mmi != null && mmi.isPinPukCommand()) {
             mPendingMMIs.add(mmi);
             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
             mmi.processCode();
diff --git a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java b/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
index de98458..6671a58 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
@@ -42,11 +42,8 @@
     private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
             new HashMap<SmsCbConcatInfo, byte[][]>(4);
 
-    private final PhoneBase mPhone;
-
     protected GsmCellBroadcastHandler(Context context, PhoneBase phone) {
-        super("GsmCellBroadcastHandler", context);
-        mPhone = phone;
+        super("GsmCellBroadcastHandler", context, phone);
         phone.mCi.setOnNewGsmBroadcastSms(getHandler(), EVENT_NEW_SMS_MESSAGE, null);
     }
 
diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
index 2c63bf0..7e48cc2 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java
@@ -38,20 +38,14 @@
     /** Handler for SMS-PP data download messages to UICC. */
     private final UsimDataDownloadHandler mDataDownloadHandler;
 
-    private final GsmCellBroadcastHandler mCellBroadcastDispatcher;
-
-    private final PhoneBase mPhone;
-
     /**
      * Create a new GSM inbound SMS handler.
      */
     private GsmInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor,
             PhoneBase phone) {
-        super("GsmInboundSmsHandler", context, storageMonitor);
-        mPhone = phone;
+        super("GsmInboundSmsHandler", context, storageMonitor, phone,
+                GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context, phone));
         phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null);
-        mCellBroadcastDispatcher = GsmCellBroadcastHandler.makeGsmCellBroadcastHandler(context,
-                phone);
         mDataDownloadHandler = new UsimDataDownloadHandler(phone.mCi);
     }
 
@@ -61,7 +55,7 @@
     @Override
     protected void onQuitting() {
         mPhone.mCi.unSetOnNewGsmSms(getHandler());
-        mCellBroadcastDispatcher.dispose();
+        mCellBroadcastHandler.dispose();
 
         if (DBG) log("unregistered for 3GPP SMS");
         super.onQuitting();     // release wakelock
@@ -147,6 +141,22 @@
     }
 
     /**
+     * Called when the phone changes the default method updates mPhone
+     * mStorageMonitor and mCellBroadcastHandler.updatePhoneObject.
+     * Override if different or other behavior is desired.
+     *
+     * @param phone
+     */
+    @Override
+    protected void onUpdatePhoneObject(PhoneBase phone) {
+        super.onUpdatePhoneObject(phone);
+        log("onUpdatePhoneObject: dispose of old CellBroadcastHandler and make a new one");
+        mCellBroadcastHandler.dispose();
+        mCellBroadcastHandler = GsmCellBroadcastHandler
+                .makeGsmCellBroadcastHandler(mContext, phone);
+    }
+
+    /**
      * Convert Android result code to 3GPP SMS failure cause.
      * @param rc the Android SMS intent result value
      * @return 0 for success, or a 3GPP SMS failure cause value
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index f41391d..c2bafbe 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -564,7 +564,7 @@
     /**
      * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
      */
-    boolean isPinCommand() {
+    boolean isPinPukCommand() {
         return mSc != null && (mSc.equals(SC_PIN) || mSc.equals(SC_PIN2)
                               || mSc.equals(SC_PUK) || mSc.equals(SC_PUK2));
      }
@@ -779,43 +779,53 @@
                 } else {
                     throw new RuntimeException ("Invalid or Unsupported MMI Code");
                 }
-            } else if (isPinCommand()) {
+            } else if (isPinPukCommand()) {
+                // TODO: This is the same as the code in CmdaMmiCode.java,
+                // MmiCode should be an abstract or base class and this and
+                // other common variables and code should be promoted.
+
                 // sia = old PIN or PUK
                 // sib = new PIN
                 // sic = new PIN
                 String oldPinOrPuk = mSia;
-                String newPin = mSib;
-                int pinLen = newPin.length();
+                String newPinOrPuk = mSib;
+                int pinLen = newPinOrPuk.length();
                 if (isRegister()) {
-                    if (!newPin.equals(mSic)) {
+                    if (!newPinOrPuk.equals(mSic)) {
                         // password mismatch; return error
                         handlePasswordError(com.android.internal.R.string.mismatchPin);
                     } else if (pinLen < 4 || pinLen > 8 ) {
                         // invalid length
                         handlePasswordError(com.android.internal.R.string.invalidPin);
-                    } else if (mSc.equals(SC_PIN) &&
-                               mUiccApplication != null &&
-                               mUiccApplication.getState() == AppState.APPSTATE_PUK ) {
+                    } else if (mSc.equals(SC_PIN)
+                            && mUiccApplication != null
+                            && mUiccApplication.getState() == AppState.APPSTATE_PUK) {
                         // Sim is puk-locked
                         handlePasswordError(com.android.internal.R.string.needPuk);
-                    } else {
-                        // pre-checks OK
+                    } else if (mUiccApplication != null) {
+                        Rlog.d(LOG_TAG, "process mmi service code using UiccApp sc=" + mSc);
+
+                        // We have an app and the pre-checks are OK
                         if (mSc.equals(SC_PIN)) {
-                            mPhone.mCi.changeIccPin(oldPinOrPuk, newPin,
+                            mUiccApplication.changeIccLockPassword(oldPinOrPuk, newPinOrPuk,
                                     obtainMessage(EVENT_SET_COMPLETE, this));
                         } else if (mSc.equals(SC_PIN2)) {
-                            mPhone.mCi.changeIccPin2(oldPinOrPuk, newPin,
+                            mUiccApplication.changeIccFdnPassword(oldPinOrPuk, newPinOrPuk,
                                     obtainMessage(EVENT_SET_COMPLETE, this));
                         } else if (mSc.equals(SC_PUK)) {
-                            mPhone.mCi.supplyIccPuk(oldPinOrPuk, newPin,
+                            mUiccApplication.supplyPuk(oldPinOrPuk, newPinOrPuk,
                                     obtainMessage(EVENT_SET_COMPLETE, this));
                         } else if (mSc.equals(SC_PUK2)) {
-                            mPhone.mCi.supplyIccPuk2(oldPinOrPuk, newPin,
+                            mUiccApplication.supplyPuk2(oldPinOrPuk, newPinOrPuk,
                                     obtainMessage(EVENT_SET_COMPLETE, this));
+                        } else {
+                            throw new RuntimeException("uicc unsupported service code=" + mSc);
                         }
+                    } else {
+                        throw new RuntimeException("No application mUiccApplicaiton is null");
                     }
                 } else {
-                    throw new RuntimeException ("Invalid or Unsupported MMI Code");
+                    throw new RuntimeException ("Ivalid register/action=" + mAction);
                 }
             } else if (mPoundString != null) {
                 sendUssd(mPoundString);
@@ -904,7 +914,7 @@
             case EVENT_SET_COMPLETE:
                 ar = (AsyncResult) (msg.obj);
 
-                onSetComplete(ar);
+                onSetComplete(msg, ar);
                 break;
 
             case EVENT_SET_CFF_COMPLETE:
@@ -921,7 +931,7 @@
                     }
                 }
 
-                onSetComplete(ar);
+                onSetComplete(msg, ar);
                 break;
 
             case EVENT_GET_CLIR_COMPLETE:
@@ -990,7 +1000,7 @@
                 return mContext.getText(com.android.internal.R.string.PwdMmi);
             } else if (mSc.equals(SC_WAIT)) {
                 return mContext.getText(com.android.internal.R.string.CwMmi);
-            } else if (isPinCommand()) {
+            } else if (isPinPukCommand()) {
                 return mContext.getText(com.android.internal.R.string.PinMmi);
             }
         }
@@ -999,7 +1009,7 @@
     }
 
     private void
-    onSetComplete(AsyncResult ar){
+    onSetComplete(Message msg, AsyncResult ar){
         StringBuilder sb = new StringBuilder(getScString());
         sb.append("\n");
 
@@ -1008,7 +1018,7 @@
             if (ar.exception instanceof CommandException) {
                 CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
                 if (err == CommandException.Error.PASSWORD_INCORRECT) {
-                    if (isPinCommand()) {
+                    if (isPinPukCommand()) {
                         // look specifically for the PUK commands and adjust
                         // the message accordingly.
                         if (mSc.equals(SC_PUK) || mSc.equals(SC_PUK2)) {
@@ -1018,6 +1028,18 @@
                             sb.append(mContext.getText(
                                     com.android.internal.R.string.badPin));
                         }
+                        // Get the No. of retries remaining to unlock PUK/PUK2
+                        int attemptsRemaining = msg.arg1;
+                        if (attemptsRemaining <= 0) {
+                            Rlog.d(LOG_TAG, "onSetComplete: PUK locked,"
+                                    + " cancel as lock screen will handle this");
+                            mState = State.CANCELLED;
+                        } else if (attemptsRemaining > 0) {
+                            Rlog.d(LOG_TAG, "onSetComplete: attemptsRemaining="+attemptsRemaining);
+                            sb.append(mContext.getResources().getQuantityString(
+                                    com.android.internal.R.plurals.pinpuk_attempts,
+                                    attemptsRemaining, attemptsRemaining));
+                        }
                     } else {
                         sb.append(mContext.getText(
                                 com.android.internal.R.string.passwordIncorrect));
@@ -1028,6 +1050,10 @@
                     sb.append("\n");
                     sb.append(mContext.getText(
                             com.android.internal.R.string.needPuk2));
+                } else if (err == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+                    if (mSc.equals(SC_PIN)) {
+                        sb.append(mContext.getText(com.android.internal.R.string.enablePin));
+                    }
                 } else if (err == CommandException.Error.FDN_CHECK_FAILURE) {
                     Rlog.i(LOG_TAG, "FDN_CHECK_FAILURE");
                     sb.append(mContext.getText(com.android.internal.R.string.mmiFdnError));
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 4520d70..345abba 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -28,11 +27,11 @@
 import android.telephony.Rlog;
 
 import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.ImsSMSDispatcher;
+import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.SMSDispatcher;
 import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.ImsSMSDispatcher;
-import com.android.internal.telephony.InboundSmsHandler;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsStorageMonitor;
 import com.android.internal.telephony.SmsUsageMonitor;
@@ -51,7 +50,6 @@
 public final class GsmSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "GsmSMSDispatcher";
     private static final boolean VDBG = false;
-    private ImsSMSDispatcher mImsSMSDispatcher;
     protected UiccController mUiccController = null;
     private AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
     private AtomicReference<UiccCardApplication> mUiccApplication =
@@ -61,13 +59,14 @@
     /** Status report received */
     private static final int EVENT_NEW_SMS_STATUS_REPORT = 100;
 
-    public GsmSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
-            SmsUsageMonitor usageMonitor, ImsSMSDispatcher imsSMSDispatcher,
+    public GsmSMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
+            ImsSMSDispatcher imsSMSDispatcher,
             GsmInboundSmsHandler gsmInboundSmsHandler) {
-        super(phone, usageMonitor);
+        super(phone, usageMonitor, imsSMSDispatcher);
         mCi.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
-        mImsSMSDispatcher = imsSMSDispatcher;
         mGsmInboundSmsHandler = gsmInboundSmsHandler;
+        mUiccController = UiccController.getInstance();
+        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
         Rlog.d(TAG, "GsmSMSDispatcher created");
     }
 
@@ -75,6 +74,7 @@
     public void dispose() {
         super.dispose();
         mCi.unSetOnSmsStatus(this);
+        mUiccController.unregisterForIccChanged(this);
     }
 
     @Override
@@ -155,8 +155,8 @@
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, destPort, data, (deliveryIntent != null));
         if (pdu != null) {
-            HashMap map =  SmsTrackerMapFactory(destAddr, scAddr, destPort, data, pdu);
-            SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent,
+            HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
+            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,
                     getFormat());
             sendRawPdu(tracker);
         } else {
@@ -171,8 +171,8 @@
         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                 scAddr, destAddr, text, (deliveryIntent != null));
         if (pdu != null) {
-            HashMap map =  SmsTrackerMapFactory(destAddr, scAddr, text, pdu);
-            SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent,
+            HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
+            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,
                     getFormat());
             sendRawPdu(tracker);
         } else {
@@ -196,9 +196,9 @@
                 message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
                 encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
         if (pdu != null) {
-            HashMap map =  SmsTrackerMapFactory(destinationAddress, scAddress,
+            HashMap map =  getSmsTrackerMap(destinationAddress, scAddress,
                     message, pdu);
-            SmsTracker tracker = SmsTrackerFactory(map, sentIntent,
+            SmsTracker tracker = getSmsTracker(map, sentIntent,
                     deliveryIntent, getFormat());
             sendRawPdu(tracker);
         } else {
@@ -263,12 +263,6 @@
         }
     }
 
-    @Override
-    public void sendRetrySms(SmsTracker tracker) {
-        //re-routing to ImsSMSDispatcher
-        mImsSMSDispatcher.sendRetrySms(tracker);
-    }
-
     protected UiccCardApplication getUiccCardApplication() {
         return mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
     }
@@ -300,14 +294,4 @@
             }
         }
     }
-
-    @Override
-    public boolean isIms() {
-        return mImsSMSDispatcher.isIms();
-    }
-
-    @Override
-    public String getImsSmsFormat() {
-        return mImsSMSDispatcher.getImsSmsFormat();
-    }
 }
diff --git a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 5884aeb..0b75d49 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -1367,8 +1367,6 @@
         for (String numeric : numericArray) {
             if (operatorNumeric.startsWith(numeric))
                 return true;
-            else
-                return false;
         }
         return false;
     }
diff --git a/src/java/com/android/internal/telephony/gsm/SmsMessage.java b/src/java/com/android/internal/telephony/gsm/SmsMessage.java
index 6d5ecd9..48d76c5 100644
--- a/src/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/src/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
@@ -558,8 +557,9 @@
             try {
                 ret = new GsmSmsAddress(mPdu, mCur, lengthBytes);
             } catch (ParseException e) {
-                Rlog.e(LOG_TAG, e.getMessage());
                 ret = null;
+                //This is caught by createFromPdu(byte[] pdu)
+                throw new RuntimeException(e.getMessage());
             }
 
             mCur += lengthBytes;
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 3fc4e85..49c9933 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2010 The Android Open Source Project
- * Copyright (c) 2012-13, The Linux Foundation. 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.
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 28e4d64..d4d012e 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
index 733af64..c512ecf 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
@@ -604,8 +604,9 @@
     @Override
     public boolean getIccLockEnabled() {
         synchronized (mLock) {
-            /* defaults to true, if ICC is absent */
-            Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccLockEnabled() : true;
+            /* defaults to false, if ICC is absent/deactivated */
+            Boolean retValue = mUiccApplication != null ?
+                    mUiccApplication.getIccLockEnabled() : false;
             return retValue;
         }
     }
@@ -613,11 +614,29 @@
     @Override
     public boolean getIccFdnEnabled() {
         synchronized (mLock) {
-            Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnEnabled() : false;
+            Boolean retValue = mUiccApplication != null ?
+                    mUiccApplication.getIccFdnEnabled() : false;
             return retValue;
         }
     }
 
+    public boolean getIccFdnAvailable() {
+        boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false;
+        return retValue;
+    }
+
+    public boolean getIccPin2Blocked() {
+        /* defaults to disabled */
+        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
+        return retValue;
+    }
+
+    public boolean getIccPuk2Blocked() {
+        /* defaults to disabled */
+        Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
+        return retValue;
+    }
+
     @Override
     public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
         synchronized (mLock) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
index 0715b0e..d125dbe 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
@@ -40,10 +40,14 @@
     private static final String LOG_TAG = "UiccCardApplication";
     private static final boolean DBG = true;
 
-    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 1;
-    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 2;
-    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 3;
-    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 4;
+    private static final int EVENT_PIN1_PUK1_DONE = 1;
+    private static final int EVENT_CHANGE_PIN1_DONE = 2;
+    private static final int EVENT_CHANGE_PIN2_DONE = 3;
+    private static final int EVENT_QUERY_FACILITY_FDN_DONE = 4;
+    private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 5;
+    private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 6;
+    private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 7;
+    private static final int EVENT_PIN2_PUK2_DONE = 8;
 
     private final Object  mLock = new Object();
     private UiccCard      mUiccCard; //parent
@@ -59,6 +63,7 @@
     private boolean       mDesiredFdnEnabled;
     private boolean       mIccLockEnabled;
     private boolean       mDesiredPinLocked;
+    private boolean       mIccFdnAvailable = true; // Default is enabled.
 
     private CommandsInterface mCi;
     private Context mContext;
@@ -209,10 +214,18 @@
                 return;
             }
 
-            int[] ints = (int[])ar.result;
-            if(ints.length != 0) {
-                mIccFdnEnabled = (0!=ints[0]);
-                if (DBG) log("Query facility lock : "  + mIccFdnEnabled);
+            int[] result = (int[])ar.result;
+            if(result.length != 0) {
+                //0 - Available & Disabled, 1-Available & Enabled, 2-Unavailable.
+                if (result[0] == 2) {
+                    mIccFdnEnabled = false;
+                    mIccFdnAvailable = false;
+                } else {
+                    mIccFdnEnabled = (result[0] == 1) ? true : false;
+                    mIccFdnAvailable = true;
+                }
+                log("Query facility FDN : FDN service available: "+ mIccFdnAvailable
+                        +" enabled: "  + mIccFdnEnabled);
             } else {
                 loge("Bogus facility lock response");
             }
@@ -221,14 +234,18 @@
 
     private void onChangeFdnDone(AsyncResult ar) {
         synchronized (mLock) {
+            int attemptsRemaining = -1;
+
             if (ar.exception == null) {
                 mIccFdnEnabled = mDesiredFdnEnabled;
                 if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
                         "mIccFdnEnabled=" + mIccFdnEnabled);
             } else {
+                attemptsRemaining = parsePinPukErrorResult(ar);
                 loge("Error change facility fdn with exception " + ar.exception);
             }
             Message response = (Message)ar.userObj;
+            response.arg1 = attemptsRemaining;
             AsyncResult.forMessage(response).exception = ar.exception;
             response.sendToTarget();
         }
@@ -297,15 +314,38 @@
     /** REMOVE when mIccLockEnabled is not needed */
     private void onChangeFacilityLock(AsyncResult ar) {
         synchronized (mLock) {
+            int attemptsRemaining = -1;
+
             if (ar.exception == null) {
                 mIccLockEnabled = mDesiredPinLocked;
                 if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
                         + mIccLockEnabled);
             } else {
+                attemptsRemaining = parsePinPukErrorResult(ar);
                 loge("Error change facility lock with exception " + ar.exception);
             }
-            AsyncResult.forMessage(((Message)ar.userObj)).exception = ar.exception;
-            ((Message)ar.userObj).sendToTarget();
+            Message response = (Message)ar.userObj;
+            AsyncResult.forMessage(response).exception = ar.exception;
+            response.arg1 = attemptsRemaining;
+            response.sendToTarget();
+        }
+    }
+
+    /**
+     * Parse the error response to obtain number of attempts remaining
+     */
+    private int parsePinPukErrorResult(AsyncResult ar) {
+        int[] result = (int[]) ar.result;
+        if (result == null) {
+            return -1;
+        } else {
+            int length = result.length;
+            int attemptsRemaining = -1;
+            if (length > 0) {
+                attemptsRemaining = result[0];
+            }
+            log("parsePinPukErrorResult: attemptsRemaining=" + attemptsRemaining);
+            return attemptsRemaining;
         }
     }
 
@@ -321,6 +361,22 @@
             }
 
             switch (msg.what) {
+                case EVENT_PIN1_PUK1_DONE:
+                case EVENT_PIN2_PUK2_DONE:
+                case EVENT_CHANGE_PIN1_DONE:
+                case EVENT_CHANGE_PIN2_DONE:
+                    // a PIN/PUK/PIN2/PUK2 complete
+                    // request has completed. ar.userObj is the response Message
+                    int attemptsRemaining = -1;
+                    ar = (AsyncResult)msg.obj;
+                    if ((ar.exception != null) && (ar.result != null)) {
+                        attemptsRemaining = parsePinPukErrorResult(ar);
+                    }
+                    Message response = (Message)ar.userObj;
+                    AsyncResult.forMessage(response).exception = ar.exception;
+                    response.arg1 = attemptsRemaining;
+                    response.sendToTarget();
+                    break;
                 case EVENT_QUERY_FACILITY_FDN_DONE:
                     ar = (AsyncResult)msg.obj;
                     onQueryFdnEnabled(ar);
@@ -520,6 +576,34 @@
      * Handler.
      *
      * onComplete.obj will be an AsyncResult
+     * onComplete.arg1 = remaining attempts before puk locked or -1 if unknown
+     *
+     * ((AsyncResult)onComplete.obj).exception == null on success
+     * ((AsyncResult)onComplete.obj).exception != null on fail
+     *
+     * If the supplied PIN is incorrect:
+     * ((AsyncResult)onComplete.obj).exception != null
+     * && ((AsyncResult)onComplete.obj).exception
+     *       instanceof com.android.internal.telephony.gsm.CommandException)
+     * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
+     *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
+     */
+    public void supplyPin (String pin, Message onComplete) {
+        synchronized (mLock) {
+            mCi.supplyIccPinForApp(pin, mAid, mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE,
+                    onComplete));
+        }
+    }
+
+    /**
+     * Supply the ICC PUK to the ICC
+     *
+     * When the operation is complete, onComplete will be sent to its
+     * Handler.
+     *
+     * onComplete.obj will be an AsyncResult
+     * onComplete.arg1 = remaining attempts before Icc will be permanently unusable
+     * or -1 if unknown
      *
      * ((AsyncResult)onComplete.obj).exception == null on success
      * ((AsyncResult)onComplete.obj).exception != null on fail
@@ -533,27 +617,24 @@
      *
      *
      */
-    public void supplyPin (String pin, Message onComplete) {
-        synchronized (mLock) {
-            mCi.supplyIccPin(pin, onComplete);
-        }
-    }
-
     public void supplyPuk (String puk, String newPin, Message onComplete) {
         synchronized (mLock) {
-            mCi.supplyIccPuk(puk, newPin, onComplete);
+        mCi.supplyIccPukForApp(puk, newPin, mAid,
+                mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE, onComplete));
         }
     }
 
     public void supplyPin2 (String pin2, Message onComplete) {
         synchronized (mLock) {
-            mCi.supplyIccPin2(pin2, onComplete);
+            mCi.supplyIccPin2ForApp(pin2, mAid,
+                    mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
         }
     }
 
     public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
         synchronized (mLock) {
-            mCi.supplyIccPuk2(puk2, newPin2, onComplete);
+            mCi.supplyIccPuk2ForApp(puk2, newPin2, mAid,
+                    mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
         }
     }
 
@@ -597,6 +678,15 @@
     }
 
     /**
+     * Check whether fdn (fixed dialing number) service is available.
+     * @return true if ICC fdn service available
+     *         false if ICC fdn service not available
+     */
+    public boolean getIccFdnAvailable() {
+        return mIccFdnAvailable;
+    }
+
+    /**
      * Set the ICC pin lock enabled or disabled
      * When the operation is complete, onComplete will be sent to its handler
      *
@@ -659,6 +749,7 @@
      * @param newPassword is the new password
      * @param onComplete
      *        onComplete.obj will be an AsyncResult
+     *        onComplete.arg1 = attempts remaining or -1 if unknown
      *        ((AsyncResult)onComplete.obj).exception == null on success
      *        ((AsyncResult)onComplete.obj).exception != null on fail
      */
@@ -667,7 +758,7 @@
         synchronized (mLock) {
             if (DBG) log("changeIccLockPassword");
             mCi.changeIccPinForApp(oldPassword, newPassword, mAid,
-                    onComplete);
+                    mHandler.obtainMessage(EVENT_CHANGE_PIN1_DONE, onComplete));
         }
     }
 
@@ -687,7 +778,25 @@
         synchronized (mLock) {
             if (DBG) log("changeIccFdnPassword");
             mCi.changeIccPin2ForApp(oldPassword, newPassword, mAid,
-                    onComplete);
+                    mHandler.obtainMessage(EVENT_CHANGE_PIN2_DONE, onComplete));
+        }
+    }
+
+    /**
+     * @return true if ICC card is PIN2 blocked
+     */
+    public boolean getIccPin2Blocked() {
+        synchronized (mLock) {
+            return mPin2State == PinState.PINSTATE_ENABLED_BLOCKED;
+        }
+    }
+
+    /**
+     * @return true if ICC card is PUK2 blocked
+     */
+    public boolean getIccPuk2Blocked() {
+        synchronized (mLock) {
+            return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
         }
     }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
index 72d2d62..ec6e230 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2011 The Android Open Source Project
- * Copyright (c) 2012-2013, The Linux Foundation. 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.