Fix CDMA SMS delivery status reporting.

CDMA SMS status reports are messages with bearer data message type
DELIVERY_ACK.  Identify these messages after parsing during demux,
update the deliveryPendingList and generate a RESULT_OK intent in the
same manner as GSM.

Addresses issue:
http://buganizer/issue?id=2047571

Change-Id: Ia38718b0bb169a0f3398f50c27a95e8bce7e4c99
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index bf42257..623d985 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -21,6 +21,7 @@
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.ContentValues;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -73,6 +74,23 @@
         Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
     }
 
+    private void handleCdmaStatusReport(SmsMessage sms) {
+        for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
+            SmsTracker tracker = deliveryPendingList.get(i);
+            if (tracker.mMessageRef == sms.messageRef) {
+                // Found it.  Remove from list and broadcast.
+                deliveryPendingList.remove(i);
+                PendingIntent intent = tracker.mDeliveryIntent;
+                Intent fillIn = new Intent();
+                fillIn.putExtra("pdu", sms.getPdu());
+                try {
+                    intent.send(mContext, Activity.RESULT_OK, fillIn);
+                } catch (CanceledException ex) {}
+                break;  // Only expect to see one tracker matching this message.
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     protected int dispatchMessage(SmsMessageBase smsb) {
 
@@ -105,6 +123,11 @@
             editor.commit();
             ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
             handled = true;
+        } else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
+                (SmsEnvelope.TELESERVICE_WEMT == teleService)) &&
+                sms.isStatusReportMessage()) {
+            handleCdmaStatusReport(sms);
+            handled = true;
         } else if ((sms.getUserData() == null)) {
             if (Config.LOGD) {
                 Log.d(TAG, "Received SMS without user data");
@@ -354,8 +377,12 @@
             uData.payloadStr = parts.get(i);
             uData.userDataHeader = smsHeader;
 
+            /* By setting the statusReportRequested bit only for the
+             * last message fragment, this will result in only one
+             * callback to the sender when that last fragment delivery
+             * has been acknowledged. */
             SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr,
-                    uData, deliveryIntent != null);
+                    uData, (deliveryIntent != null) && (i == (msgCount - 1)));
 
             sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index d17468c..165d583 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -424,12 +424,9 @@
         return (status << 16);
     }
 
-    /**
-     *  Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
+    /** Return true iff the bearer data message type is DELIVERY_ACK. */
     public boolean isStatusReportMessage() {
-        Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode.");
-        return false;
+        return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
     }
 
     /**
@@ -548,17 +545,6 @@
             messageBody = mBearerData.userData.payloadStr;
         }
 
-        // TP-Message-Type-Indicator (See 3GPP2 C.S0015-B, v2, 4.5.1)
-        switch (mBearerData.messageType) {
-        case BearerData.MESSAGE_TYPE_USER_ACK:
-        case BearerData.MESSAGE_TYPE_READ_ACK:
-        case BearerData.MESSAGE_TYPE_DELIVER:
-        case BearerData.MESSAGE_TYPE_DELIVERY_ACK:
-            break;
-        default:
-            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
-        }
-
         if (originatingAddress != null) {
             originatingAddress.address = new String(originatingAddress.origBytes);
             if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
@@ -571,11 +557,26 @@
 
         if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
 
-        // TODO(Teleca): do we really want this test to occur only for DELIVERY_ACKs?
-        if ((mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) &&
-                (mBearerData.errorClass != BearerData.ERROR_UNDEFINED)) {
-            status = mBearerData.errorClass << 8;
-            status |= mBearerData.messageStatus;
+        // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1)
+        if (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) {
+            // The BearerData MsgStatus subparameter should only be
+            // included for DELIVERY_ACK messages.  If it occurred for
+            // other messages, it would be unclear what the status
+            // being reported refers to.  The MsgStatus subparameter
+            // is primarily useful to indicate error conditions -- a
+            // message without this subparameter is assumed to
+            // indicate successful delivery (status == 0).
+            if (! mBearerData.messageStatusSet) {
+                Log.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" +
+                        (userData == null ? "also missing" : "does have") +
+                        " userData).");
+                status = 0;
+            } else {
+                status = mBearerData.errorClass << 8;
+                status |= mBearerData.messageStatus;
+            }
+        } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) {
+            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
         }
 
         if (messageBody != null) {