Loading telephony/java/android/telephony/SmsCbMessage.java +85 −16 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.telephony; import android.util.Log; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SmsCbHeader; Loading Loading @@ -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. */ Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 } Loading @@ -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; } } telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +63 −12 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -33,16 +56,21 @@ 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"); } 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] << 8) | pdu[3]; dataCodingScheme = pdu[4]; messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); dataCodingScheme = pdu[4] & 0xff; // Check for invalid page parameter int pageIndex = (pdu[5] & 0xf0) >> 4; Loading @@ -55,5 +83,28 @@ public class SmsCbHeader { 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; } } } telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java +364 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
telephony/java/android/telephony/SmsCbMessage.java +85 −16 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package android.telephony; import android.util.Log; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SmsCbHeader; Loading Loading @@ -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. */ Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 } Loading @@ -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; } }
telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java +63 −12 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -33,16 +56,21 @@ 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"); } 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] << 8) | pdu[3]; dataCodingScheme = pdu[4]; messageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff); dataCodingScheme = pdu[4] & 0xff; // Check for invalid page parameter int pageIndex = (pdu[5] & 0xf0) >> 4; Loading @@ -55,5 +83,28 @@ public class SmsCbHeader { 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; } } }
telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsCbTest.java +364 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes