Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0527c02e authored by Amit Mahajan's avatar Amit Mahajan Committed by android-build-merger
Browse files

Merge "Changes to de-dup messages in SMS raw table." into nyc-dev

am: 9fff8118

* commit '9fff8118':
  Changes to de-dup messages in SMS raw table.

Change-Id: I62dd900c16feb205a61f53ccfa1516abb0d441ae
parents e9ffc868 9fff8118
Loading
Loading
Loading
Loading
+51 −49
Original line number Original line Diff line number Diff line
@@ -125,7 +125,8 @@ public abstract class InboundSmsHandler extends StateMachine {
    public static final int ID_COLUMN = 7;
    public static final int ID_COLUMN = 7;


    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=?";
    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;
@@ -161,6 +162,8 @@ public abstract class InboundSmsHandler extends StateMachine {


    /** URI for raw table of SMS provider. */
    /** URI for raw table of SMS provider. */
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");


    protected final Context mContext;
    protected final Context mContext;
    private final ContentResolver mResolver;
    private final ContentResolver mResolver;
@@ -790,13 +793,13 @@ public abstract class InboundSmsHandler extends StateMachine {
            if (result == Activity.RESULT_OK) {
            if (result == Activity.RESULT_OK) {
                return true;
                return true;
            } else {
            } else {
                deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs());
                deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), false);
                return false;
                return false;
            }
            }
        }
        }


        if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
        if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs());
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), true);
            return false;
            return false;
        }
        }


@@ -983,8 +986,10 @@ public abstract class InboundSmsHandler extends StateMachine {
    /**
    /**
     * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table.
     * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table.
     */
     */
    private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs) {
    private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs,
        int rows = mResolver.delete(sRawUri, deleteWhere, deleteWhereArgs);
                                    boolean permanentDelete) {
        Uri uri = permanentDelete ? sRawUriPermanentDelete : sRawUri;
        int rows = mResolver.delete(uri, deleteWhere, deleteWhereArgs);
        if (rows == 0) {
        if (rows == 0) {
            loge("No rows were deleted from raw table!");
            loge("No rows were deleted from raw table!");
        } else if (DBG) {
        } else if (DBG) {
@@ -1074,7 +1079,6 @@ public abstract class InboundSmsHandler extends StateMachine {
     * @return true on success; false on failure to write to database
     * @return true on success; false on failure to write to database
     */
     */
    private int addTrackerToRawTable(InboundSmsTracker tracker) {
    private int addTrackerToRawTable(InboundSmsTracker tracker) {
        if (tracker.getMessageCount() != 1) {
        // check for duplicate message segments
        // check for duplicate message segments
        Cursor cursor = null;
        Cursor cursor = null;
        try {
        try {
@@ -1085,8 +1089,8 @@ public abstract class InboundSmsHandler extends StateMachine {
            String address = tracker.getAddress();
            String address = tracker.getAddress();
            String refNumber = Integer.toString(tracker.getReferenceNumber());
            String refNumber = Integer.toString(tracker.getReferenceNumber());
            String count = Integer.toString(tracker.getMessageCount());
            String count = Integer.toString(tracker.getMessageCount());

            String seqNumber = Integer.toString(sequence);
            String seqNumber = Integer.toString(sequence);
            String date = Long.toString(tracker.getTimestamp());


            // 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};
@@ -1094,8 +1098,8 @@ public abstract class InboundSmsHandler extends StateMachine {


            // Check for duplicate message segments
            // Check for duplicate message segments
            cursor = mResolver.query(sRawUri, PDU_PROJECTION,
            cursor = mResolver.query(sRawUri, PDU_PROJECTION,
                        "address=? AND reference_number=? AND count=? AND sequence=?",
                    "address=? AND reference_number=? AND count=? AND sequence=? AND date=?",
                        new String[] {address, refNumber, count, seqNumber}, null);
                    new String[] {address, refNumber, count, seqNumber, date}, null);


            // moveToNext() returns false if no duplicates were found
            // moveToNext() returns false if no duplicates were found
            if (cursor.moveToNext()) {
            if (cursor.moveToNext()) {
@@ -1110,7 +1114,6 @@ public abstract class InboundSmsHandler extends StateMachine {
                }
                }
                return Intents.RESULT_SMS_DUPLICATED;   // reject message
                return Intents.RESULT_SMS_DUPLICATED;   // reject message
            }
            }
                cursor.close();
        } catch (SQLException e) {
        } catch (SQLException e) {
            loge("Can't access multipart SMS database", e);
            loge("Can't access multipart SMS database", e);
            return Intents.RESULT_SMS_GENERIC_ERROR;    // reject message
            return Intents.RESULT_SMS_GENERIC_ERROR;    // reject message
@@ -1119,7 +1122,6 @@ public abstract class InboundSmsHandler extends StateMachine {
                cursor.close();
                cursor.close();
            }
            }
        }
        }
        }


        ContentValues values = tracker.getContentValues();
        ContentValues values = tracker.getContentValues();


@@ -1212,7 +1214,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                    log("successful broadcast, deleting from raw table.");
                    log("successful broadcast, deleting from raw table.");
                }
                }


                deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs);
                deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, false);
                sendMessage(EVENT_BROADCAST_COMPLETE);
                sendMessage(EVENT_BROADCAST_COMPLETE);


                int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000);
                int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000);
