Add cleaned up unit tests moved from platform am: 35ef4b5382
am: 8acff00705
Change-Id: I6f3a572c8ddf2ef119552ac44223f3c981ada8d4
diff --git a/src/com/android/cellbroadcastservice/BearerData.java b/src/com/android/cellbroadcastservice/BearerData.java
index 6ebd041..cc7a155 100644
--- a/src/com/android/cellbroadcastservice/BearerData.java
+++ b/src/com/android/cellbroadcastservice/BearerData.java
@@ -66,6 +66,13 @@
public static final int LANGUAGE_HEBREW = 0x07;
/**
+ * Supported message types for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
+ * Used for CdmaSmsCbTest.
+ */
+ public static final int MESSAGE_TYPE_DELIVER = 0x01;
+
+ /**
* 16-bit value indicating the message ID, which increments modulo 65536.
* (Special rules apply for WAP-messages.)
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
diff --git a/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java b/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
index fdf3b4a..15e550b 100644
--- a/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
+++ b/src/com/android/cellbroadcastservice/DefaultCellBroadcastService.java
@@ -26,6 +26,8 @@
import android.telephony.cdma.CdmaSmsCbProgramData;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -76,7 +78,8 @@
} else {
plmn = "";
}
- SmsCbMessage message = parseBroadcastSms(slotIndex, plmn, bearerData, serviceCategory);
+ SmsCbMessage message = parseBroadcastSms(getApplicationContext(), slotIndex, plmn,
+ bearerData, serviceCategory);
if (message != null) {
mCdmaCellBroadcastHandler.onCdmaCellBroadcastSms(message);
}
@@ -90,7 +93,6 @@
originatingAddress, callback);
}
-
/**
* Parses a CDMA broadcast SMS
*
@@ -99,9 +101,11 @@
* @param bearerData the bearerData of the SMS
* @param serviceCategory the service category of the broadcast
*/
- private SmsCbMessage parseBroadcastSms(int slotIndex, String plmn, byte[] bearerData,
+ @VisibleForTesting
+ public static SmsCbMessage parseBroadcastSms(Context context, int slotIndex, String plmn,
+ byte[] bearerData,
int serviceCategory) {
- BearerData bData = BearerData.decode(getApplicationContext(), bearerData, serviceCategory);
+ BearerData bData = BearerData.decode(context, bearerData, serviceCategory);
if (bData == null) {
Log.w(TAG, "BearerData.decode() returned null");
return null;
diff --git a/tests/src/com/android/cellbroadcastservice/CdmaSmsMessageTest.java b/tests/src/com/android/cellbroadcastservice/CdmaSmsMessageTest.java
new file mode 100644
index 0000000..e24dbd5
--- /dev/null
+++ b/tests/src/com/android/cellbroadcastservice/CdmaSmsMessageTest.java
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cellbroadcastservice;
+
+import android.content.Context;
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.telephony.SmsCbCmasInfo;
+import android.telephony.SmsCbMessage;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.Log;
+
+import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.cdma.SmsMessage;
+import com.android.internal.telephony.cdma.SmsMessageConverter;
+import com.android.internal.util.BitwiseOutputStream;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Test cases to verify that our parseBroadcastSms function correctly works with the
+ * CdmaSmsMessage class.
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class CdmaSmsMessageTest extends CellBroadcastServiceTestBase {
+
+ private static final String TAG = "CdmaSmsMessageTest";
+
+ /* Copy of private subparameter identifier constants from BearerData class. */
+ private static final byte SUBPARAM_MESSAGE_IDENTIFIER = (byte) 0x00;
+ private static final byte SUBPARAM_USER_DATA = (byte) 0x01;
+ private static final byte SUBPARAM_PRIORITY_INDICATOR = (byte) 0x08;
+ private static final byte SUBPARAM_LANGUAGE_INDICATOR = (byte) 0x0D;
+ private static final byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12;
+
+ private static final int TELESERVICE_NOT_SET = 0x0000;
+ private static final int TELESERVICE_SCPT = 0x1006;
+
+ /**
+ * Digit Mode Indicator is a 1-bit value that indicates whether
+ * the address digits are 4-bit DTMF codes or 8-bit codes. (See
+ * 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ private static final int DIGIT_MODE_4BIT_DTMF = 0x00;
+ private static final int DIGIT_MODE_8BIT_CHAR = 0x01;
+
+ /**
+ * Number Mode Indicator is 1-bit value that indicates whether the
+ * address type is a data network address or not. (See 3GPP2
+ * C.S0015-B, v2, 3.4.3.3)
+ */
+ private static final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00;
+ private static final int NUMBER_MODE_DATA_NETWORK = 0x01;
+
+ /**
+ * Number Types for data networks.
+ * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
+ * NOTE: value is stored in the parent class ton field.
+ */
+ private static final int TON_UNKNOWN = 0x00;
+
+ /**
+ * Numbering Plan identification is a 0 or 4-bit value that
+ * indicates which numbering plan identification is set. (See
+ * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
+ */
+ private static final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1;
+
+ /**
+ * User data encoding types.
+ * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
+ */
+ public static final int ENCODING_OCTET = 0x00;
+ public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01;
+ public static final int ENCODING_7BIT_ASCII = 0x02;
+ public static final int ENCODING_IA5 = 0x03;
+ public static final int ENCODING_UNICODE_16 = 0x04;
+ public static final int ENCODING_SHIFT_JIS = 0x05;
+ public static final int ENCODING_KOREAN = 0x06;
+ public static final int ENCODING_LATIN_HEBREW = 0x07;
+ public static final int ENCODING_LATIN = 0x08;
+ public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09;
+ public static final int ENCODING_GSM_DCS = 0x0A;
+
+ /**
+ * IS-91 message types.
+ * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3)
+ */
+ public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS = 0x82;
+ public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83;
+ public static final int IS91_MSG_TYPE_CLI = 0x84;
+ public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85;
+
+ /**
+ * Supported message types for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
+ */
+ public static final int MESSAGE_TYPE_DELIVER = 0x01;
+ public static final int MESSAGE_TYPE_SUBMIT = 0x02;
+ public static final int MESSAGE_TYPE_CANCELLATION = 0x03;
+ public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ putResources(R.bool.config_sms_utf8_support, false);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Initialize a Parcel for an incoming CDMA cell broadcast. The caller will write the
+ * bearer data and then convert it to an SmsMessage.
+ *
+ * @param serviceCategory the CDMA service category
+ * @return the initialized Parcel
+ */
+ private static CdmaSmsMessage createBroadcastParcel(int serviceCategory) {
+ CdmaSmsMessage msg = new CdmaSmsMessage();
+
+ msg.teleserviceId = TELESERVICE_NOT_SET;
+ msg.isServicePresent = true;
+ msg.serviceCategory = serviceCategory;
+
+ // dummy address (RIL may generate a different dummy address for broadcasts)
+ msg.address.digitMode = DIGIT_MODE_4BIT_DTMF;
+ msg.address.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ msg.address.numberType = TON_UNKNOWN;
+ msg.address.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+ msg.subAddress.subaddressType = 0;
+ msg.subAddress.odd = false;
+ return msg;
+ }
+
+ /**
+ * Initialize a BitwiseOutputStream with the CDMA bearer data subparameters except for
+ * user data. The caller will append the user data and add it to the parcel.
+ *
+ * @param messageId the 16-bit message identifier
+ * @param priority message priority
+ * @param language message language code
+ * @return the initialized BitwiseOutputStream
+ */
+ private static BitwiseOutputStream createBearerDataStream(int messageId, int priority,
+ int language) throws BitwiseOutputStream.AccessException {
+ BitwiseOutputStream bos = new BitwiseOutputStream(10);
+ bos.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
+ bos.write(8, 3); // length: 3 bytes
+ bos.write(4, BearerData.MESSAGE_TYPE_DELIVER);
+ bos.write(8, ((messageId >>> 8) & 0xff));
+ bos.write(8, (messageId & 0xff));
+ bos.write(1, 0); // no User Data Header
+ bos.write(3, 0); // reserved
+
+ if (priority != -1) {
+ bos.write(8, SUBPARAM_PRIORITY_INDICATOR);
+ bos.write(8, 1); // length: 1 byte
+ bos.write(2, (priority & 0x03));
+ bos.write(6, 0); // reserved
+ }
+
+ if (language != -1) {
+ bos.write(8, SUBPARAM_LANGUAGE_INDICATOR);
+ bos.write(8, 1); // length: 1 byte
+ bos.write(8, (language & 0xff));
+ }
+
+ return bos;
+ }
+
+ /**
+ * Write the bearer data array to the parcel, then return a new SmsMessage from the parcel.
+ *
+ * @param msg CdmaSmsMessage containing the CDMA SMS headers
+ * @param bearerData the bearer data byte array to append to the parcel
+ * @return the new SmsMessage created from the parcel
+ */
+ private static SmsMessage createMessageFromParcel(CdmaSmsMessage msg, byte[] bearerData) {
+ for (byte b : bearerData) {
+ msg.bearerData.add(b);
+ }
+ SmsMessage message = SmsMessageConverter.newCdmaSmsMessageFromRil(msg);
+ return message;
+ }
+
+ /**
+ * Create a parcel for an incoming CMAS broadcast, then return a new SmsMessage created
+ * from the parcel.
+ *
+ * @param serviceCategory the CDMA service category
+ * @param messageId the 16-bit message identifier
+ * @param priority message priority
+ * @param language message language code
+ * @param body message body
+ * @param cmasCategory CMAS category (or -1 to skip adding CMAS type 1 elements record)
+ * @param responseType CMAS response type
+ * @param severity CMAS severity
+ * @param urgency CMAS urgency
+ * @param certainty CMAS certainty
+ * @return the newly created SmsMessage object
+ */
+ private static SmsMessage createCmasSmsMessage(int serviceCategory, int messageId, int priority,
+ int language, int encoding, String body, int cmasCategory, int responseType,
+ int severity, int urgency, int certainty) throws Exception {
+ BitwiseOutputStream cmasBos = new BitwiseOutputStream(10);
+ cmasBos.write(8, 0); // CMAE protocol version 0
+
+ if (body != null) {
+ cmasBos.write(8, 0); // Type 0 elements (alert text)
+ encodeBody(encoding, body, true, cmasBos);
+ }
+
+ if (cmasCategory != SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN) {
+ cmasBos.write(8, 1); // Type 1 elements
+ cmasBos.write(8, 4); // length: 4 bytes
+ cmasBos.write(8, (cmasCategory & 0xff));
+ cmasBos.write(8, (responseType & 0xff));
+ cmasBos.write(4, (severity & 0x0f));
+ cmasBos.write(4, (urgency & 0x0f));
+ cmasBos.write(4, (certainty & 0x0f));
+ cmasBos.write(4, 0); // pad to octet boundary
+ }
+
+ byte[] cmasUserData = cmasBos.toByteArray();
+
+ CdmaSmsMessage msg = createBroadcastParcel(serviceCategory);
+ BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language);
+
+ bos.write(8, SUBPARAM_USER_DATA);
+ bos.write(8, cmasUserData.length + 2); // add 2 bytes for msg_encoding and num_fields
+ bos.write(5, ENCODING_OCTET);
+ bos.write(8, cmasUserData.length);
+ bos.writeByteArray(cmasUserData.length * 8, cmasUserData);
+ bos.write(3, 0); // pad to byte boundary
+
+ return createMessageFromParcel(msg, bos.toByteArray());
+ }
+
+ /**
+ * Create a parcel for an incoming CDMA cell broadcast, then return a new SmsMessage created
+ * from the parcel.
+ *
+ * @param serviceCategory the CDMA service category
+ * @param messageId the 16-bit message identifier
+ * @param priority message priority
+ * @param language message language code
+ * @param encoding user data encoding method
+ * @param body the message body
+ * @return the newly created SmsMessage object
+ */
+ private static SmsMessage createBroadcastSmsMessage(int serviceCategory, int messageId,
+ int priority, int language, int encoding, String body) throws Exception {
+ CdmaSmsMessage msg = createBroadcastParcel(serviceCategory);
+ BitwiseOutputStream bos = createBearerDataStream(messageId, priority, language);
+
+ bos.write(8, SUBPARAM_USER_DATA);
+ encodeBody(encoding, body, false, bos);
+
+ return createMessageFromParcel(msg, bos.toByteArray());
+ }
+
+ /**
+ * Append the message length, encoding, and body to the BearerData output stream.
+ * This is used for writing the User Data subparameter for non-CMAS broadcasts and for
+ * writing the alert text for CMAS broadcasts.
+ *
+ * @param encoding one of the CDMA UserData encoding values
+ * @param body the message body
+ * @param isCmasRecord true if this is a CMAS type 0 elements record; false for user data
+ * @param bos the BitwiseOutputStream to write to
+ * @throws Exception on any encoding error
+ */
+ private static void encodeBody(int encoding, String body, boolean isCmasRecord,
+ BitwiseOutputStream bos) throws Exception {
+ if (encoding == ENCODING_7BIT_ASCII || encoding == ENCODING_IA5) {
+ int charCount = body.length();
+ int recordBits = (charCount * 7) + 5; // add 5 bits for char set field
+ int recordOctets = (recordBits + 7) / 8; // round up to octet boundary
+ int padBits = (recordOctets * 8) - recordBits;
+
+ if (!isCmasRecord) {
+ recordOctets++; // add 8 bits for num_fields
+ }
+
+ bos.write(8, recordOctets);
+ bos.write(5, (encoding & 0x1f));
+
+ if (!isCmasRecord) {
+ bos.write(8, charCount);
+ }
+
+ for (int i = 0; i < charCount; i++) {
+ bos.write(7, body.charAt(i));
+ }
+
+ bos.write(padBits, 0); // pad to octet boundary
+ } else if (encoding == ENCODING_GSM_7BIT_ALPHABET
+ || encoding == ENCODING_GSM_DCS) {
+ // convert to 7-bit packed encoding with septet count in index 0 of byte array
+ byte[] encodedBody = GsmAlphabet.stringToGsm7BitPacked(body);
+
+ int charCount = encodedBody[0]; // septet count
+ int recordBits = (charCount * 7) + 5; // add 5 bits for char set field
+ int recordOctets = (recordBits + 7) / 8; // round up to octet boundary
+ int padBits = (recordOctets * 8) - recordBits;
+
+ if (!isCmasRecord) {
+ recordOctets++; // add 8 bits for num_fields
+ if (encoding == ENCODING_GSM_DCS) {
+ recordOctets++; // add 8 bits for DCS (message type)
+ }
+ }
+
+ bos.write(8, recordOctets);
+ bos.write(5, (encoding & 0x1f));
+
+ if (!isCmasRecord && encoding == ENCODING_GSM_DCS) {
+ bos.write(8, 0); // GSM DCS: 7 bit default alphabet, no msg class
+ }
+
+ if (!isCmasRecord) {
+ bos.write(8, charCount);
+ }
+ byte[] bodySeptets = Arrays.copyOfRange(encodedBody, 1, encodedBody.length);
+ bos.writeByteArray(charCount * 7, bodySeptets);
+ bos.write(padBits, 0); // pad to octet boundary
+ } else if (encoding == ENCODING_IS91_EXTENDED_PROTOCOL) {
+ // 6 bit packed encoding with 0x20 offset (ASCII 0x20 - 0x60)
+ int charCount = body.length();
+ int recordBits = (charCount * 6) + 21; // add 21 bits for header fields
+ int recordOctets = (recordBits + 7) / 8; // round up to octet boundary
+ int padBits = (recordOctets * 8) - recordBits;
+
+ bos.write(8, recordOctets);
+
+ bos.write(5, (encoding & 0x1f));
+ bos.write(8, IS91_MSG_TYPE_SHORT_MESSAGE);
+ bos.write(8, charCount);
+
+ for (int i = 0; i < charCount; i++) {
+ bos.write(6, ((int) body.charAt(i) - 0x20));
+ }
+
+ bos.write(padBits, 0); // pad to octet boundary
+ } else {
+ byte[] encodedBody;
+ switch (encoding) {
+ case ENCODING_UNICODE_16:
+ encodedBody = body.getBytes("UTF-16BE");
+ break;
+
+ case ENCODING_SHIFT_JIS:
+ encodedBody = body.getBytes("Shift_JIS");
+ break;
+
+ case ENCODING_KOREAN:
+ encodedBody = body.getBytes("KSC5601");
+ break;
+
+ case ENCODING_LATIN_HEBREW:
+ encodedBody = body.getBytes("ISO-8859-8");
+ break;
+
+ case ENCODING_LATIN:
+ default:
+ encodedBody = body.getBytes("ISO-8859-1");
+ break;
+ }
+ int charCount = body.length(); // use actual char count for num fields
+ int recordOctets = encodedBody.length + 1; // add 1 byte for encoding and pad bits
+ if (!isCmasRecord) {
+ recordOctets++; // add 8 bits for num_fields
+ }
+ bos.write(8, recordOctets);
+ bos.write(5, (encoding & 0x1f));
+ if (!isCmasRecord) {
+ bos.write(8, charCount);
+ }
+ bos.writeByteArray(encodedBody.length * 8, encodedBody);
+ bos.write(3, 0); // pad to octet boundary
+ }
+ }
+
+ private static final String TEST_TEXT = "This is a test CDMA cell broadcast message..."
+ + "678901234567890123456789012345678901234567890";
+
+ private static final String PRES_ALERT =
+ "THE PRESIDENT HAS ISSUED AN EMERGENCY ALERT. CHECK LOCAL MEDIA FOR MORE DETAILS";
+
+ private static final String EXTREME_ALERT = "FLASH FLOOD WARNING FOR SOUTH COCONINO COUNTY"
+ + " - NORTH CENTRAL ARIZONA UNTIL 415 PM MST";
+
+ private static final String SEVERE_ALERT = "SEVERE WEATHER WARNING FOR SOMERSET COUNTY"
+ + " - NEW JERSEY UNTIL 415 PM MST";
+
+ private static final String AMBER_ALERT =
+ "AMBER ALERT:Mountain View,CA VEH'07 Blue Honda Civic CA LIC 5ABC123";
+
+ private static final String MONTHLY_TEST_ALERT = "This is a test of the emergency alert system."
+ + " This is only a test. 89012345678901234567890";
+
+ private static final String IS91_TEXT = "IS91 SHORT MSG"; // max length 14 chars
+
+ /**
+ * Verify that the SmsCbMessage has the correct values for CDMA.
+ *
+ * @param cbMessage the message to test
+ */
+ private static void verifyCbValues(SmsCbMessage cbMessage) {
+ assertEquals(SmsCbMessage.MESSAGE_FORMAT_3GPP2, cbMessage.getMessageFormat());
+ assertEquals(SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, cbMessage.getGeographicalScope());
+ assertEquals(false, cbMessage.isEtwsMessage()); // ETWS on CDMA not currently supported
+ }
+
+ private static void doTestNonEmergencyBroadcast(Context context, int encoding)
+ throws Exception {
+ SmsMessage msg = createBroadcastSmsMessage(123, 456, BearerData.PRIORITY_NORMAL,
+ BearerData.LANGUAGE_ENGLISH, encoding, TEST_TEXT);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(context,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ verifyCbValues(cbMessage);
+ assertEquals(123, cbMessage.getServiceCategory());
+ assertEquals(456, cbMessage.getSerialNumber());
+ assertEquals(SmsCbMessage.MESSAGE_PRIORITY_NORMAL, cbMessage.getMessagePriority());
+ assertEquals("en", cbMessage.getLanguageCode());
+ assertEquals(TEST_TEXT, cbMessage.getMessageBody());
+ assertEquals(false, cbMessage.isEmergencyMessage());
+ assertEquals(false, cbMessage.isCmasMessage());
+ }
+
+ @Test
+ public void testNonEmergencyBroadcast7bitAscii() throws Exception {
+ doTestNonEmergencyBroadcast(mMockedContext, ENCODING_7BIT_ASCII);
+ }
+
+ @Test
+ public void testNonEmergencyBroadcast7bitGsm() throws Exception {
+ doTestNonEmergencyBroadcast(mMockedContext, ENCODING_GSM_7BIT_ALPHABET);
+ }
+
+ @Test
+ public void testNonEmergencyBroadcast16bitUnicode() throws Exception {
+ doTestNonEmergencyBroadcast(mMockedContext, ENCODING_UNICODE_16);
+ }
+
+ private static void doTestCmasBroadcast(Context context, int serviceCategory, int messageClass,
+ String body) throws Exception {
+ SmsMessage msg = createCmasSmsMessage(
+ serviceCategory, 1234, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
+ ENCODING_7BIT_ASCII, body, -1, -1, -1, -1, -1);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(context,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ verifyCbValues(cbMessage);
+ assertEquals(serviceCategory, cbMessage.getServiceCategory());
+ assertEquals(1234, cbMessage.getSerialNumber());
+ assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority());
+ assertEquals("en", cbMessage.getLanguageCode());
+ assertEquals(body, cbMessage.getMessageBody());
+ assertEquals(true, cbMessage.isEmergencyMessage());
+ assertEquals(true, cbMessage.isCmasMessage());
+ SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo();
+ assertEquals(messageClass, cmasInfo.getMessageClass());
+ assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory());
+ assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType());
+ assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity());
+ assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency());
+ assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty());
+ }
+
+ @Test
+ public void testCmasPresidentialAlert() throws Exception {
+ doTestCmasBroadcast(mMockedContext,
+ CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT,
+ SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, PRES_ALERT);
+ }
+
+ @Test
+ public void testCmasExtremeAlert() throws Exception {
+ doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, EXTREME_ALERT);
+ }
+
+ @Test
+ public void testCmasSevereAlert() throws Exception {
+ doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT,
+ SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT, SEVERE_ALERT);
+ }
+
+ @Test
+ public void testCmasAmberAlert() throws Exception {
+ doTestCmasBroadcast(mMockedContext,
+ CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY,
+ SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY, AMBER_ALERT);
+ }
+
+ @Test
+ public void testCmasTestMessage() throws Exception {
+ doTestCmasBroadcast(mMockedContext, CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE,
+ SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST, MONTHLY_TEST_ALERT);
+ }
+
+ @Test
+ public void testCmasExtremeAlertType1Elements() throws Exception {
+ SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ 5678, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
+ ENCODING_7BIT_ASCII, EXTREME_ALERT, SmsCbCmasInfo.CMAS_CATEGORY_ENV,
+ SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, SmsCbCmasInfo.CMAS_SEVERITY_SEVERE,
+ SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ verifyCbValues(cbMessage);
+ assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ cbMessage.getServiceCategory());
+ assertEquals(5678, cbMessage.getSerialNumber());
+ assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority());
+ assertEquals("en", cbMessage.getLanguageCode());
+ assertEquals(EXTREME_ALERT, cbMessage.getMessageBody());
+ assertEquals(true, cbMessage.isEmergencyMessage());
+ assertEquals(true, cbMessage.isCmasMessage());
+ SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo();
+ assertEquals(SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT, cmasInfo.getMessageClass());
+ assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_ENV, cmasInfo.getCategory());
+ assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_MONITOR, cmasInfo.getResponseType());
+ assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_SEVERE, cmasInfo.getSeverity());
+ assertEquals(SmsCbCmasInfo.CMAS_URGENCY_EXPECTED, cmasInfo.getUrgency());
+ assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY, cmasInfo.getCertainty());
+ }
+
+ // VZW requirement is to discard message with unsupported charset. Verify that we return null
+ // for this unsupported character set.
+ @Ignore
+ @Test
+ public void testCmasUnsupportedCharSet() throws Exception {
+ SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ 12345, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
+ 0x1F, EXTREME_ALERT, -1, -1, -1, -1, -1);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ assertNull("expected null for unsupported charset", cbMessage);
+ }
+
+ // VZW requirement is to discard message with unsupported charset. Verify that we return null
+ // for this unsupported character set.
+ @Test
+ public void testCmasUnsupportedCharSet2() throws Exception {
+ SmsMessage msg = createCmasSmsMessage(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ 67890, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
+ ENCODING_KOREAN, EXTREME_ALERT, -1, -1, -1, -1, -1);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ assertNull("expected null for unsupported charset", cbMessage);
+ }
+
+ // VZW requirement is to discard message without record type 0. The framework will decode it
+ // and the app will discard it.
+ @Test
+ public void testCmasNoRecordType0() throws Exception {
+ SmsMessage msg = createCmasSmsMessage(
+ CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 1234,
+ BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
+ ENCODING_7BIT_ASCII, null, -1, -1, -1, -1, -1);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ verifyCbValues(cbMessage);
+ assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT,
+ cbMessage.getServiceCategory());
+ assertEquals(1234, cbMessage.getSerialNumber());
+ assertEquals(SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, cbMessage.getMessagePriority());
+ assertEquals("en", cbMessage.getLanguageCode());
+ assertEquals(null, cbMessage.getMessageBody());
+ assertEquals(true, cbMessage.isEmergencyMessage());
+ assertEquals(true, cbMessage.isCmasMessage());
+ SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo();
+ assertEquals(SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, cmasInfo.getMessageClass());
+ assertEquals(SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN, cmasInfo.getCategory());
+ assertEquals(SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, cmasInfo.getResponseType());
+ assertEquals(SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN, cmasInfo.getSeverity());
+ assertEquals(SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN, cmasInfo.getUrgency());
+ assertEquals(SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN, cmasInfo.getCertainty());
+ }
+
+ // Make sure we don't throw an exception if we feed completely random data to BearerStream.
+ @Test
+ public void testRandomBearerStreamData() {
+ Random r = new Random(54321);
+ for (int run = 0; run < 1000; run++) {
+ int len = r.nextInt(140);
+ byte[] data = new byte[len];
+ for (int i = 0; i < len; i++) {
+ data[i] = (byte) r.nextInt(256);
+ }
+ // Log.d(TAG, "trying random bearer data run " + run + " length " + len);
+ try {
+ int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS
+ CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(category);
+ SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, data);
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(
+ mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(),
+ msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ // with random input, cbMessage will almost always be null (log when it isn't)
+ if (cbMessage != null) {
+ Log.d(TAG, "success: " + cbMessage);
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "exception thrown", e);
+ fail("Exception in decoder at run " + run + " length " + len + ": " + e);
+ }
+ }
+ }
+
+ // Make sure we don't throw an exception if we put random data in the UserData subparam.
+ @Test
+ public void testRandomUserData() {
+ Random r = new Random(94040);
+ for (int run = 0; run < 1000; run++) {
+ int category = 0x0ff0 + r.nextInt(32); // half CMAS, half non-CMAS
+ CdmaSmsMessage cdmaSmsMessage = createBroadcastParcel(category);
+ int len = r.nextInt(140);
+ // Log.d(TAG, "trying random user data run " + run + " length " + len);
+
+ try {
+ BitwiseOutputStream bos = createBearerDataStream(r.nextInt(65536), r.nextInt(4),
+ r.nextInt(256));
+
+ bos.write(8, SUBPARAM_USER_DATA);
+ bos.write(8, len);
+
+ for (int i = 0; i < len; i++) {
+ bos.write(8, r.nextInt(256));
+ }
+
+ SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray());
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext, 0, "",
+ msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ } catch (Exception e) {
+ Log.d(TAG, "exception thrown", e);
+ fail("Exception in decoder at run " + run + " length " + len + ": " + e);
+ }
+ }
+ }
+
+ /**
+ * Initialize a Parcel for incoming Service Category Program Data teleservice. The caller will
+ * write the bearer data and then convert it to an SmsMessage.
+ *
+ * @return the initialized Parcel
+ */
+ private static CdmaSmsMessage createServiceCategoryProgramDataParcel() {
+ CdmaSmsMessage msg = new CdmaSmsMessage();
+
+ msg.teleserviceId = TELESERVICE_SCPT;
+ msg.isServicePresent = false;
+ msg.serviceCategory = 0;
+
+ // dummy address (RIL may generate a different dummy address for broadcasts)
+ msg.address.digitMode = DIGIT_MODE_4BIT_DTMF;
+ msg.address.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
+ msg.address.numberType = TON_UNKNOWN;
+ msg.address.numberPlan = NUMBERING_PLAN_ISDN_TELEPHONY;
+ msg.subAddress.subaddressType = 0;
+ msg.subAddress.odd = false;
+ return msg;
+ }
+
+ private static final String CAT_EXTREME_THREAT = "Extreme Threat to Life and Property";
+ private static final String CAT_SEVERE_THREAT = "Severe Threat to Life and Property";
+ private static final String CAT_AMBER_ALERTS = "AMBER Alerts";
+
+ @Test
+ public void testServiceCategoryProgramDataAddCategory() throws Exception {
+ CdmaSmsMessage cdmaSmsMessage = createServiceCategoryProgramDataParcel();
+ BitwiseOutputStream bos = createBearerDataStream(123, -1, -1);
+
+ int categoryNameLength = CAT_EXTREME_THREAT.length();
+ int subparamLengthBits = (53 + (categoryNameLength * 7));
+ int subparamLengthBytes = (subparamLengthBits + 7) / 8;
+ int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits;
+
+ bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA);
+ bos.write(8, subparamLengthBytes);
+ bos.write(5, ENCODING_7BIT_ASCII);
+
+ bos.write(4, CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY);
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT >>> 8));
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT & 0xff));
+ bos.write(8, BearerData.LANGUAGE_ENGLISH);
+ bos.write(8, 100); // max messages
+ bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT);
+
+ bos.write(8, categoryNameLength);
+ for (int i = 0; i < categoryNameLength; i++) {
+ bos.write(7, CAT_EXTREME_THREAT.charAt(i));
+ }
+ bos.write(subparamPadBits, 0);
+
+ SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray());
+ assertNotNull(msg);
+ msg.parseSms();
+ List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData();
+ assertNotNull(programDataList);
+ assertEquals(1, programDataList.size());
+ CdmaSmsCbProgramData programData = programDataList.get(0);
+ assertEquals(CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY, programData.getOperation());
+ assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT,
+ programData.getCategory());
+ assertEquals(CAT_EXTREME_THREAT, programData.getCategoryName());
+ assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
+ assertEquals(100, programData.getMaxMessages());
+ assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_DEFAULT_ALERT, programData.getAlertOption());
+ }
+
+ @Test
+ public void testServiceCategoryProgramDataDeleteTwoCategories() throws Exception {
+ CdmaSmsMessage cdmaSmsMessage = createServiceCategoryProgramDataParcel();
+ BitwiseOutputStream bos = createBearerDataStream(456, -1, -1);
+
+ int category1NameLength = CAT_SEVERE_THREAT.length();
+ int category2NameLength = CAT_AMBER_ALERTS.length();
+
+ int subparamLengthBits = (101 + (category1NameLength * 7) + (category2NameLength * 7));
+ int subparamLengthBytes = (subparamLengthBits + 7) / 8;
+ int subparamPadBits = (subparamLengthBytes * 8) - subparamLengthBits;
+
+ bos.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA);
+ bos.write(8, subparamLengthBytes);
+ bos.write(5, ENCODING_7BIT_ASCII);
+
+ bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY);
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT >>> 8));
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT & 0xff));
+ bos.write(8, BearerData.LANGUAGE_ENGLISH);
+ bos.write(8, 0); // max messages
+ bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT);
+
+ bos.write(8, category1NameLength);
+ for (int i = 0; i < category1NameLength; i++) {
+ bos.write(7, CAT_SEVERE_THREAT.charAt(i));
+ }
+
+ bos.write(4, CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY);
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY >>> 8));
+ bos.write(8, (CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY & 0xff));
+ bos.write(8, BearerData.LANGUAGE_ENGLISH);
+ bos.write(8, 0); // max messages
+ bos.write(4, CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT);
+
+ bos.write(8, category2NameLength);
+ for (int i = 0; i < category2NameLength; i++) {
+ bos.write(7, CAT_AMBER_ALERTS.charAt(i));
+ }
+
+ bos.write(subparamPadBits, 0);
+
+ SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, bos.toByteArray());
+ assertNotNull(msg);
+ msg.parseSms();
+ List<CdmaSmsCbProgramData> programDataList = msg.getSmsCbProgramData();
+ assertNotNull(programDataList);
+ assertEquals(2, programDataList.size());
+
+ CdmaSmsCbProgramData programData = programDataList.get(0);
+ assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation());
+ assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT,
+ programData.getCategory());
+ assertEquals(CAT_SEVERE_THREAT, programData.getCategoryName());
+ assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
+ assertEquals(0, programData.getMaxMessages());
+ assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption());
+
+ programData = programDataList.get(1);
+ assertEquals(CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY, programData.getOperation());
+ assertEquals(CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY,
+ programData.getCategory());
+ assertEquals(CAT_AMBER_ALERTS, programData.getCategoryName());
+ assertEquals(BearerData.LANGUAGE_ENGLISH, programData.getLanguage());
+ assertEquals(0, programData.getMaxMessages());
+ assertEquals(CdmaSmsCbProgramData.ALERT_OPTION_NO_ALERT, programData.getAlertOption());
+ }
+
+ private static final byte[] CMAS_TEST_BEARER_DATA = {
+ 0x00, 0x03, 0x1C, 0x78, 0x00, 0x01, 0x59, 0x02, (byte) 0xB8, 0x00, 0x02, 0x10,
+ (byte) 0xAA,
+ 0x68, (byte) 0xD3, (byte) 0xCD, 0x06, (byte) 0x9E, 0x68, 0x30, (byte) 0xA0, (byte) 0xE9,
+ (byte) 0x97, (byte) 0x9F, 0x44, 0x1B, (byte) 0xF3, 0x20, (byte) 0xE9, (byte) 0xA3,
+ 0x2A, 0x08, 0x7B, (byte) 0xF6, (byte) 0xED, (byte) 0xCB, (byte) 0xCB, 0x1E, (byte) 0x9C,
+ 0x3B, 0x10, 0x4D, (byte) 0xDF, (byte) 0x8B, 0x4E,
+ (byte) 0xCC, (byte) 0xA8, 0x20, (byte) 0xEC, (byte) 0xCB, (byte) 0xCB, (byte) 0xA2,
+ 0x0A,
+ 0x7E, 0x79, (byte) 0xF4, (byte) 0xCB, (byte) 0xB5, 0x72, 0x0A, (byte) 0x9A, 0x34,
+ (byte) 0xF3, 0x41, (byte) 0xA7, (byte) 0x9A, 0x0D, (byte) 0xFB, (byte) 0xB6, 0x79, 0x41,
+ (byte) 0x85, 0x07, 0x4C, (byte) 0xBC, (byte) 0xFA, 0x2E, 0x00, 0x08, 0x20, 0x58, 0x38,
+ (byte) 0x88, (byte) 0x80, 0x10, 0x54, 0x06, 0x38, 0x20, 0x60,
+ 0x30, (byte) 0xA8, (byte) 0x81, (byte) 0x90, 0x20, 0x08
+ };
+
+ // Test case for CMAS test message received on the Sprint network.
+ @Test
+ public void testDecodeRawBearerData() {
+ CdmaSmsMessage cdmaSmsMessage =
+ createBroadcastParcel(CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE);
+ SmsMessage msg = createMessageFromParcel(cdmaSmsMessage, CMAS_TEST_BEARER_DATA);
+
+ SmsCbMessage cbMessage =
+ DefaultCellBroadcastService.parseBroadcastSms(mMockedContext,
+ 0, "", msg.getEnvelopeBearerData(), msg.getEnvelopeServiceCategory());
+ //SmsCbMessage cbMessage = msg.parseBroadcastSms("", 0);
+ assertNotNull("expected non-null for bearer data", cbMessage);
+ assertEquals("geoScope", cbMessage.getGeographicalScope(), 1);
+ assertEquals("serialNumber", cbMessage.getSerialNumber(), 51072);
+ assertEquals("serviceCategory", cbMessage.getServiceCategory(),
+ CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE);
+ assertEquals("payload", cbMessage.getMessageBody(),
+ "This is a test of the Commercial Mobile Alert System. This is only a test.");
+
+ SmsCbCmasInfo cmasInfo = cbMessage.getCmasWarningInfo();
+ assertNotNull("expected non-null for CMAS info", cmasInfo);
+ assertEquals("category", cmasInfo.getCategory(), SmsCbCmasInfo.CMAS_CATEGORY_OTHER);
+ assertEquals("responseType", cmasInfo.getResponseType(),
+ SmsCbCmasInfo.CMAS_RESPONSE_TYPE_NONE);
+ assertEquals("severity", cmasInfo.getSeverity(), SmsCbCmasInfo.CMAS_SEVERITY_SEVERE);
+ assertEquals("urgency", cmasInfo.getUrgency(), SmsCbCmasInfo.CMAS_URGENCY_EXPECTED);
+ assertEquals("certainty", cmasInfo.getCertainty(), SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY);
+ }
+}
diff --git a/tests/src/com/android/cellbroadcastservice/GsmSmsCbMessageTest.java b/tests/src/com/android/cellbroadcastservice/GsmSmsCbMessageTest.java
index de80095..c39f650 100644
--- a/tests/src/com/android/cellbroadcastservice/GsmSmsCbMessageTest.java
+++ b/tests/src/com/android/cellbroadcastservice/GsmSmsCbMessageTest.java
@@ -19,12 +19,14 @@
import android.telephony.CbGeoUtils;
import android.telephony.SmsCbCmasInfo;
import android.telephony.SmsCbEtwsInfo;
+import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
-import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import com.android.cellbroadcastservice.CbGeoUtils.Circle;
import com.android.cellbroadcastservice.CbGeoUtils.Polygon;
@@ -34,6 +36,7 @@
import org.junit.runner.RunWith;
import java.util.List;
+import java.util.Random;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -41,6 +44,9 @@
private static final String TAG = "GsmSmsCbMessageTest";
+ private static final SmsCbLocation TEST_LOCATION = new SmsCbLocation("94040", 1234, 5678);
+
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -52,7 +58,6 @@
}
@Test
- @SmallTest
public void testGetEtwsPrimaryMessage() {
String testMessage1 = "Testmessage1";
String testMessage2 = "Testmessage2";
@@ -93,7 +98,6 @@
}
@Test
- @SmallTest
public void testCreateMessageFromBinary() throws Exception {
final byte[] pdu = hexStringToBytes("0111130F6A0101C8329BFD06559BD429E8FE96B3C92C101D9D9"
+ "E83D27350B22E1C7EAFF234BDFCADB962AE9A6BCE06A1DCE57B0AD40241C3E73208147B81622E000"
@@ -158,7 +162,6 @@
}
@Test
- @SmallTest
public void testCreateTriggerMessage() throws Exception {
final byte[] pdu = hexStringToBytes("0001113001010010C0111204D2");
GsmSmsCbMessage.GeoFencingTriggerMessage triggerMessage =
@@ -172,4 +175,887 @@
assertEquals(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
triggerMessage.cbIdentifiers.get(0).messageIdentifier);
}
+
+ private SmsCbMessage createFromPdu(byte[] pdu) {
+ try {
+ SmsCbHeader header = new SmsCbHeader(pdu);
+ byte[][] pdus = new byte[1][];
+ pdus[0] = pdu;
+ return GsmSmsCbMessage.createSmsCbMessage(InstrumentationRegistry.getContext(), header,
+ TEST_LOCATION, pdus, /* slotIndex */ 0);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ private void doTestGeographicalScopeValue(byte[] pdu, byte b, int expectedGs) {
+ pdu[0] = b;
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected geographical scope decoded", expectedGs, msg
+ .getGeographicalScope());
+ }
+
+ @Test
+ public void testCreateNullPdu() {
+ SmsCbMessage msg = createFromPdu(null);
+ assertNull("createFromPdu(byte[] with null pdu should return null", msg);
+ }
+
+ @Test
+ public void testCreateTooShortPdu() {
+ byte[] pdu = new byte[4];
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertNull("createFromPdu(byte[] with too short pdu should return null", msg);
+ }
+
+ @Test
+ public void testGetGeographicalScope() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+
+ doTestGeographicalScopeValue(pdu, (byte) 0x00,
+ SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE);
+ doTestGeographicalScopeValue(pdu, (byte) 0x40, SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE);
+ doTestGeographicalScopeValue(pdu, (byte) 0x80,
+ SmsCbMessage.GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE);
+ doTestGeographicalScopeValue(pdu, (byte) 0xC0, SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE);
+ }
+
+ @Test
+ public void testGetGeographicalScopeUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE, (byte) 0x69, (byte) 0x3A,
+ (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5, (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75, (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93,
+ (byte) 0xC9, (byte) 0x69, (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x34
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected geographical scope decoded",
+ SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE, msg.getGeographicalScope());
+ }
+
+ @Test
+ public void testGetMessageBody7Bit() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBody7BitUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE, (byte) 0x69, (byte) 0x3A,
+ (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5, (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75, (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93,
+ (byte) 0xC9, (byte) 0x69, (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x34
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBody7BitMultipageUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xC0, (byte) 0x00, (byte) 0x40,
+
+ (byte) 0x02,
+
+ (byte) 0xC6, (byte) 0xB4, (byte) 0x7C, (byte) 0x4E, (byte) 0x07, (byte) 0xC1,
+ (byte) 0xC3, (byte) 0xE7, (byte) 0xF2, (byte) 0xAA, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34,
+ (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x0A,
+
+ (byte) 0xD3, (byte) 0xF2, (byte) 0xF8, (byte) 0xED, (byte) 0x26, (byte) 0x83,
+ (byte) 0xE0, (byte) 0xE1, (byte) 0x73, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34,
+ (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x0A
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected multipage 7-bit string decoded",
+ "First page+Second page",
+ msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBody7BitFull() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xC4,
+ (byte) 0xE5,
+ (byte) 0xB4, (byte) 0xFB, (byte) 0x0C, (byte) 0x2A, (byte) 0xE3, (byte) 0xC3,
+ (byte) 0x63,
+ (byte) 0x3A, (byte) 0x3B, (byte) 0x0F, (byte) 0xCA, (byte) 0xCD, (byte) 0x40,
+ (byte) 0x63,
+ (byte) 0x74, (byte) 0x58, (byte) 0x1E, (byte) 0x1E, (byte) 0xD3, (byte) 0xCB,
+ (byte) 0xF2,
+ (byte) 0x39, (byte) 0x88, (byte) 0xFD, (byte) 0x76, (byte) 0x9F, (byte) 0x59,
+ (byte) 0xA0,
+ (byte) 0x76, (byte) 0x39, (byte) 0xEC, (byte) 0x4E, (byte) 0xBB, (byte) 0xCF,
+ (byte) 0x20,
+ (byte) 0x3A, (byte) 0xBA, (byte) 0x2C, (byte) 0x2F, (byte) 0x83, (byte) 0xD2,
+ (byte) 0x73,
+ (byte) 0x90, (byte) 0xFB, (byte) 0x0D, (byte) 0x82, (byte) 0x87, (byte) 0xC9,
+ (byte) 0xE4,
+ (byte) 0xB4, (byte) 0xFB, (byte) 0x1C, (byte) 0x02
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals(
+ "Unexpected 7-bit string decoded",
+ "A GSM default alphabet message being exactly 93 characters long, "
+ + "meaning there is no padding!",
+ msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBody7BitFullUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xC4, (byte) 0xE5, (byte) 0xB4,
+ (byte) 0xFB, (byte) 0x0C, (byte) 0x2A, (byte) 0xE3, (byte) 0xC3, (byte) 0x63,
+ (byte) 0x3A, (byte) 0x3B, (byte) 0x0F, (byte) 0xCA, (byte) 0xCD, (byte) 0x40,
+ (byte) 0x63, (byte) 0x74, (byte) 0x58, (byte) 0x1E, (byte) 0x1E, (byte) 0xD3,
+ (byte) 0xCB, (byte) 0xF2, (byte) 0x39, (byte) 0x88, (byte) 0xFD, (byte) 0x76,
+ (byte) 0x9F, (byte) 0x59, (byte) 0xA0, (byte) 0x76, (byte) 0x39, (byte) 0xEC,
+ (byte) 0x4E, (byte) 0xBB, (byte) 0xCF, (byte) 0x20, (byte) 0x3A, (byte) 0xBA,
+ (byte) 0x2C, (byte) 0x2F, (byte) 0x83, (byte) 0xD2, (byte) 0x73, (byte) 0x90,
+ (byte) 0xFB, (byte) 0x0D, (byte) 0x82, (byte) 0x87, (byte) 0xC9, (byte) 0xE4,
+ (byte) 0xB4, (byte) 0xFB, (byte) 0x1C, (byte) 0x02,
+
+ (byte) 0x52
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals(
+ "Unexpected 7-bit string decoded",
+ "A GSM default alphabet message being exactly 93 characters long, "
+ + "meaning there is no padding!",
+ msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBody7BitWithLanguage() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x04, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "es", msg.getLanguageCode());
+ }
+
+ @Test
+ public void testGetMessageBody7BitWithLanguageInBody() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x10, (byte) 0x11,
+ (byte) 0x73,
+ (byte) 0x7B, (byte) 0x23, (byte) 0x08, (byte) 0x3A, (byte) 0x4E, (byte) 0x9B,
+ (byte) 0x20,
+ (byte) 0x72, (byte) 0xD9, (byte) 0x1C, (byte) 0xAE, (byte) 0xB3, (byte) 0xE9,
+ (byte) 0xA0,
+ (byte) 0x30, (byte) 0x1B, (byte) 0x8E, (byte) 0x0E, (byte) 0x8B, (byte) 0xCB,
+ (byte) 0x74,
+ (byte) 0x50, (byte) 0xBB, (byte) 0x3C, (byte) 0x9F, (byte) 0x87, (byte) 0xCF,
+ (byte) 0x65,
+ (byte) 0xD0, (byte) 0x3D, (byte) 0x4D, (byte) 0x47, (byte) 0x83, (byte) 0xC6,
+ (byte) 0x61,
+ (byte) 0xB9, (byte) 0x3C, (byte) 0x1D, (byte) 0x3E, (byte) 0x97, (byte) 0x41,
+ (byte) 0xF2,
+ (byte) 0x32, (byte) 0xBD, (byte) 0x2E, (byte) 0x77, (byte) 0x83, (byte) 0xE0,
+ (byte) 0x61,
+ (byte) 0x32, (byte) 0x39, (byte) 0xED, (byte) 0x3E, (byte) 0x37, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
+ }
+
+ @Test
+ public void testGetMessageBody7BitWithLanguageInBodyUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x10,
+
+ (byte) 0x01,
+
+ (byte) 0x73, (byte) 0x7B, (byte) 0x23, (byte) 0x08, (byte) 0x3A, (byte) 0x4E,
+ (byte) 0x9B, (byte) 0x20, (byte) 0x72, (byte) 0xD9, (byte) 0x1C, (byte) 0xAE,
+ (byte) 0xB3, (byte) 0xE9, (byte) 0xA0, (byte) 0x30, (byte) 0x1B, (byte) 0x8E,
+ (byte) 0x0E, (byte) 0x8B, (byte) 0xCB, (byte) 0x74, (byte) 0x50, (byte) 0xBB,
+ (byte) 0x3C, (byte) 0x9F, (byte) 0x87, (byte) 0xCF, (byte) 0x65, (byte) 0xD0,
+ (byte) 0x3D, (byte) 0x4D, (byte) 0x47, (byte) 0x83, (byte) 0xC6, (byte) 0x61,
+ (byte) 0xB9, (byte) 0x3C, (byte) 0x1D, (byte) 0x3E, (byte) 0x97, (byte) 0x41,
+ (byte) 0xF2, (byte) 0x32, (byte) 0xBD, (byte) 0x2E, (byte) 0x77, (byte) 0x83,
+ (byte) 0xE0, (byte) 0x61, (byte) 0x32, (byte) 0x39, (byte) 0xED, (byte) 0x3E,
+ (byte) 0x37, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x37
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A GSM default alphabet message with carriage return padding",
+ msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "sv", msg.getLanguageCode());
+ }
+
+ @Test
+ public void testGetMessageBody8Bit() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x44, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, (byte) 0x47,
+ (byte) 0x41,
+ (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("8-bit message body should be empty", "", msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBodyUcs2() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x48, (byte) 0x11,
+ (byte) 0x00,
+ (byte) 0x41, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x55, (byte) 0x00,
+ (byte) 0x43,
+ (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x20,
+ (byte) 0x00,
+ (byte) 0x6D, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x73, (byte) 0x00,
+ (byte) 0x73,
+ (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x65,
+ (byte) 0x00,
+ (byte) 0x20, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x6F, (byte) 0x00,
+ (byte) 0x6E,
+ (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x69,
+ (byte) 0x00,
+ (byte) 0x6E, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6E, (byte) 0x00,
+ (byte) 0x67,
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x20,
+ (byte) 0x04,
+ (byte) 0x34, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x63, (byte) 0x00,
+ (byte) 0x68,
+ (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00,
+ (byte) 0x63, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00,
+ (byte) 0x72,
+ (byte) 0x00, (byte) 0x0D, (byte) 0x00, (byte) 0x0D
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBodyUcs2Umts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x48,
+
+ (byte) 0x01,
+
+ (byte) 0x00, (byte) 0x41, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x55,
+ (byte) 0x00, (byte) 0x43, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x32,
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x6D, (byte) 0x00, (byte) 0x65,
+ (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x20,
+ (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x6F, (byte) 0x00, (byte) 0x6E,
+ (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x69,
+ (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6E,
+ (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00, (byte) 0x20, (byte) 0x04, (byte) 0x34, (byte) 0x00, (byte) 0x20,
+ (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x68, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x63,
+ (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x72,
+ (byte) 0x00, (byte) 0x0D, (byte) 0x00, (byte) 0x0D,
+
+ (byte) 0x4E
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBodyUcs2MultipageUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x48,
+
+ (byte) 0x02,
+
+ (byte) 0x00, (byte) 0x41, (byte) 0x00, (byte) 0x41, (byte) 0x00, (byte) 0x41,
+ (byte) 0x00, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+
+ (byte) 0x06,
+
+ (byte) 0x00, (byte) 0x42, (byte) 0x00, (byte) 0x42, (byte) 0x00, (byte) 0x42,
+ (byte) 0x00, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+ (byte) 0x0D, (byte) 0x0D, (byte) 0x0D, (byte) 0x0D,
+
+ (byte) 0x06
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected multipage UCS2 string decoded",
+ "AAABBB", msg.getMessageBody());
+ }
+
+ @Test
+ public void testGetMessageBodyUcs2WithLanguageInBody() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0x11, (byte) 0x11,
+ (byte) 0x78,
+ (byte) 0x3C, (byte) 0x00, (byte) 0x41, (byte) 0x00, (byte) 0x20, (byte) 0x00,
+ (byte) 0x55,
+ (byte) 0x00, (byte) 0x43, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x32,
+ (byte) 0x00,
+ (byte) 0x20, (byte) 0x00, (byte) 0x6D, (byte) 0x00, (byte) 0x65, (byte) 0x00,
+ (byte) 0x73,
+ (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x67,
+ (byte) 0x00,
+ (byte) 0x65, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x63, (byte) 0x00,
+ (byte) 0x6F,
+ (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00,
+ (byte) 0x69, (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x69, (byte) 0x00,
+ (byte) 0x6E,
+ (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00,
+ (byte) 0x20, (byte) 0x04, (byte) 0x34, (byte) 0x00, (byte) 0x20, (byte) 0x00,
+ (byte) 0x63,
+ (byte) 0x00, (byte) 0x68, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72,
+ (byte) 0x00,
+ (byte) 0x61, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x74, (byte) 0x00,
+ (byte) 0x65,
+ (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x0D
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
+ }
+
+ @Test
+ public void testGetMessageBodyUcs2WithLanguageInBodyUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x00, (byte) 0x32, (byte) 0xC0, (byte) 0x00, (byte) 0x11,
+
+ (byte) 0x01,
+
+ (byte) 0x78, (byte) 0x3C, (byte) 0x00, (byte) 0x41, (byte) 0x00, (byte) 0x20,
+ (byte) 0x00, (byte) 0x55, (byte) 0x00, (byte) 0x43, (byte) 0x00, (byte) 0x53,
+ (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x6D,
+ (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x73,
+ (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x65,
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x6F,
+ (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x69,
+ (byte) 0x00, (byte) 0x6E, (byte) 0x00, (byte) 0x67, (byte) 0x00, (byte) 0x20,
+ (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x20, (byte) 0x04, (byte) 0x34,
+ (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x68,
+ (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x61,
+ (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65,
+ (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x0D,
+
+ (byte) 0x50
+ };
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected 7-bit string decoded",
+ "A UCS2 message containing a \u0434 character", msg.getMessageBody());
+
+ assertEquals("Unexpected language indicator decoded", "xx", msg.getLanguageCode());
+ }
+
+ @Test
+ public void testGetMessageIdentifier() {
+ byte[] pdu = {
+ (byte) 0xC0, (byte) 0x00, (byte) 0x30, (byte) 0x39, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory());
+ }
+
+ @Test
+ public void testGetMessageIdentifierUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x30, (byte) 0x39, (byte) 0x2A, (byte) 0xA5, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE, (byte) 0x69, (byte) 0x3A,
+ (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5, (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75, (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93,
+ (byte) 0xC9, (byte) 0x69, (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x34
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+
+ assertEquals("Unexpected message identifier decoded", 12345, msg.getServiceCategory());
+ }
+
+ @Test
+ public void testGetMessageCode() {
+ byte[] pdu = {
+ (byte) 0x2A, (byte) 0xA5, (byte) 0x30, (byte) 0x39, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+ int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4;
+
+ assertEquals("Unexpected message code decoded", 682, messageCode);
+ }
+
+ @Test
+ public void testGetMessageCodeUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x30, (byte) 0x39, (byte) 0x2A, (byte) 0xA5, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE, (byte) 0x69, (byte) 0x3A,
+ (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5, (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75, (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93,
+ (byte) 0xC9, (byte) 0x69, (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x34
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+ int messageCode = (msg.getSerialNumber() & 0x3ff0) >> 4;
+
+ assertEquals("Unexpected message code decoded", 682, messageCode);
+ }
+
+ @Test
+ public void testGetUpdateNumber() {
+ byte[] pdu = {
+ (byte) 0x2A, (byte) 0xA5, (byte) 0x30, (byte) 0x39, (byte) 0x40, (byte) 0x11,
+ (byte) 0x41,
+ (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91, (byte) 0xCB,
+ (byte) 0xE6,
+ (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07, (byte) 0x85, (byte) 0xD9,
+ (byte) 0x70,
+ (byte) 0x74, (byte) 0x58, (byte) 0x5C, (byte) 0xA6, (byte) 0x83, (byte) 0xDA,
+ (byte) 0xE5,
+ (byte) 0xF9, (byte) 0x3C, (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE,
+ (byte) 0x69,
+ (byte) 0x3A, (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5,
+ (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75,
+ (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93, (byte) 0xC9,
+ (byte) 0x69,
+ (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A,
+ (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+ int updateNumber = msg.getSerialNumber() & 0x000f;
+
+ assertEquals("Unexpected update number decoded", 5, updateNumber);
+ }
+
+ @Test
+ public void testGetUpdateNumberUmts() {
+ byte[] pdu = {
+ (byte) 0x01, (byte) 0x30, (byte) 0x39, (byte) 0x2A, (byte) 0xA5, (byte) 0x40,
+
+ (byte) 0x01,
+
+ (byte) 0x41, (byte) 0xD0, (byte) 0x71, (byte) 0xDA, (byte) 0x04, (byte) 0x91,
+ (byte) 0xCB, (byte) 0xE6, (byte) 0x70, (byte) 0x9D, (byte) 0x4D, (byte) 0x07,
+ (byte) 0x85, (byte) 0xD9, (byte) 0x70, (byte) 0x74, (byte) 0x58, (byte) 0x5C,
+ (byte) 0xA6, (byte) 0x83, (byte) 0xDA, (byte) 0xE5, (byte) 0xF9, (byte) 0x3C,
+ (byte) 0x7C, (byte) 0x2E, (byte) 0x83, (byte) 0xEE, (byte) 0x69, (byte) 0x3A,
+ (byte) 0x1A, (byte) 0x34, (byte) 0x0E, (byte) 0xCB, (byte) 0xE5, (byte) 0xE9,
+ (byte) 0xF0, (byte) 0xB9, (byte) 0x0C, (byte) 0x92, (byte) 0x97, (byte) 0xE9,
+ (byte) 0x75, (byte) 0xB9, (byte) 0x1B, (byte) 0x04, (byte) 0x0F, (byte) 0x93,
+ (byte) 0xC9, (byte) 0x69, (byte) 0xF7, (byte) 0xB9, (byte) 0xD1, (byte) 0x68,
+ (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3, (byte) 0xD1,
+ (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46, (byte) 0xA3,
+ (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D, (byte) 0x46,
+ (byte) 0xA3, (byte) 0xD1, (byte) 0x68, (byte) 0x34, (byte) 0x1A, (byte) 0x8D,
+ (byte) 0x46, (byte) 0xA3, (byte) 0xD1, (byte) 0x00,
+
+ (byte) 0x34
+ };
+
+ SmsCbMessage msg = createFromPdu(pdu);
+ int updateNumber = msg.getSerialNumber() & 0x000f;
+
+ assertEquals("Unexpected update number decoded", 5, updateNumber);
+ }
+
+ /* ETWS Test message including header */
+ private static final byte[] etwsMessageNormal = hexStringToBytes("000011001101"
+ + "0D0A5BAE57CE770C531790E85C716CBF3044573065B930675730"
+ + "9707767A751F30025F37304463FA308C306B5099304830664E0B30553044FF086C178C615E81FF09"
+ + "0000000000000000000000000000");
+
+ private static final byte[] etwsMessageCancel = hexStringToBytes("000011001101"
+ + "0D0A5148307B3069002800310030003A0035"
+ + "00320029306E7DCA602557309707901F5831309253D66D883057307E3059FF086C178C615E81FF09"
+ + "00000000000000000000000000000000000000000000");
+
+ private static final byte[] etwsMessageTest = hexStringToBytes("000011031101"
+ + "0D0A5BAE57CE770C531790E85C716CBF3044"
+ + "573065B9306757309707300263FA308C306B5099304830664E0B30553044FF086C178C615E81FF09"
+ + "00000000000000000000000000000000000000000000");
+
+ // FIXME: add example of ETWS primary notification PDU
+
+ @Test
+ public void testEtwsMessageNormal() {
+ SmsCbMessage msg = createFromPdu(etwsMessageNormal);
+ Log.d(TAG, msg.toString());
+ assertEquals("GS mismatch", 0, msg.getGeographicalScope());
+ assertEquals("serial number mismatch", 0, msg.getSerialNumber());
+ assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory());
+ assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE,
+ msg.getEtwsWarningInfo().getWarningType());
+ }
+
+ @Test
+ public void testEtwsMessageCancel() {
+ SmsCbMessage msg = createFromPdu(etwsMessageCancel);
+ Log.d(TAG, msg.toString());
+ assertEquals("GS mismatch", 0, msg.getGeographicalScope());
+ assertEquals("serial number mismatch", 0, msg.getSerialNumber());
+ assertEquals("message ID mismatch", 0x1100, msg.getServiceCategory());
+ assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE,
+ msg.getEtwsWarningInfo().getWarningType());
+ }
+
+ @Test
+ public void testEtwsMessageTest() {
+ SmsCbMessage msg = createFromPdu(etwsMessageTest);
+ Log.d(TAG, msg.toString());
+ assertEquals("GS mismatch", 0, msg.getGeographicalScope());
+ assertEquals("serial number mismatch", 0, msg.getSerialNumber());
+ assertEquals("message ID mismatch", 0x1103, msg.getServiceCategory());
+ assertEquals("warning type mismatch", SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE,
+ msg.getEtwsWarningInfo().getWarningType());
+ }
+
+ // Make sure we don't throw an exception if we feed random data to the PDU parser.
+ @Test
+ public void testRandomPdus() {
+ Random r = new Random(94040);
+ for (int run = 0; run < 10000; run++) {
+ int len = r.nextInt(140);
+ byte[] data = new byte[len];
+ for (int i = 0; i < len; i++) {
+ data[i] = (byte) r.nextInt(256);
+ }
+ try {
+ // this should return a SmsCbMessage object or null for invalid data
+ SmsCbMessage msg = createFromPdu(data);
+ } catch (Exception e) {
+ Log.d(TAG, "exception thrown", e);
+ fail("Exception in decoder at run " + run + " length " + len + ": " + e);
+ }
+ }
+ }
}