Adding support for parsing of SMS-CB pdus in UMTS format.
This enables RIL to dispatch pdus in both GSM or UMTS format. The RAT that was used will be transparent to clients. Change-Id: I57c53ec79496d274e18b3fee196551af97c0857d
This commit is contained in:
committed by
Johan Redestig
parent
fcf3d12d70
commit
4f95b1250f
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.telephony;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
import com.android.internal.telephony.gsm.SmsCbHeader;
|
||||
|
||||
@@ -58,10 +60,13 @@ public class SmsCbMessage {
|
||||
try {
|
||||
return new SmsCbMessage(pdu);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(LOG_TAG, "Failed parsing SMS-CB pdu", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String LOG_TAG = "SMSCB";
|
||||
|
||||
/**
|
||||
* Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
|
||||
*/
|
||||
@@ -80,6 +85,8 @@ public class SmsCbMessage {
|
||||
|
||||
private static final char CARRIAGE_RETURN = 0x0d;
|
||||
|
||||
private static final int PDU_BODY_PAGE_LENGTH = 82;
|
||||
|
||||
private SmsCbHeader mHeader;
|
||||
|
||||
private String mLanguage;
|
||||
@@ -149,6 +156,13 @@ public class SmsCbMessage {
|
||||
return mHeader.updateNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and unpack the body text according to the encoding in the DCS.
|
||||
* After completing successfully this method will have assigned the body
|
||||
* text into mBody, and optionally the language code into mLanguage
|
||||
*
|
||||
* @param pdu The pdu
|
||||
*/
|
||||
private void parseBody(byte[] pdu) {
|
||||
int encoding;
|
||||
boolean hasLanguageIndicator = false;
|
||||
@@ -221,28 +235,81 @@ public class SmsCbMessage {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mHeader.format == SmsCbHeader.FORMAT_UMTS) {
|
||||
// Payload may contain multiple pages
|
||||
int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
|
||||
|
||||
if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1)
|
||||
* nrPages) {
|
||||
throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match "
|
||||
+ nrPages + " pages");
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < nrPages; i++) {
|
||||
// Each page is 82 bytes followed by a length octet indicating
|
||||
// the number of useful octets within those 82
|
||||
int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i;
|
||||
int length = pdu[offset + PDU_BODY_PAGE_LENGTH];
|
||||
|
||||
if (length > PDU_BODY_PAGE_LENGTH) {
|
||||
throw new IllegalArgumentException("Page length " + length
|
||||
+ " exceeds maximum value " + PDU_BODY_PAGE_LENGTH);
|
||||
}
|
||||
|
||||
sb.append(unpackBody(pdu, encoding, offset, length, hasLanguageIndicator));
|
||||
}
|
||||
mBody = sb.toString();
|
||||
} else {
|
||||
// Payload is one single page
|
||||
int offset = SmsCbHeader.PDU_HEADER_LENGTH;
|
||||
int length = pdu.length - offset;
|
||||
|
||||
mBody = unpackBody(pdu, encoding, offset, length, hasLanguageIndicator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack body text from the pdu using the given encoding, position and
|
||||
* length within the pdu
|
||||
*
|
||||
* @param pdu The pdu
|
||||
* @param encoding The encoding, as derived from the DCS
|
||||
* @param offset Position of the first byte to unpack
|
||||
* @param length Number of bytes to unpack
|
||||
* @param hasLanguageIndicator true if the body text is preceded by a
|
||||
* language indicator. If so, this method will as a side-effect
|
||||
* assign the extracted language code into mLanguage
|
||||
* @return Body text
|
||||
*/
|
||||
private String unpackBody(byte[] pdu, int encoding, int offset, int length,
|
||||
boolean hasLanguageIndicator) {
|
||||
String body = null;
|
||||
|
||||
switch (encoding) {
|
||||
case SmsMessage.ENCODING_7BIT:
|
||||
mBody = GsmAlphabet.gsm7BitPackedToString(pdu, SmsCbHeader.PDU_HEADER_LENGTH,
|
||||
(pdu.length - SmsCbHeader.PDU_HEADER_LENGTH) * 8 / 7);
|
||||
body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7);
|
||||
|
||||
if (hasLanguageIndicator && mBody != null && mBody.length() > 2) {
|
||||
mLanguage = mBody.substring(0, 2);
|
||||
mBody = mBody.substring(3);
|
||||
if (hasLanguageIndicator && body != null && body.length() > 2) {
|
||||
// Language is two GSM characters followed by a CR.
|
||||
// The actual body text is offset by 3 characters.
|
||||
mLanguage = body.substring(0, 2);
|
||||
body = body.substring(3);
|
||||
}
|
||||
break;
|
||||
|
||||
case SmsMessage.ENCODING_16BIT:
|
||||
int offset = SmsCbHeader.PDU_HEADER_LENGTH;
|
||||
|
||||
if (hasLanguageIndicator && pdu.length >= SmsCbHeader.PDU_HEADER_LENGTH + 2) {
|
||||
mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu,
|
||||
SmsCbHeader.PDU_HEADER_LENGTH, 2);
|
||||
if (hasLanguageIndicator && pdu.length >= offset + 2) {
|
||||
// Language is two GSM characters.
|
||||
// The actual body text is offset by 2 bytes.
|
||||
mLanguage = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2);
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
|
||||
try {
|
||||
mBody = new String(pdu, offset, (pdu.length & 0xfffe) - offset, "utf-16");
|
||||
body = new String(pdu, offset, (length & 0xfffe), "utf-16");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Eeeek
|
||||
}
|
||||
@@ -252,16 +319,18 @@ public class SmsCbMessage {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mBody != null) {
|
||||
if (body != null) {
|
||||
// Remove trailing carriage return
|
||||
for (int i = mBody.length() - 1; i >= 0; i--) {
|
||||
if (mBody.charAt(i) != CARRIAGE_RETURN) {
|
||||
mBody = mBody.substring(0, i + 1);
|
||||
for (int i = body.length() - 1; i >= 0; i--) {
|
||||
if (body.charAt(i) != CARRIAGE_RETURN) {
|
||||
body = body.substring(0, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mBody = "";
|
||||
body = "";
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,31 @@
|
||||
package com.android.internal.telephony.gsm;
|
||||
|
||||
public class SmsCbHeader {
|
||||
/**
|
||||
* Length of SMS-CB header
|
||||
*/
|
||||
public static final int PDU_HEADER_LENGTH = 6;
|
||||
|
||||
/**
|
||||
* GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
|
||||
*/
|
||||
public static final int FORMAT_GSM = 1;
|
||||
|
||||
/**
|
||||
* UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
|
||||
*/
|
||||
public static final int FORMAT_UMTS = 2;
|
||||
|
||||
/**
|
||||
* Message type value as defined in 3gpp TS 25.324, section 11.1.
|
||||
*/
|
||||
private static final int MESSAGE_TYPE_CBS_MESSAGE = 1;
|
||||
|
||||
/**
|
||||
* Length of GSM pdus
|
||||
*/
|
||||
private static final int PDU_LENGTH_GSM = 88;
|
||||
|
||||
public final int geographicalScope;
|
||||
|
||||
public final int messageCode;
|
||||
@@ -33,27 +56,55 @@ public class SmsCbHeader {
|
||||
|
||||
public final int nrOfPages;
|
||||
|
||||
public final int format;
|
||||
|
||||
public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
|
||||
if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
|
||||
throw new IllegalArgumentException("Illegal PDU");
|
||||
}
|
||||
|
||||
geographicalScope = (pdu[0] & 0xc0) >> 6;
|
||||
messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4);
|
||||
updateNumber = pdu[1] & 0x0f;
|
||||
messageIdentifier = (pdu[2] << 8) | pdu[3];
|
||||
dataCodingScheme = pdu[4];
|
||||
if (pdu.length <= PDU_LENGTH_GSM) {
|
||||
// GSM pdus are no more than 88 bytes
|
||||
format = FORMAT_GSM;
|
||||
geographicalScope = (pdu[0] & 0xc0) >> 6;
|
||||
messageCode = ((pdu[0] & 0x3f) << 4) | ((pdu[1] & 0xf0) >> 4);
|
||||
updateNumber = pdu[1] & 0x0f;
|
||||
messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff);
|
||||
dataCodingScheme = pdu[4] & 0xff;
|
||||
|
||||
// Check for invalid page parameter
|
||||
int pageIndex = (pdu[5] & 0xf0) >> 4;
|
||||
int nrOfPages = pdu[5] & 0x0f;
|
||||
// Check for invalid page parameter
|
||||
int pageIndex = (pdu[5] & 0xf0) >> 4;
|
||||
int nrOfPages = pdu[5] & 0x0f;
|
||||
|
||||
if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
|
||||
if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
|
||||
pageIndex = 1;
|
||||
nrOfPages = 1;
|
||||
}
|
||||
|
||||
this.pageIndex = pageIndex;
|
||||
this.nrOfPages = nrOfPages;
|
||||
} else {
|
||||
// UMTS pdus are always at least 90 bytes since the payload includes
|
||||
// a number-of-pages octet and also one length octet per page
|
||||
format = FORMAT_UMTS;
|
||||
|
||||
int messageType = pdu[0];
|
||||
|
||||
if (messageType != MESSAGE_TYPE_CBS_MESSAGE) {
|
||||
throw new IllegalArgumentException("Unsupported message type " + messageType);
|
||||
}
|
||||
|
||||
messageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff;
|
||||
geographicalScope = (pdu[3] & 0xc0) >> 6;
|
||||
messageCode = ((pdu[3] & 0x3f) << 4) | ((pdu[4] & 0xf0) >> 4);
|
||||
updateNumber = pdu[4] & 0x0f;
|
||||
dataCodingScheme = pdu[5] & 0xff;
|
||||
|
||||
// We will always consider a UMTS message as having one single page
|
||||
// since there's only one instance of the header, even though the
|
||||
// actual payload may contain several pages.
|
||||
pageIndex = 1;
|
||||
nrOfPages = 1;
|
||||
}
|
||||
|
||||
this.pageIndex = pageIndex;
|
||||
this.nrOfPages = nrOfPages;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user