@@ -1318,7 +1320,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                try {
                try {
                    // Needs phone package permissions.
                    // Needs phone package permissions.
                    deleteFromRawTable(mSmsFilter.mSmsBroadcastReceiver.mDeleteWhere,
                    deleteFromRawTable(mSmsFilter.mSmsBroadcastReceiver.mDeleteWhere,
                            mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs);
                            mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs, false);
                } finally {
                } finally {
                    Binder.restoreCallingIdentity(token);
                    Binder.restoreCallingIdentity(token);
                }
                }
+8 −3
Original line number Original line Diff line number Diff line
@@ -65,6 +65,8 @@ public class SmsBroadcastUndelivered {


    /** URI for raw table from SmsProvider. */
    /** URI for raw table from SmsProvider. */
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
    private static SmsBroadcastUndelivered instance;
    private static SmsBroadcastUndelivered instance;


    /** Content resolver to use to access raw table from SmsProvider. */
    /** Content resolver to use to access raw table from SmsProvider. */
@@ -135,7 +137,9 @@ public class SmsBroadcastUndelivered {
        HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4);
        HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4);
        Cursor cursor = null;
        Cursor cursor = null;
        try {
        try {
            cursor = mResolver.query(sRawUri, PDU_PENDING_MESSAGE_PROJECTION, null, null, null);
            // query only non-deleted ones
            cursor = mResolver.query(sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null,
                    null);
            if (cursor == null) {
            if (cursor == null) {
                Rlog.e(TAG, "error getting pending message cursor");
                Rlog.e(TAG, "error getting pending message cursor");
                return;
                return;
@@ -182,8 +186,9 @@ public class SmsBroadcastUndelivered {
            }
            }
            // Delete old incomplete message segments
            // Delete old incomplete message segments
            for (SmsReferenceKey message : oldMultiPartMessages) {
            for (SmsReferenceKey message : oldMultiPartMessages) {
                int rows = mResolver.delete(sRawUri, InboundSmsHandler.SELECT_BY_REFERENCE,
                // delete permanently
                        message.getDeleteWhereArgs());
                int rows = mResolver.delete(sRawUriPermanentDelete,
                        InboundSmsHandler.SELECT_BY_REFERENCE, 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) {
+1 −1
Original line number Original line Diff line number Diff line
@@ -52,7 +52,7 @@ public abstract class SmsMessageBase {
    /** {@hide} */
    /** {@hide} */
    protected boolean mIsEmail;
    protected boolean mIsEmail;


    /** {@hide} */
    /** {@hide} Time when SC (service centre) received the message */
    protected long mScTimeMillis;
    protected long mScTimeMillis;


    /** {@hide} The raw PDU of the message */
    /** {@hide} The raw PDU of the message */
+161 −37
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ import org.mockito.Mock;


import java.lang.reflect.Method;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;


public class GsmInboundSmsHandlerTest extends TelephonyTest {
public class GsmInboundSmsHandlerTest extends TelephonyTest {
    @Mock
    @Mock
@@ -77,6 +78,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {


    private FakeSmsContentProvider mContentProvider;
    private FakeSmsContentProvider mContentProvider;
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");

    private ContentValues mInboundSmsTrackerCV = new ContentValues();
    private ContentValues mInboundSmsTrackerCV = new ContentValues();
    // For multi-part SMS
    // For multi-part SMS
    private ContentValues mInboundSmsTrackerCVPart1;
    private ContentValues mInboundSmsTrackerCVPart1;
@@ -93,13 +97,56 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                "destination_port",
                "destination_port",
                "address",
                "address",
                "sub_id",
                "sub_id",
                "pdu"};
                "pdu",
        private MatrixCursor mRawCursor = new MatrixCursor(mRawColumns);
                "deleted"};
        private List<ArrayList<Object>> mListOfRows = new ArrayList<ArrayList<Object>>();
        private int mNumRows = 0;
        private int mNumRows = 0;


        private int getColumnIndex(String columnName) {
            int i = 0;
            for (String s : mRawColumns) {
                if (s.equals(columnName)) {
                    break;
                }
                i++;
            }
            return i;
        }

        @Override
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            return 0;
            int count = 0;
            if (mNumRows > 0) {
                // parse selection and selectionArgs
                SelectionParams selectionParams = new SelectionParams();
                selectionParams.parseSelectionParams(selection, selectionArgs);

                List<Integer> deleteRows = new ArrayList<Integer>();
                int i = -1;
                for (ArrayList<Object> row : mListOfRows) {
                    i++;
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        if (!selectionParams.isMatch(row)) {
                            continue;
                        }
                    }
                    if (uri.compareTo(sRawUri) == 0) {
                        row.set(getColumnIndex("deleted"), "1");
                    } else {
                        // save index for removal
                        deleteRows.add(i);
                    }
                    count++;
                }

                if (uri.compareTo(sRawUriPermanentDelete) == 0) {
                    for (i = deleteRows.size() - 1; i >= 0; i--) {
                        mListOfRows.remove(i);
                    }
                }
            }
            return count;
        }
        }


        @Override
        @Override
@@ -107,7 +154,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            Uri newUri = null;
            Uri newUri = null;
            if (uri.compareTo(sRawUri) == 0) {
            if (uri.compareTo(sRawUri) == 0) {
                if (values != null) {
                if (values != null) {
                    mRawCursor.addRow(convertRawCVtoArrayList(values));
                    mListOfRows.add(convertRawCVtoArrayList(values));
                    mNumRows++;
                    mNumRows++;
                    newUri = Uri.withAppendedPath(uri, "" + mNumRows);
                    newUri = Uri.withAppendedPath(uri, "" + mNumRows);
                }
                }
@@ -120,9 +167,11 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            ArrayList<Object> newRow = new ArrayList<>();
            ArrayList<Object> newRow = new ArrayList<>();
            for (String key : mRawColumns) {
            for (String key : mRawColumns) {
                if (values.containsKey(key)) {
                if (values.containsKey(key)) {
                    newRow.add(values.get(key));
                    newRow.add(values.getAsString(key));
                } else if (key.equals("_id")) {
                } else if (key.equals("_id")) {
                    newRow.add(mNumRows + 1);
                    newRow.add(mNumRows + 1);
                } else if (key.equals("deleted")) {
                    newRow.add("0");
                } else {
                } else {
                    newRow.add(null);
                    newRow.add(null);
                }
                }
@@ -130,15 +179,11 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            return newRow;
            return newRow;
        }
        }


        @Override
        private class SelectionParams {
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                            String sortOrder) {
            logd("query called for: " + selection);
            MatrixCursor cursor = new MatrixCursor(projection);
            if (mNumRows > 0) {
                // parse selection and selectionArgs
            String[] paramName = null;
            String[] paramName = null;
            String[] paramValue = null;
            String[] paramValue = null;

            private void parseSelectionParams(String selection, String[] selectionArgs) {
                if (selection != null) {
                if (selection != null) {
                    selection = selection.toLowerCase();
                    selection = selection.toLowerCase();
                    String[] selectionParams = selection.toLowerCase().split("and");
                    String[] selectionParams = selection.toLowerCase().split("and");
@@ -157,38 +202,52 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                        }
                        }
                    }
                    }
                }
                }
            }


                mRawCursor.moveToFirst();
            private boolean isMatch(ArrayList<Object> row) {
                do {
                    ArrayList<Object> row = new ArrayList<>();
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        boolean match = true;
                for (int i = 0; i < paramName.length; i++) {
                for (int i = 0; i < paramName.length; i++) {
                    int columnIndex = 0;
                    for (String columnName : mRawColumns) {
                    for (String columnName : mRawColumns) {
                                int columnIndex = mRawCursor.getColumnIndex(columnName);
                        if (columnName.equals(paramName[i])) {
                                if (columnName.equals(paramName[i]) &&
                            if (!paramValue[i].equals(row.get(columnIndex))) {
                                        !mRawCursor.getString(columnIndex).equals(paramValue[i])) {
                                return false;
                                    match = false;
                            } else {
                                // move on to next param
                                break;
                                break;
                            }
                            }
                        }
                        }
                            if (!match) {
                        columnIndex++;
                                break;
                    }
                }
                }
                return true;
            }
            }
                        // move on to next row if current one does not satisfy selection criteria
        }
                        if (!match) {

        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                            String sortOrder) {
            logd("query called for: " + selection);
            MatrixCursor cursor = new MatrixCursor(projection);
            if (mNumRows > 0) {
                // parse selection and selectionArgs
                SelectionParams selectionParams = new SelectionParams();
                selectionParams.parseSelectionParams(selection, selectionArgs);

                for (ArrayList<Object> row : mListOfRows) {
                    ArrayList<Object> retRow = new ArrayList<>();
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        if (!selectionParams.isMatch(row)) {
                            continue;
                            continue;
                        }
                        }
                    }
                    }


                    for (String columnName : projection) {
                    for (String columnName : projection) {
                        int columnIndex = mRawCursor.getColumnIndex(columnName);
                        int columnIndex = getColumnIndex(columnName);
                        row.add(mRawCursor.getString(columnIndex));
                        retRow.add(row.get(columnIndex));
                    }
                    cursor.addRow(retRow);
                }
                }
                    cursor.addRow(row);
                } while(mRawCursor.moveToNext());
            }
            }
            if (cursor != null) {
            if (cursor != null) {
                logd("returning rows: " + cursor.getCount());
                logd("returning rows: " + cursor.getCount());
@@ -383,6 +442,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        mInboundSmsTrackerCVPart1.put("reference_number", 1);
        mInboundSmsTrackerCVPart1.put("reference_number", 1);
        mInboundSmsTrackerCVPart1.put("sequence", 1);
        mInboundSmsTrackerCVPart1.put("sequence", 1);
        mInboundSmsTrackerCVPart1.put("count", 2);
        mInboundSmsTrackerCVPart1.put("count", 2);
        mInboundSmsTrackerCVPart1.put("date", System.currentTimeMillis());


        doReturn(2).when(mInboundSmsTrackerPart1).getMessageCount();
        doReturn(2).when(mInboundSmsTrackerPart1).getMessageCount();
        doReturn(1).when(mInboundSmsTrackerPart1).getReferenceNumber();
        doReturn(1).when(mInboundSmsTrackerPart1).getReferenceNumber();
@@ -391,6 +451,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        doReturn(1).when(mInboundSmsTrackerPart1).getIndexOffset();
        doReturn(1).when(mInboundSmsTrackerPart1).getIndexOffset();
        doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort();
        doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu();
        doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1).
                getTimestamp();
        doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues();
        doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues();


        // Part 2
        // Part 2
@@ -401,6 +463,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        mInboundSmsTrackerCVPart2.put("reference_number", 1);
        mInboundSmsTrackerCVPart2.put("reference_number", 1);
        mInboundSmsTrackerCVPart2.put("sequence", 2);
        mInboundSmsTrackerCVPart2.put("sequence", 2);
        mInboundSmsTrackerCVPart2.put("count", 2);
        mInboundSmsTrackerCVPart2.put("count", 2);
        mInboundSmsTrackerCVPart2.put("date", System.currentTimeMillis());


        doReturn(2).when(mInboundSmsTrackerPart2).getMessageCount();
        doReturn(2).when(mInboundSmsTrackerPart2).getMessageCount();
        doReturn(1).when(mInboundSmsTrackerPart2).getReferenceNumber();
        doReturn(1).when(mInboundSmsTrackerPart2).getReferenceNumber();
@@ -409,6 +472,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        doReturn(1).when(mInboundSmsTrackerPart2).getIndexOffset();
        doReturn(1).when(mInboundSmsTrackerPart2).getIndexOffset();
        doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort();
        doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu();
        doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2).
                getTimestamp();
        doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues();
        doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues();
    }
    }


