Loading src/java/com/android/internal/telephony/InboundSmsHandler.java +4 −7 Original line number Original line Diff line number Diff line Loading @@ -132,8 +132,6 @@ public abstract class InboundSmsHandler extends StateMachine { public static final int DISPLAY_ADDRESS_COLUMN = 9; public static final int DISPLAY_ADDRESS_COLUMN = 9; public static final String SELECT_BY_ID = "_id=?"; public static final String SELECT_BY_ID = "_id=?"; public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " + "count=? AND deleted=0"; /** New SMS received as an AsyncResult. */ /** New SMS received as an AsyncResult. */ public static final int EVENT_NEW_SMS = 1; public static final int EVENT_NEW_SMS = 1; Loading Loading @@ -754,7 +752,7 @@ public abstract class InboundSmsHandler extends StateMachine { // query for all segments and broadcast message if we have all the parts // query for all segments and broadcast message if we have all the parts String[] whereArgs = {address, refNumber, count}; String[] whereArgs = {address, refNumber, count}; cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, SELECT_BY_REFERENCE, whereArgs, null); tracker.getQueryForSegments(), whereArgs, null); int cursorCount = cursor.getCount(); int cursorCount = cursor.getCount(); if (cursorCount < messageCount) { if (cursorCount < messageCount) { Loading Loading @@ -1151,9 +1149,8 @@ public abstract class InboundSmsHandler extends StateMachine { } else { } else { // for multi-part messages, deduping should also be done against undeleted // for multi-part messages, deduping should also be done against undeleted // segments that can cause ambiguity when contacenating the segments, that is, // segments that can cause ambiguity when contacenating the segments, that is, // segments with same address, reference_number, count and sequence // segments with same address, reference_number, count, sequence and message type. where = "address=? AND reference_number=? AND count=? AND sequence=? AND " + where = tracker.getQueryForMultiPartDuplicates(); "((date=? AND message_body=?) OR deleted=0)"; } } Cursor cursor = null; Cursor cursor = null; Loading Loading @@ -1230,7 +1227,7 @@ public abstract class InboundSmsHandler extends StateMachine { } else { } else { // set the delete selection args for multi-part message // set the delete selection args for multi-part message String[] deleteWhereArgs = {address, refNumber, count}; String[] deleteWhereArgs = {address, refNumber, count}; tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs); tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs); } } return Intents.RESULT_SMS_HANDLED; return Intents.RESULT_SMS_HANDLED; } catch (Exception e) { } catch (Exception e) { Loading src/java/com/android/internal/telephony/InboundSmsTracker.java +40 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony; import android.content.ContentValues; import android.content.ContentValues; import android.database.Cursor; import android.database.Cursor; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.HexDump; import java.util.Arrays; import java.util.Arrays; Loading Loading @@ -59,21 +60,47 @@ public class InboundSmsTracker { */ */ private final String mDisplayAddress; private final String mDisplayAddress; @VisibleForTesting /** Destination port flag bit for no destination port. */ /** Destination port flag bit for no destination port. */ private static final int DEST_PORT_FLAG_NO_PORT = (1 << 16); public static final int DEST_PORT_FLAG_NO_PORT = (1 << 16); /** Destination port flag bit to indicate 3GPP format message. */ /** Destination port flag bit to indicate 3GPP format message. */ private static final int DEST_PORT_FLAG_3GPP = (1 << 17); private static final int DEST_PORT_FLAG_3GPP = (1 << 17); @VisibleForTesting /** Destination port flag bit to indicate 3GPP2 format message. */ /** Destination port flag bit to indicate 3GPP2 format message. */ private static final int DEST_PORT_FLAG_3GPP2 = (1 << 18); public static final int DEST_PORT_FLAG_3GPP2 = (1 << 18); @VisibleForTesting /** Destination port flag bit to indicate 3GPP2 format WAP message. */ /** Destination port flag bit to indicate 3GPP2 format WAP message. */ private static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19); public static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19); /** Destination port mask (16-bit unsigned value on GSM and CDMA). */ /** Destination port mask (16-bit unsigned value on GSM and CDMA). */ private static final int DEST_PORT_MASK = 0xffff; private static final int DEST_PORT_MASK = 0xffff; @VisibleForTesting public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " + "count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0) AND deleted=0"; @VisibleForTesting public static final String SELECT_BY_REFERENCE_3GPP2WAP = "address=? AND reference_number=? " + "AND count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ") AND deleted=0"; @VisibleForTesting public static final String SELECT_BY_DUPLICATE_REFERENCE = "address=? AND " + "reference_number=? AND count=? AND sequence=? AND " + "((date=? AND message_body=?) OR deleted=0) AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0)"; @VisibleForTesting public static final String SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP = "address=? AND " + "reference_number=? " + "AND count=? AND sequence=? AND " + "((date=? AND message_body=?) OR deleted=0) AND " + "(destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ")"; /** /** * Create a tracker for a single-part SMS. * Create a tracker for a single-part SMS. * * Loading Loading @@ -190,7 +217,7 @@ public class InboundSmsTracker { + " of " + mMessageCount); + " of " + mMessageCount); } } mDeleteWhere = InboundSmsHandler.SELECT_BY_REFERENCE; mDeleteWhere = getQueryForSegments(); mDeleteWhereArgs = new String[]{mAddress, mDeleteWhereArgs = new String[]{mAddress, Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)}; Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)}; } } Loading Loading @@ -293,6 +320,15 @@ public class InboundSmsTracker { return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; } } public String getQueryForSegments() { return mIs3gpp2WapPdu ? SELECT_BY_REFERENCE_3GPP2WAP : SELECT_BY_REFERENCE; } public String getQueryForMultiPartDuplicates() { return mIs3gpp2WapPdu ? SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP : SELECT_BY_DUPLICATE_REFERENCE; } /** /** * Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU * Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU * messages, which use a 0-based index. * messages, which use a 0-based index. Loading src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -200,7 +200,7 @@ public class SmsBroadcastUndelivered { for (SmsReferenceKey message : oldMultiPartMessages) { for (SmsReferenceKey message : oldMultiPartMessages) { // delete permanently // delete permanently int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, InboundSmsHandler.SELECT_BY_REFERENCE, message.getDeleteWhereArgs()); message.getDeleteWhere(), message.getDeleteWhereArgs()); if (rows == 0) { if (rows == 0) { Rlog.e(TAG, "No rows were deleted from raw table!"); Rlog.e(TAG, "No rows were deleted from raw table!"); } else if (DBG) { } else if (DBG) { Loading Loading @@ -243,11 +243,14 @@ public class SmsBroadcastUndelivered { final String mAddress; final String mAddress; final int mReferenceNumber; final int mReferenceNumber; final int mMessageCount; final int mMessageCount; final String mQuery; SmsReferenceKey(InboundSmsTracker tracker) { SmsReferenceKey(InboundSmsTracker tracker) { mAddress = tracker.getAddress(); mAddress = tracker.getAddress(); mReferenceNumber = tracker.getReferenceNumber(); mReferenceNumber = tracker.getReferenceNumber(); mMessageCount = tracker.getMessageCount(); mMessageCount = tracker.getMessageCount(); mQuery = tracker.getQueryForSegments(); } } String[] getDeleteWhereArgs() { String[] getDeleteWhereArgs() { Loading @@ -255,6 +258,10 @@ public class SmsBroadcastUndelivered { Integer.toString(mMessageCount)}; Integer.toString(mMessageCount)}; } } String getDeleteWhere() { return mQuery; } @Override @Override public int hashCode() { public int hashCode() { return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); Loading tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +125 −10 Original line number Original line Diff line number Diff line Loading @@ -146,7 +146,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { } } mSmsMessage.mWrappedSmsMessage = mGsmSmsMessage; mSmsMessage.mWrappedSmsMessage = mGsmSmsMessage; mInboundSmsTrackerCV.put("destination_port", 1 << 16); mInboundSmsTrackerCV.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("reference_number", 1); mInboundSmsTrackerCV.put("reference_number", 1); Loading Loading @@ -317,10 +317,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); assertEquals("IdleState", getCurrentState().getName()); } } private void prepareMultiPartSms() { private void prepareMultiPartSms(boolean isWapPush) { // Part 1 // Part 1 mInboundSmsTrackerCVPart1 = new ContentValues(); mInboundSmsTrackerCVPart1 = new ContentValues(); mInboundSmsTrackerCVPart1.put("destination_port", 1 << 16); mInboundSmsTrackerCVPart1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart1.put("address", "1234567890"); mInboundSmsTrackerCVPart1.put("address", "1234567890"); mInboundSmsTrackerCVPart1.put("reference_number", 1); mInboundSmsTrackerCVPart1.put("reference_number", 1); Loading @@ -338,13 +337,40 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(mMessageBodyPart1).when(mInboundSmsTrackerPart1).getMessageBody(); doReturn(mMessageBodyPart1).when(mInboundSmsTrackerPart1).getMessageBody(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu(); doReturn(new String[]{mInboundSmsTrackerPart1.getAddress(), Integer.toString(mInboundSmsTrackerPart1.getReferenceNumber()), Integer.toString(mInboundSmsTrackerPart1.getMessageCount())}) .when(mInboundSmsTrackerPart1).getDeleteWhereArgs(); doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1). doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1). getTimestamp(); getTimestamp(); doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues(); doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues(); if (isWapPush) { mInboundSmsTrackerCVPart1.put("destination_port", (InboundSmsTracker.DEST_PORT_FLAG_3GPP2 | InboundSmsTracker.DEST_PORT_FLAG_3GPP2_WAP_PDU | SmsHeader.PORT_WAP_PUSH)); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart1) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP) .when(mInboundSmsTrackerPart1).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart1) .getDeleteWhere(); doReturn(SmsHeader.PORT_WAP_PUSH).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(true).when(mInboundSmsTrackerPart1).is3gpp2(); } else { mInboundSmsTrackerCVPart1.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart1) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE) .when(mInboundSmsTrackerPart1).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart1) .getDeleteWhere(); } // Part 2 // Part 2 mInboundSmsTrackerCVPart2 = new ContentValues(); mInboundSmsTrackerCVPart2 = new ContentValues(); mInboundSmsTrackerCVPart2.put("destination_port", 1 << 16); mInboundSmsTrackerCVPart2.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart2.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart2.put("address", "1234567890"); mInboundSmsTrackerCVPart2.put("address", "1234567890"); mInboundSmsTrackerCVPart2.put("reference_number", 1); mInboundSmsTrackerCVPart2.put("reference_number", 1); Loading @@ -362,9 +388,98 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(mMessageBodyPart2).when(mInboundSmsTrackerPart2).getMessageBody(); doReturn(mMessageBodyPart2).when(mInboundSmsTrackerPart2).getMessageBody(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu(); doReturn(new String[]{mInboundSmsTrackerPart2.getAddress(), Integer.toString(mInboundSmsTrackerPart2.getReferenceNumber()), Integer.toString(mInboundSmsTrackerPart2.getMessageCount())}) .when(mInboundSmsTrackerPart2).getDeleteWhereArgs(); doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2). doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2). getTimestamp(); getTimestamp(); doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues(); doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues(); if (isWapPush) { mInboundSmsTrackerCVPart2.put("destination_port", (InboundSmsTracker.DEST_PORT_FLAG_3GPP2 | InboundSmsTracker.DEST_PORT_FLAG_3GPP2_WAP_PDU | SmsHeader.PORT_WAP_PUSH)); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart2) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP) .when(mInboundSmsTrackerPart2).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart2) .getDeleteWhere(); doReturn(SmsHeader.PORT_WAP_PUSH).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(true).when(mInboundSmsTrackerPart2).is3gpp2(); } else { mInboundSmsTrackerCVPart2.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart2) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE) .when(mInboundSmsTrackerPart2).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart2) .getDeleteWhere(); } } @Test @MediumTest public void testMultiPartSmsWithIncompleteWAP() { /** * Test scenario: 3 messages are received with same address, ref number, count. two of the * messages are belonging to the same multi-part SMS and the other one is a 3GPP2WAP. * we should not try to merge 3gpp2wap with the multi-part SMS. */ transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); // part 2 of non-3gpp2wap arrives first doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // State machine should go back to idle and wait for second part assertEquals("IdleState", getCurrentState().getName()); // mock a 3gpp2wap push prepareMultiPartSms(true); doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // State machine should go back to idle and wait for second part assertEquals("IdleState", getCurrentState().getName()); // verify no broadcast sent. verify(mContext, times(0)).sendBroadcast(any(Intent.class)); // additional copy of part 1 of non-3gpp2wap prepareMultiPartSms(false); doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // verify broadcast intents verifySmsIntentBroadcasts(0); assertEquals("IdleState", getCurrentState().getName()); // verify there are three segments in the db and only one of them is not marked as deleted. assertEquals(3, mContentProvider.getNumRows()); assertEquals(1, mContentProvider.query(sRawUri, null, "deleted=0", null, null).getCount()); } } @FlakyTest @FlakyTest Loading @@ -374,7 +489,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); Loading Loading @@ -421,7 +536,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { // timestamps, should not be combined with the additional part 2 received above // timestamps, should not be combined with the additional part 2 received above // call prepareMultiPartSms() to update timestamps // call prepareMultiPartSms() to update timestamps prepareMultiPartSms(); prepareMultiPartSms(false); // part 1 of new sms // part 1 of new sms doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) Loading @@ -448,7 +563,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); // change seqNumber in part 2 to 1 // change seqNumber in part 2 to 1 mInboundSmsTrackerCVPart2.put("sequence", 1); mInboundSmsTrackerCVPart2.put("sequence", 1); doReturn(1).when(mInboundSmsTrackerPart2).getSequenceNumber(); doReturn(1).when(mInboundSmsTrackerPart2).getSequenceNumber(); Loading Loading @@ -491,7 +606,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); Loading Loading @@ -527,7 +642,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); // only the first SMS is configured with the display originating email address // only the first SMS is configured with the display originating email address mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890@test.com"); mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890@test.com"); Loading Loading @@ -643,7 +758,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); //add the 2 SMS parts to db //add the 2 SMS parts to db mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart1); mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart1); Loading Loading
src/java/com/android/internal/telephony/InboundSmsHandler.java +4 −7 Original line number Original line Diff line number Diff line Loading @@ -132,8 +132,6 @@ public abstract class InboundSmsHandler extends StateMachine { public static final int DISPLAY_ADDRESS_COLUMN = 9; public static final int DISPLAY_ADDRESS_COLUMN = 9; public static final String SELECT_BY_ID = "_id=?"; public static final String SELECT_BY_ID = "_id=?"; public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " + "count=? AND deleted=0"; /** New SMS received as an AsyncResult. */ /** New SMS received as an AsyncResult. */ public static final int EVENT_NEW_SMS = 1; public static final int EVENT_NEW_SMS = 1; Loading Loading @@ -754,7 +752,7 @@ public abstract class InboundSmsHandler extends StateMachine { // query for all segments and broadcast message if we have all the parts // query for all segments and broadcast message if we have all the parts String[] whereArgs = {address, refNumber, count}; String[] whereArgs = {address, refNumber, count}; cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION, SELECT_BY_REFERENCE, whereArgs, null); tracker.getQueryForSegments(), whereArgs, null); int cursorCount = cursor.getCount(); int cursorCount = cursor.getCount(); if (cursorCount < messageCount) { if (cursorCount < messageCount) { Loading Loading @@ -1151,9 +1149,8 @@ public abstract class InboundSmsHandler extends StateMachine { } else { } else { // for multi-part messages, deduping should also be done against undeleted // for multi-part messages, deduping should also be done against undeleted // segments that can cause ambiguity when contacenating the segments, that is, // segments that can cause ambiguity when contacenating the segments, that is, // segments with same address, reference_number, count and sequence // segments with same address, reference_number, count, sequence and message type. where = "address=? AND reference_number=? AND count=? AND sequence=? AND " + where = tracker.getQueryForMultiPartDuplicates(); "((date=? AND message_body=?) OR deleted=0)"; } } Cursor cursor = null; Cursor cursor = null; Loading Loading @@ -1230,7 +1227,7 @@ public abstract class InboundSmsHandler extends StateMachine { } else { } else { // set the delete selection args for multi-part message // set the delete selection args for multi-part message String[] deleteWhereArgs = {address, refNumber, count}; String[] deleteWhereArgs = {address, refNumber, count}; tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs); tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs); } } return Intents.RESULT_SMS_HANDLED; return Intents.RESULT_SMS_HANDLED; } catch (Exception e) { } catch (Exception e) { Loading
src/java/com/android/internal/telephony/InboundSmsTracker.java +40 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.internal.telephony; import android.content.ContentValues; import android.content.ContentValues; import android.database.Cursor; import android.database.Cursor; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.internal.util.HexDump; import java.util.Arrays; import java.util.Arrays; Loading Loading @@ -59,21 +60,47 @@ public class InboundSmsTracker { */ */ private final String mDisplayAddress; private final String mDisplayAddress; @VisibleForTesting /** Destination port flag bit for no destination port. */ /** Destination port flag bit for no destination port. */ private static final int DEST_PORT_FLAG_NO_PORT = (1 << 16); public static final int DEST_PORT_FLAG_NO_PORT = (1 << 16); /** Destination port flag bit to indicate 3GPP format message. */ /** Destination port flag bit to indicate 3GPP format message. */ private static final int DEST_PORT_FLAG_3GPP = (1 << 17); private static final int DEST_PORT_FLAG_3GPP = (1 << 17); @VisibleForTesting /** Destination port flag bit to indicate 3GPP2 format message. */ /** Destination port flag bit to indicate 3GPP2 format message. */ private static final int DEST_PORT_FLAG_3GPP2 = (1 << 18); public static final int DEST_PORT_FLAG_3GPP2 = (1 << 18); @VisibleForTesting /** Destination port flag bit to indicate 3GPP2 format WAP message. */ /** Destination port flag bit to indicate 3GPP2 format WAP message. */ private static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19); public static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19); /** Destination port mask (16-bit unsigned value on GSM and CDMA). */ /** Destination port mask (16-bit unsigned value on GSM and CDMA). */ private static final int DEST_PORT_MASK = 0xffff; private static final int DEST_PORT_MASK = 0xffff; @VisibleForTesting public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " + "count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0) AND deleted=0"; @VisibleForTesting public static final String SELECT_BY_REFERENCE_3GPP2WAP = "address=? AND reference_number=? " + "AND count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ") AND deleted=0"; @VisibleForTesting public static final String SELECT_BY_DUPLICATE_REFERENCE = "address=? AND " + "reference_number=? AND count=? AND sequence=? AND " + "((date=? AND message_body=?) OR deleted=0) AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0)"; @VisibleForTesting public static final String SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP = "address=? AND " + "reference_number=? " + "AND count=? AND sequence=? AND " + "((date=? AND message_body=?) OR deleted=0) AND " + "(destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ")"; /** /** * Create a tracker for a single-part SMS. * Create a tracker for a single-part SMS. * * Loading Loading @@ -190,7 +217,7 @@ public class InboundSmsTracker { + " of " + mMessageCount); + " of " + mMessageCount); } } mDeleteWhere = InboundSmsHandler.SELECT_BY_REFERENCE; mDeleteWhere = getQueryForSegments(); mDeleteWhereArgs = new String[]{mAddress, mDeleteWhereArgs = new String[]{mAddress, Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)}; Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)}; } } Loading Loading @@ -293,6 +320,15 @@ public class InboundSmsTracker { return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP; } } public String getQueryForSegments() { return mIs3gpp2WapPdu ? SELECT_BY_REFERENCE_3GPP2WAP : SELECT_BY_REFERENCE; } public String getQueryForMultiPartDuplicates() { return mIs3gpp2WapPdu ? SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP : SELECT_BY_DUPLICATE_REFERENCE; } /** /** * Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU * Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU * messages, which use a 0-based index. * messages, which use a 0-based index. Loading
src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -200,7 +200,7 @@ public class SmsBroadcastUndelivered { for (SmsReferenceKey message : oldMultiPartMessages) { for (SmsReferenceKey message : oldMultiPartMessages) { // delete permanently // delete permanently int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, InboundSmsHandler.SELECT_BY_REFERENCE, message.getDeleteWhereArgs()); message.getDeleteWhere(), message.getDeleteWhereArgs()); if (rows == 0) { if (rows == 0) { Rlog.e(TAG, "No rows were deleted from raw table!"); Rlog.e(TAG, "No rows were deleted from raw table!"); } else if (DBG) { } else if (DBG) { Loading Loading @@ -243,11 +243,14 @@ public class SmsBroadcastUndelivered { final String mAddress; final String mAddress; final int mReferenceNumber; final int mReferenceNumber; final int mMessageCount; final int mMessageCount; final String mQuery; SmsReferenceKey(InboundSmsTracker tracker) { SmsReferenceKey(InboundSmsTracker tracker) { mAddress = tracker.getAddress(); mAddress = tracker.getAddress(); mReferenceNumber = tracker.getReferenceNumber(); mReferenceNumber = tracker.getReferenceNumber(); mMessageCount = tracker.getMessageCount(); mMessageCount = tracker.getMessageCount(); mQuery = tracker.getQueryForSegments(); } } String[] getDeleteWhereArgs() { String[] getDeleteWhereArgs() { Loading @@ -255,6 +258,10 @@ public class SmsBroadcastUndelivered { Integer.toString(mMessageCount)}; Integer.toString(mMessageCount)}; } } String getDeleteWhere() { return mQuery; } @Override @Override public int hashCode() { public int hashCode() { return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); Loading
tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +125 −10 Original line number Original line Diff line number Diff line Loading @@ -146,7 +146,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { } } mSmsMessage.mWrappedSmsMessage = mGsmSmsMessage; mSmsMessage.mWrappedSmsMessage = mGsmSmsMessage; mInboundSmsTrackerCV.put("destination_port", 1 << 16); mInboundSmsTrackerCV.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("address", "1234567890"); mInboundSmsTrackerCV.put("reference_number", 1); mInboundSmsTrackerCV.put("reference_number", 1); Loading Loading @@ -317,10 +317,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); assertEquals("IdleState", getCurrentState().getName()); } } private void prepareMultiPartSms() { private void prepareMultiPartSms(boolean isWapPush) { // Part 1 // Part 1 mInboundSmsTrackerCVPart1 = new ContentValues(); mInboundSmsTrackerCVPart1 = new ContentValues(); mInboundSmsTrackerCVPart1.put("destination_port", 1 << 16); mInboundSmsTrackerCVPart1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart1.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart1.put("address", "1234567890"); mInboundSmsTrackerCVPart1.put("address", "1234567890"); mInboundSmsTrackerCVPart1.put("reference_number", 1); mInboundSmsTrackerCVPart1.put("reference_number", 1); Loading @@ -338,13 +337,40 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(mMessageBodyPart1).when(mInboundSmsTrackerPart1).getMessageBody(); doReturn(mMessageBodyPart1).when(mInboundSmsTrackerPart1).getMessageBody(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu(); doReturn(new String[]{mInboundSmsTrackerPart1.getAddress(), Integer.toString(mInboundSmsTrackerPart1.getReferenceNumber()), Integer.toString(mInboundSmsTrackerPart1.getMessageCount())}) .when(mInboundSmsTrackerPart1).getDeleteWhereArgs(); doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1). doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1). getTimestamp(); getTimestamp(); doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues(); doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues(); if (isWapPush) { mInboundSmsTrackerCVPart1.put("destination_port", (InboundSmsTracker.DEST_PORT_FLAG_3GPP2 | InboundSmsTracker.DEST_PORT_FLAG_3GPP2_WAP_PDU | SmsHeader.PORT_WAP_PUSH)); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart1) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP) .when(mInboundSmsTrackerPart1).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart1) .getDeleteWhere(); doReturn(SmsHeader.PORT_WAP_PUSH).when(mInboundSmsTrackerPart1).getDestPort(); doReturn(true).when(mInboundSmsTrackerPart1).is3gpp2(); } else { mInboundSmsTrackerCVPart1.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart1) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE) .when(mInboundSmsTrackerPart1).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart1) .getDeleteWhere(); } // Part 2 // Part 2 mInboundSmsTrackerCVPart2 = new ContentValues(); mInboundSmsTrackerCVPart2 = new ContentValues(); mInboundSmsTrackerCVPart2.put("destination_port", 1 << 16); mInboundSmsTrackerCVPart2.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart2.put("pdu", HexDump.toHexString(mSmsPdu)); mInboundSmsTrackerCVPart2.put("address", "1234567890"); mInboundSmsTrackerCVPart2.put("address", "1234567890"); mInboundSmsTrackerCVPart2.put("reference_number", 1); mInboundSmsTrackerCVPart2.put("reference_number", 1); Loading @@ -362,9 +388,98 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(mMessageBodyPart2).when(mInboundSmsTrackerPart2).getMessageBody(); doReturn(mMessageBodyPart2).when(mInboundSmsTrackerPart2).getMessageBody(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu(); doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu(); doReturn(new String[]{mInboundSmsTrackerPart2.getAddress(), Integer.toString(mInboundSmsTrackerPart2.getReferenceNumber()), Integer.toString(mInboundSmsTrackerPart2.getMessageCount())}) .when(mInboundSmsTrackerPart2).getDeleteWhereArgs(); doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2). doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2). getTimestamp(); getTimestamp(); doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues(); doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues(); if (isWapPush) { mInboundSmsTrackerCVPart2.put("destination_port", (InboundSmsTracker.DEST_PORT_FLAG_3GPP2 | InboundSmsTracker.DEST_PORT_FLAG_3GPP2_WAP_PDU | SmsHeader.PORT_WAP_PUSH)); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart2) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP) .when(mInboundSmsTrackerPart2).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE_3GPP2WAP).when(mInboundSmsTrackerPart2) .getDeleteWhere(); doReturn(SmsHeader.PORT_WAP_PUSH).when(mInboundSmsTrackerPart2).getDestPort(); doReturn(true).when(mInboundSmsTrackerPart2).is3gpp2(); } else { mInboundSmsTrackerCVPart2.put("destination_port", InboundSmsTracker.DEST_PORT_FLAG_NO_PORT); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart2) .getQueryForSegments(); doReturn(InboundSmsTracker.SELECT_BY_DUPLICATE_REFERENCE) .when(mInboundSmsTrackerPart2).getQueryForMultiPartDuplicates(); doReturn(InboundSmsTracker.SELECT_BY_REFERENCE).when(mInboundSmsTrackerPart2) .getDeleteWhere(); } } @Test @MediumTest public void testMultiPartSmsWithIncompleteWAP() { /** * Test scenario: 3 messages are received with same address, ref number, count. two of the * messages are belonging to the same multi-part SMS and the other one is a 3GPP2WAP. * we should not try to merge 3gpp2wap with the multi-part SMS. */ transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); // part 2 of non-3gpp2wap arrives first doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // State machine should go back to idle and wait for second part assertEquals("IdleState", getCurrentState().getName()); // mock a 3gpp2wap push prepareMultiPartSms(true); doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // State machine should go back to idle and wait for second part assertEquals("IdleState", getCurrentState().getName()); // verify no broadcast sent. verify(mContext, times(0)).sendBroadcast(any(Intent.class)); // additional copy of part 1 of non-3gpp2wap prepareMultiPartSms(false); doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(), nullable(String.class), nullable(String.class), anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class)); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(200); // verify broadcast intents verifySmsIntentBroadcasts(0); assertEquals("IdleState", getCurrentState().getName()); // verify there are three segments in the db and only one of them is not marked as deleted. assertEquals(3, mContentProvider.getNumRows()); assertEquals(1, mContentProvider.query(sRawUri, null, "deleted=0", null, null).getCount()); } } @FlakyTest @FlakyTest Loading @@ -374,7 +489,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); Loading Loading @@ -421,7 +536,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { // timestamps, should not be combined with the additional part 2 received above // timestamps, should not be combined with the additional part 2 received above // call prepareMultiPartSms() to update timestamps // call prepareMultiPartSms() to update timestamps prepareMultiPartSms(); prepareMultiPartSms(false); // part 1 of new sms // part 1 of new sms doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) Loading @@ -448,7 +563,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); // change seqNumber in part 2 to 1 // change seqNumber in part 2 to 1 mInboundSmsTrackerCVPart2.put("sequence", 1); mInboundSmsTrackerCVPart2.put("sequence", 1); doReturn(1).when(mInboundSmsTrackerPart2).getSequenceNumber(); doReturn(1).when(mInboundSmsTrackerPart2).getSequenceNumber(); Loading Loading @@ -491,7 +606,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); mSmsHeader.concatRef = new SmsHeader.ConcatRef(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); Loading Loading @@ -527,7 +642,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { transitionFromStartupToIdle(); transitionFromStartupToIdle(); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); // only the first SMS is configured with the display originating email address // only the first SMS is configured with the display originating email address mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890@test.com"); mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890@test.com"); Loading Loading @@ -643,7 +758,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null); // prepare SMS part 1 and part 2 // prepare SMS part 1 and part 2 prepareMultiPartSms(); prepareMultiPartSms(false); //add the 2 SMS parts to db //add the 2 SMS parts to db mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart1); mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart1); Loading