| /* |
| * Copyright (C) 2009 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 android.telephony.cts; |
| |
| import static android.telephony.cts.util.TelephonyUtils.hexStringToByteArray; |
| |
| import static androidx.test.InstrumentationRegistry.getContext; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assume.assumeFalse; |
| import static org.junit.Assume.assumeTrue; |
| |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.telephony.SmsManager; |
| import android.telephony.SmsMessage; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.telephony.cts.util.TelephonyUtils; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.util.Arrays; |
| |
| public class SmsMessageTest { |
| |
| private TelephonyManager mTelephonyManager; |
| private PackageManager mPackageManager; |
| |
| private static final String DISPLAY_MESSAGE_BODY = "test subject /test body"; |
| private static final String DMB = "{ testBody[^~\\] }"; |
| private static final String EMAIL_ADD = "foo@example.com"; |
| private static final String EMAIL_FROM = "foo@example.com"; |
| private static final String MB = DMB; |
| private static final String MESSAGE_BODY1 = "Test"; |
| private static final String MESSAGE_BODY2 = "(Subject)Test"; |
| private static final String MESSAGE_BODY3 = "\u2122\u00a9\u00aehello"; |
| private static final String MESSAGE_BODY4 = " "; |
| private static final String MESSAGE_BODY5 = " "; |
| private static final String OA = "foo@example.com"; |
| private static final String OA1 = "+14154255486"; |
| private static final String OA2 = "+15122977683"; |
| private static final String OA3 = "_@"; |
| private static final String OA4 = "\u0394@"; |
| // pseudo subject will always be empty |
| private static final String PSEUDO_SUBJECT = ""; |
| private static final String SCA1 = "+16466220020"; |
| private static final String SCA2 = "+12063130012"; |
| private static final String SCA3 = "+14155551212"; |
| private static final String SCA4 = "+14155551212"; |
| private static final int NOT_CREATE_FROM_SIM = -1; |
| private static final int NOT_CREATE_FROM_ICC = -1; |
| private static final int PROTOCOL_IDENTIFIER = 0; |
| private static final int SMS_NUMBER1 = 1; |
| private static final int SMS_NUMBER2 = 1; |
| private static final int SMS_NUMBER3 = 1; |
| private static final int STATUS = 0; |
| private static final int STATUS_ON_SIM_DEF = -1; |
| private static final int STATUS_ON_ICC_DEF = -1; |
| private static final int TPLAYER_LENGTH_FOR_PDU = 23; |
| private static final long TIMESTAMP_MILLIS = 1149631383000l; |
| private static final int SEPTETS_SKT = 80; |
| private static final int SEPTETS_KT = 90; |
| private static final String LONG_TEXT_WITH_32BIT_CHARS = |
| "Long dkkshsh jdjsusj kbsksbdf jfkhcu hhdiwoqiwyrygrvn?*?*!\";:'/,." |
| + "__?9#9292736&4;\"$+$+((]\\[\\℅©℅™^®°¥°¥=¢£}}£∆~¶~÷|√×." |
| + " 😯😆😉😇😂😀👕🎓😀👙🐕🐀🐶🐰🐩⛪⛲ "; |
| private static final String LONG_TEXT_WITH_FLAGS = |
| "🇦🇫🇦🇽🇦🇱🇩🇿🇦🇸🇦🇩🇦🇴🇦🇮🇦🇶🇦🇬🇦🇷🇦🇲🇦🇼🇦🇨" |
| + "🇦🇺🇦🇹🇦🇿🇧🇸🇧🇭🇧🇩🇧🇧🇧🇾🇧🇪🇧🇿🇧🇯🇧🇲🇧🇹🇧🇴🇧🇦"; |
| |
| @Before |
| public void setUp() throws Exception { |
| assumeTrue(getContext().getPackageManager().hasSystemFeature( |
| PackageManager.FEATURE_TELEPHONY_MESSAGING)); |
| mPackageManager = getContext().getPackageManager(); |
| mTelephonyManager = |
| (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE); |
| } |
| |
| @Test |
| public void testCreateFromPdu() throws Exception { |
| // TODO: temp workaround, need to adjust test to use CDMA pdus |
| assumeFalse(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_TELEPHONY_CDMA)); |
| |
| String pdu = "07916164260220F0040B914151245584F600006060605130308A04D4F29C0E"; |
| SmsMessage sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), |
| SmsMessage.FORMAT_3GPP); |
| assertEquals(SCA1, sms.getServiceCenterAddress()); |
| assertEquals(OA1, sms.getOriginatingAddress()); |
| assertEquals(MESSAGE_BODY1, sms.getMessageBody()); |
| assertEquals(TPLAYER_LENGTH_FOR_PDU, SmsMessage.getTPLayerLengthForPDU(pdu)); |
| int[] result = SmsMessage.calculateLength(sms.getMessageBody(), true); |
| assertEquals(6, result.length); |
| assertEquals(SMS_NUMBER1, result[0]); |
| assertEquals(sms.getMessageBody().length(), result[1]); |
| assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS); |
| assertEquals(SmsMessage.ENCODING_7BIT, result[3]); |
| assertEquals(pdu, TelephonyUtils.toHexString(sms.getPdu())); |
| |
| assertEquals(NOT_CREATE_FROM_SIM, sms.getIndexOnSim()); |
| assertEquals(NOT_CREATE_FROM_ICC, sms.getIndexOnIcc()); |
| assertEquals(PROTOCOL_IDENTIFIER, sms.getProtocolIdentifier()); |
| assertFalse(sms.isEmail()); |
| assertFalse(sms.isReplyPathPresent()); |
| assertFalse(sms.isStatusReportMessage()); |
| assertFalse(sms.isCphsMwiMessage()); |
| assertEquals(SmsMessage.MessageClass.UNKNOWN, sms.getMessageClass()); |
| assertEquals(STATUS, sms.getStatus()); |
| assertEquals(STATUS_ON_SIM_DEF, sms.getStatusOnSim()); |
| assertEquals(STATUS_ON_ICC_DEF, sms.getStatusOnIcc()); |
| assertEquals(TIMESTAMP_MILLIS, sms.getTimestampMillis()); |
| |
| // Test create from null Pdu |
| sms = SmsMessage.createFromPdu(null, SmsMessage.FORMAT_3GPP); |
| assertNull(sms); |
| |
| // Test create from long Pdu |
| pdu = "07912160130310F2040B915121927786F300036060924180008A0DA" |
| + "8695DAC2E8FE9296A794E07"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertEquals(SCA2, sms.getServiceCenterAddress()); |
| assertEquals(OA2, sms.getOriginatingAddress()); |
| assertEquals(MESSAGE_BODY2, sms.getMessageBody()); |
| CharSequence msgBody = sms.getMessageBody(); |
| result = SmsMessage.calculateLength(msgBody, false); |
| assertEquals(6, result.length); |
| assertEquals(SMS_NUMBER2, result[0]); |
| assertEquals(sms.getMessageBody().length(), result[1]); |
| assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS); |
| assertEquals(SmsMessage.ENCODING_7BIT, result[3]); |
| |
| // Test createFromPdu Ucs to Sms |
| pdu = "07912160130300F4040B914151245584" |
| + "F600087010807121352B10212200A900AE00680065006C006C006F"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertEquals(MESSAGE_BODY3, sms.getMessageBody()); |
| result = SmsMessage.calculateLength(sms.getMessageBody(), true); |
| assertEquals(6, result.length); |
| assertEquals(SMS_NUMBER3, result[0]); |
| assertEquals(sms.getMessageBody().length(), result[1]); |
| assertRemaining(sms.getMessageBody().length(), result[2], SmsMessage.MAX_USER_DATA_SEPTETS); |
| assertEquals(SmsMessage.ENCODING_7BIT, result[3]); |
| |
| // Test createFromPdu to test ENCODING_KSC5601 (0x84 as DCS in pdu) |
| // The only way of retrieving the Data Coding Scheme is via SmsMessage#calculateLength, |
| // but it never returns ENCODING_KSC5601, so we're testing for ENCODING_16BIT instead. |
| pdu = "07916164260220F0040B914151245584F600846060605130308A04D4F29C0E"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| result = SmsMessage.calculateLength(sms.getMessageBody(), false); |
| assertEquals(SmsMessage.ENCODING_16BIT, result[3]); |
| } |
| |
| private void assertRemaining(int messageLength, int remaining, int maxChars) { |
| if (TelephonyUtils.isSkt(mTelephonyManager)) { |
| assertTrue(checkRemaining(SEPTETS_SKT, messageLength, remaining) |
| || checkRemaining(maxChars, messageLength, remaining)); |
| } else if (TelephonyUtils.isKt(mTelephonyManager)) { |
| assertTrue(checkRemaining(SEPTETS_KT, messageLength, remaining) |
| || checkRemaining(maxChars, messageLength, remaining)); |
| } else { |
| assertTrue(checkRemaining(maxChars, messageLength, remaining)); |
| } |
| } |
| |
| private boolean checkRemaining(int total, int messageLength, int remaining) { |
| return total - messageLength == remaining; |
| } |
| |
| @Test |
| public void testCPHSVoiceMail() throws Exception { |
| // TODO: temp workaround, need to adjust test to use CDMA pdus |
| assumeFalse(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_TELEPHONY_CDMA)); |
| |
| // "set MWI flag" |
| String pdu = "07912160130310F20404D0110041006060627171118A0120"; |
| SmsMessage sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), |
| SmsMessage.FORMAT_3GPP); |
| assertTrue(sms.isReplace()); |
| assertEquals(OA3, sms.getOriginatingAddress()); |
| assertEquals(MESSAGE_BODY4, sms.getMessageBody()); |
| assertTrue(sms.isMWISetMessage()); |
| |
| // "clear mwi flag" |
| pdu = "07912160130310F20404D0100041006021924193352B0120"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertTrue(sms.isMWIClearMessage()); |
| |
| // "clear MWI flag" |
| pdu = "07912160130310F20404D0100041006060627161058A0120"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertTrue(sms.isReplace()); |
| assertEquals(OA4, sms.getOriginatingAddress()); |
| assertEquals(MESSAGE_BODY5, sms.getMessageBody()); |
| assertTrue(sms.isMWIClearMessage()); |
| |
| // "set MWI flag" |
| pdu = "07912180958750F84401800500C87020026195702B06040102000200"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertTrue(sms.isMWISetMessage()); |
| assertTrue(sms.isMwiDontStore()); |
| |
| // "clear mwi flag" |
| pdu = "07912180958750F84401800500C07020027160112B06040102000000"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| |
| assertTrue(sms.isMWIClearMessage()); |
| assertTrue(sms.isMwiDontStore()); |
| } |
| |
| @Test |
| public void testGetUserData() throws Exception { |
| // TODO: temp workaround, need to adjust test to use CDMA pdus |
| assumeFalse(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_TELEPHONY_CDMA)); |
| |
| String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F" |
| + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" |
| + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426" |
| + "66C414141414D7741414236514141414141008D908918802B3135313232393737" |
| + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703" |
| + "A2F2F36"; |
| SmsMessage sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), |
| SmsMessage.FORMAT_3GPP); |
| byte[] userData = sms.getUserData(); |
| assertNotNull(userData); |
| } |
| |
| @Test |
| public void testGetSubmitPdu() throws Exception { |
| SmsMessage.SubmitPdu smsPdu; |
| String scAddress = null, destinationAddress = null; |
| String message = null; |
| boolean statusReportRequested = false; |
| |
| // Null message, null destination |
| smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, |
| statusReportRequested); |
| assertNull(smsPdu); |
| |
| message = "This is a test message"; |
| |
| // Non-null message, null destination |
| smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, |
| statusReportRequested); |
| assertNull(smsPdu); |
| |
| if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { |
| // TODO: temp workaround, OCTET encoding for EMS not properly supported |
| return; |
| } |
| |
| scAddress = "1650253000"; |
| destinationAddress = "18004664411"; |
| message = "This is a test message"; |
| statusReportRequested = false; |
| smsPdu = SmsMessage.getSubmitPdu( |
| scAddress, destinationAddress, message, statusReportRequested); |
| assertNotNull(smsPdu); |
| |
| smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, (short)80, |
| message.getBytes(), statusReportRequested); |
| assertNotNull(smsPdu); |
| } |
| |
| @Test |
| public void testEmailGateway() throws Exception { |
| // TODO: temp workaround, need to adjust test to use CDMA pdus |
| assumeFalse(mPackageManager.hasSystemFeature( |
| PackageManager.FEATURE_TELEPHONY_CDMA)); |
| |
| String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" + |
| "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3"; |
| |
| SmsMessage sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), |
| SmsMessage.FORMAT_3GPP); |
| assertEquals(SCA4, sms.getServiceCenterAddress()); |
| assertTrue(sms.isEmail()); |
| assertEquals(EMAIL_ADD, sms.getEmailFrom()); |
| assertEquals(EMAIL_ADD, sms.getDisplayOriginatingAddress()); |
| assertEquals(PSEUDO_SUBJECT, sms.getPseudoSubject()); |
| |
| assertEquals(DISPLAY_MESSAGE_BODY, sms.getDisplayMessageBody()); |
| assertEquals(DISPLAY_MESSAGE_BODY, sms.getEmailBody()); |
| |
| pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" + |
| "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629"; |
| sms = SmsMessage.createFromPdu(hexStringToByteArray(pdu), SmsMessage.FORMAT_3GPP); |
| assertEquals(SCA3, sms.getServiceCenterAddress()); |
| assertTrue(sms.isEmail()); |
| assertEquals(OA, sms.getDisplayOriginatingAddress()); |
| assertEquals(EMAIL_FROM, sms.getEmailFrom()); |
| assertEquals(DMB, sms.getDisplayMessageBody()); |
| assertEquals(MB, sms.getEmailBody()); |
| } |
| |
| @Test |
| public void testCalculateLength() throws Exception { |
| int[] result = SmsMessage.calculateLength(LONG_TEXT_WITH_32BIT_CHARS, false); |
| assertEquals(6, result.length); |
| assertEquals(3, result[0]); |
| assertEquals(LONG_TEXT_WITH_32BIT_CHARS.length(), result[1]); |
| // 3 parts, each with (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2) 16-bit |
| // characters. We need to subtract one because a 32-bit character crosses the |
| // boundary of 2 parts. |
| int preMaxChars = 3 * SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2 - 1; |
| // If EMS is not supported, break down EMS into single segment SMS |
| // and add page info "x/y". |
| // In the case of UCS2 encoding type, we need 8 bytes for this |
| // but we only have 6 bytes from UDH, so truncate the limit for |
| // each segment by 2 bytes (1 char). This log sms has three segments, |
| // so truncate the limit by 3 char in total |
| int maxChars = SmsMessage.hasEmsSupport() ? preMaxChars : preMaxChars - 3; |
| assertRemaining(LONG_TEXT_WITH_32BIT_CHARS.length(), result[2], |
| maxChars); |
| assertEquals(SmsMessage.ENCODING_16BIT, result[3]); |
| } |
| |
| @Test |
| public void testCalculateLengthFlags() throws Exception { |
| int[] result = SmsMessage.calculateLength(LONG_TEXT_WITH_FLAGS, false); |
| assertEquals(2, result[0]); |
| } |
| |
| @Test |
| public void testGetSmsPdu() { |
| SmsMessage.SubmitPdu smsPdu; |
| String scAddress = null; |
| String destinationAddress = null; |
| String message = null; |
| |
| // Null message, null destination |
| smsPdu = SmsMessage.getSmsPdu(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, |
| SmsManager.STATUS_ON_ICC_READ, |
| scAddress, destinationAddress, message, System.currentTimeMillis()); |
| assertNull(smsPdu); |
| |
| message = "This is a test message"; |
| |
| // Non-null message, null destination |
| smsPdu = SmsMessage.getSmsPdu(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, |
| SmsManager.STATUS_ON_ICC_READ, |
| scAddress, destinationAddress, message, System.currentTimeMillis()); |
| assertNull(smsPdu); |
| |
| if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { |
| // TODO: temp workaround, OCTET encoding for EMS not properly supported |
| return; |
| } |
| |
| scAddress = "1650253000"; |
| destinationAddress = "18004664411"; |
| message = "This is a test message"; |
| smsPdu = SmsMessage.getSmsPdu(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, |
| SmsManager.STATUS_ON_ICC_READ, |
| scAddress, destinationAddress, message, System.currentTimeMillis()); |
| assertNotNull(smsPdu); |
| } |
| |
| @Test |
| public void testGetSubmitPduEncodedMessage() throws Exception { |
| String destinationAddress = "18004664411"; |
| String message = "This is a test message"; |
| |
| byte[] gsmMsg = SmsMessage.getSubmitPduEncodedMessage(true, destinationAddress, |
| message, |
| 1, // Encoding code unit size. Pick ENCODING_7BIT here. |
| 0, // GSM national language table. It's usually 0. |
| 0, // GSM national language table. It's usually 0. |
| 1, // Reference number of concatenated SMS. Pick 1 for simplicity. |
| 1, // Sequence number of concatenated SMS. Pick 1 for simplicity. |
| 2); // Count of messages of concatenated SMS. Pick 2 for simplicity. |
| |
| // Encoded gsm message. |
| byte[] expectedGsmMsg = {65, 0, 11, -127, -127, 0, 100, 70, 20, -15, 0, 0, 29, 5, 0, 3, 1, |
| 2, 1, -88, -24, -12, 28, -108, -98, -125, -62, 32, 122, 121, 78, 7, -75, -53, -13, |
| 121, -8, 92, 6}; |
| |
| // See comments for gsmMsg. |
| byte[] cdmaMsg = SmsMessage.getSubmitPduEncodedMessage(false, destinationAddress, |
| message, 1, 0, 0, 1, 1, 2); |
| |
| // Encoded cdma message. |
| byte[] expectedCdmaMsg = {0, 0, 16, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 1, 8, 10, 10, |
| 4, 6, 6, 4, 4, 1, 1, 0, 0, 0, 35, 0, 3, 32, 0, 24, 1, 28, 72, -24, 40, 0, 24, 8, 16, |
| 13, 71, 71, -96, -28, -92, -12, 30, 17, 3, -45, -54, 112, 61, -82, 95, -101, -49, |
| -62, -32, 48}; |
| |
| assertArrayEquals(expectedGsmMsg, gsmMsg); |
| // In CDMA, the message byte array is affected by the messageId generated by |
| // {@link com.android.internal.telephony.cdma.SmsMessage#getNextMessageId()} |
| // which is not consistent. Skip the 2 bytes which are affected by it. |
| assertArrayEquals(Arrays.copyOfRange(expectedCdmaMsg, 0, 35), |
| Arrays.copyOfRange(cdmaMsg, 0, 35)); |
| assertArrayEquals(Arrays.copyOfRange(expectedCdmaMsg, 37, expectedCdmaMsg.length), |
| Arrays.copyOfRange(cdmaMsg, 37, expectedCdmaMsg.length)); |
| } |
| |
| @Test |
| public void testCreateFromNativeSmsSubmitPdu() { |
| // Short message with status RECEIVED_READ and size 0. See 3GPP2 C.S0023 3.4.27 |
| byte[] submitPdu = {1, 0}; |
| SmsMessage sms = SmsMessage.createFromNativeSmsSubmitPdu(submitPdu, true); |
| assertNull(sms); |
| } |
| } |