@@ -422,10 +487,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {


        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();

        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());

        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
                mSmsMessage, null));
        waitForMs(100);
        waitForMs(100);
@@ -440,7 +505,42 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                mSmsMessage, null));
                mSmsMessage, null));
        waitForMs(100);
        waitForMs(100);


        // verify broadcast intents
        verifySmsIntentBroadcasts(0);
        verifySmsIntentBroadcasts(0);

        // if an additional copy of one of the segments above is received, it should not be kept in
        // the db and should not be combined with any subsequent messages received from the same
        // sender

        // additional copy of part 2 of message
        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
        waitForMs(100);

        // verify no additional broadcasts sent
        verify(mContext, times(2)).sendBroadcast(any(Intent.class));

        // part 1 of new sms recieved from same sender with same parameters, just different
        // timestamps, should not be combined with the additional part 2 received above

        // call prepareMultiPartSms() to update timestamps
        prepareMultiPartSms();

        // part 1 of new sms
        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
        waitForMs(100);

        // verify no additional broadcasts sent
        verify(mContext, times(2)).sendBroadcast(any(Intent.class));

        assertEquals("IdleState", getCurrentState().getName());
    }
    }


    @Test
    @Test
@@ -498,6 +598,30 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        verifyDataSmsIntentBroadcasts(1);
        verifyDataSmsIntentBroadcasts(1);
    }
    }


    @Test
    @MediumTest
    public void testBroadcastUndeliveredDeleted() throws Exception {
        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
        doReturn(0).when(mInboundSmsTracker).getDestPort();

        //add a fake entry to db
        ContentValues rawSms = new ContentValues();
        rawSms.put("deleted", 1);
        mContentProvider.insert(sRawUri, rawSms);

        //make it a single-part message
        doReturn(1).when(mInboundSmsTracker).getMessageCount();

        //when user unlocks the device, broadcast should not be sent for new message
        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED));
        waitForMs(100);

        verify(mContext, times(1)).sendBroadcast(any(Intent.class));
        assertEquals("IdleState", getCurrentState().getName());

    }

    @Test
    @Test
    @MediumTest
    @MediumTest
    public void testBroadcastUndeliveredMultiPart() throws Exception {
    public void testBroadcastUndeliveredMultiPart() throws Exception {