Manually merge a few fixes from cupcake and cupcake_dcm.

CL 144717: Correctly set user data payload length for non-7-bit encoded payload.
CL 149058: Check for null TP-OA in SmsMessage.parseMessageBody().
CL 138094: Make sure call state (and other updates) have a chance to get processed between data setup attempts.
CL 132624: Added a comment for a way to save a message to the SIM.
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index d23af1f..77755ce 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -103,9 +103,9 @@
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
     /** Default ping deadline, in seconds. */
-    protected final int DEFAULT_PING_DEADLINE = 5;
+    protected static final int DEFAULT_PING_DEADLINE = 5;
     /** Default max failure count before attempting to network re-registration. */
-    protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
+    protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
 
     /**
      * After detecting a potential connection problem, this is the max number
@@ -217,7 +217,7 @@
     }
 
     // abstract handler methods
-    protected abstract void onTrySetupData();
+    protected abstract void onTrySetupData(String reason);
     protected abstract void onRoamingOff();
     protected abstract void onRoamingOn();
     protected abstract void onRadioAvailable();
@@ -232,7 +232,11 @@
         switch (msg.what) {
 
             case EVENT_TRY_SETUP_DATA:
-                onTrySetupData();
+                String reason = null;
+                if (msg.obj instanceof String) {
+                    reason = (String)msg.obj;
+                }
+                onTrySetupData(reason);
                 break;
 
             case EVENT_ROAMING_OFF:
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 31bb652..4d32c35 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -312,7 +312,9 @@
     }
 
     protected void parseMessageBody() {
-        if (originatingAddress.couldBeEmailGateway()) {
+        // originatingAddress could be null if this message is from a status
+        // report.
+        if (originatingAddress != null && originatingAddress.couldBeEmailGateway()) {
             extractEmailAddressFromMessageBody();
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index bf58ab7..d8a6a50 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -675,7 +675,7 @@
         if (state == State.FAILED) {
             cleanUpConnection(false, null);
         }
-        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
@@ -688,8 +688,8 @@
     /**
      * @override com.android.internal.telephony.DataConnectionTracker
      */
-    protected void onTrySetupData() {
-        trySetupData(null);
+    protected void onTrySetupData(String reason) {
+        trySetupData(reason);
     }
 
     /**
@@ -769,7 +769,10 @@
             }
 
             if (tryAgain(cause)) {
-                    trySetupData(reason);
+                // Wait a bit before trying again, so that
+                // we're not tying up the RIL command channel
+                sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+                        RECONNECT_DELAY_INITIAL_MILLIS);
             } else {
                 startDelayedRetry(cause, reason);
             }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 49e2daf..1d918a3 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -585,8 +585,7 @@
         if ((state == State.IDLE || state == State.SCANNING)
                 && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
                 && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded()
-                && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() ||
-                     phone.getState() == Phone.State.IDLE )
+                && phone.getState() == Phone.State.IDLE
                 && isDataAllowed()
                 && !mIsPsRestricted
                 && desiredPowerState ) {
@@ -1221,7 +1220,7 @@
         if (state == State.FAILED) {
             cleanUpConnection(false, null);
         }
-        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onEnableNewApn() {
@@ -1230,8 +1229,8 @@
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
-    protected void onTrySetupData() {
-        trySetupData(null);
+    protected void onTrySetupData(String reason) {
+        trySetupData(reason);
     }
 
     protected void onRestoreDefaultApn() {
@@ -1363,7 +1362,10 @@
                 } else {
                     // we still have more apns to try
                     setState(State.SCANNING);
-                    trySetupData(reason);
+                    // Wait a bit before trying the next APN, so that
+                    // we're not tying up the RIL command channel
+                    sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+                            RECONNECT_DELAY_INITIAL_MILLIS);
                 }
             } else {
                 startDelayedRetry(cause, reason);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index ed61c3f..bfdd8a7 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -250,6 +250,12 @@
 
             // TP-Data-Coding-Scheme
             // Default encoding, uncompressed
+            // To test writing messages to the SIM card, change this value 0x00
+            // to 0x12, which means "bits 1 and 0 contain message class, and the
+            // class is 2". Note that this takes effect for the sender. In other
+            // words, messages sent by the phone with this change will end up on
+            // the receiver's SIM card. You can then send messages to yourself
+            // (on a phone with this change) and they'll end up on the SIM card.
             bo.write(0x00);
 
             // (no TP-Validity-Period)
@@ -558,9 +564,10 @@
             int offset = cur;
             int userDataLength = pdu[offset++] & 0xff;
             int headerSeptets = 0;
+            int userDataHeaderLength = 0;
 
             if (hasUserDataHeader) {
-                int userDataHeaderLength = pdu[offset++] & 0xff;
+                userDataHeaderLength = pdu[offset++] & 0xff;
 
                 byte[] udh = new byte[userDataHeaderLength];
                 System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength);
@@ -573,19 +580,34 @@
                 mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
             }
 
-            /*
-             * Here we just create the user data length to be the remainder of
-             * the pdu minus the user data hearder. This is because the count
-             * could mean the number of uncompressed sepets if the userdata is
-             * encoded in 7-bit.
-             */
-            userData = new byte[pdu.length - offset];
+            int bufferLen;
+            if (dataInSeptets) {
+                /*
+                 * Here we just create the user data length to be the remainder of
+                 * the pdu minus the user data header, since userDataLength means
+                 * the number of uncompressed sepets.
+                 */
+                bufferLen = pdu.length - offset;
+            } else {
+                /*
+                 * userDataLength is the count of octets, so just subtract the
+                 * user data header.
+                 */
+                bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0);
+                if (bufferLen < 0) {
+                    bufferLen = 0;
+                }
+            }
+
+            userData = new byte[bufferLen];
             System.arraycopy(pdu, offset, userData, 0, userData.length);
             cur = offset;
 
             if (dataInSeptets) {
                 // Return the number of septets
-                return userDataLength - headerSeptets;
+                int count = userDataLength - headerSeptets;
+                // If count < 0, return 0 (means UDL was probably incorrect)
+                return count < 0 ? 0 : count;
             } else {
                 // Return the number of octets
                 return userData.length;