132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan/*
22f2dba9413a3f14da0bcf45031986eb78f007dd8fionaxu * Copyright (C) 2016 The Android Open Source Project
332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan *
432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * Licensed under the Apache License, Version 2.0 (the "License");
532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * you may not use this file except in compliance with the License.
632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * You may obtain a copy of the License at
732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan *
832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan *      http://www.apache.org/licenses/LICENSE-2.0
932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan *
1032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * Unless required by applicable law or agreed to in writing, software
1132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * distributed under the License is distributed on an "AS IS" BASIS,
1232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * See the License for the specific language governing permissions and
1432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan * limitations under the License.
1532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan */
1632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
1732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanpackage com.android.internal.telephony.gsm;
1832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
195eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastryimport android.content.BroadcastReceiver;
20e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.content.ContentValues;
21e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.content.Context;
22e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.content.Intent;
23e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.content.IntentFilter;
24e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.database.Cursor;
25e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.database.MatrixCursor;
26e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.net.Uri;
27e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.os.AsyncResult;
28e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport android.os.Bundle;
29655bae990bdd7e4584491def4d30692e6173779cfionaxuimport android.os.Handler;
30655bae990bdd7e4584491def4d30692e6173779cfionaxuimport android.os.HandlerThread;
3132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport android.os.UserManager;
321bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yuimport android.os.RemoteException;
331bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yuimport android.os.UserHandle;
34153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajanimport android.provider.Telephony;
356ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxuimport android.test.mock.MockContentProvider;
366ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxuimport android.test.mock.MockContentResolver;
37871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajanimport android.test.suitebuilder.annotation.MediumTest;
38e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry
39b9d551db1795b30598e2ce98cfae7106788c12d6fionaxuimport com.android.internal.telephony.InboundSmsHandler;
401bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yuimport com.android.internal.telephony.InboundSmsTracker;
4132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport com.android.internal.telephony.SmsBroadcastUndelivered;
4232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport com.android.internal.telephony.SmsHeader;
43ec6e2f9f13bac23cdfa0de0a56826b21050b6487fionaxuimport com.android.internal.telephony.SmsStorageMonitor;
44e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport com.android.internal.telephony.TelephonyTest;
4532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
461fe1dbf473755c4e812a1218f331759eccacb447Jack Yuimport com.android.internal.util.HexDump;
47e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport com.android.internal.util.IState;
48e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastryimport com.android.internal.util.StateMachine;
4932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
50655bae990bdd7e4584491def4d30692e6173779cfionaxuimport static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
51f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajanimport static org.junit.Assert.*;
5232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport static org.mockito.Mockito.*;
53f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu
54f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxuimport org.junit.After;
5575ba09a17a669f4906268088a769836aa87d8241fionaxuimport org.junit.Before;
5632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport org.junit.Test;
5732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanimport org.mockito.ArgumentCaptor;
58dbe4d7749d5524be575f629486874acdae721138Amit Mahajanimport org.mockito.Mock;
5932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
60f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxuimport java.lang.reflect.Method;
61f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxuimport java.util.ArrayList;
62ec6e2f9f13bac23cdfa0de0a56826b21050b6487fionaxuimport java.util.List;
6332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
6432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajanpublic class GsmInboundSmsHandlerTest extends TelephonyTest {
6532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    @Mock
66655bae990bdd7e4584491def4d30692e6173779cfionaxu    private SmsStorageMonitor mSmsStorageMonitor;
67e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry    @Mock
68153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan    private android.telephony.SmsMessage mSmsMessage;
69153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan    @Mock
7078867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan    private SmsMessage mGsmSmsMessage;
7132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    @Mock
7232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private SmsHeader mSmsHeader;
7332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    @Mock
7432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private InboundSmsTracker mInboundSmsTrackerPart1;
75e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry    @Mock
76e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry    private InboundSmsTracker mInboundSmsTrackerPart2;
7732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    @Mock
7832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private CdmaInboundSmsHandler mCdmaInboundSmsHandler;
7932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
80e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry    private GsmInboundSmsHandler mGsmInboundSmsHandler;
819c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
829c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    private FakeSmsContentProvider mContentProvider;
83e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
8432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private static final Uri sRawUriPermanentDelete =
8532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
8632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
8732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private ContentValues mInboundSmsTrackerCV = new ContentValues();
8832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    // For multi-part SMS
89f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan    private ContentValues mInboundSmsTrackerCVPart1;
9032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private ContentValues mInboundSmsTrackerCVPart2;
91f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu    private String mMessageBody = "This is the message body of a single-part message";
92f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu    private String mMessageBodyPart1 = "This is the first part of a multi-part message";
9332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    private String mMessageBodyPart2 = "This is the second part of a multi-part message";
9432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
9532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    byte[] mSmsPdu = new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF};
9632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
97f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu    public static class FakeSmsContentProvider extends MockContentProvider {
98f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu        private String[] mRawColumns = {"_id",
9932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "date",
10032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "reference_number",
10132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "count",
10232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "sequence",
10332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "destination_port",
10432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "address",
10532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "sub_id",
10632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "pdu",
10732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "deleted",
10832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                "message_body"};
10932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        private List<ArrayList<Object>> mListOfRows = new ArrayList<ArrayList<Object>>();
11032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        private int mNumRows = 0;
11132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
11232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        private int getColumnIndex(String columnName) {
11332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            int i = 0;
11432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            for (String s : mRawColumns) {
11575ba09a17a669f4906268088a769836aa87d8241fionaxu                if (s.equals(columnName)) {
11632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                    break;
11732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                }
11832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                i++;
1194a9f066fbcbd20e2ea3ca3cbc914f81b230e3825fionaxu            }
1204a9f066fbcbd20e2ea3ca3cbc914f81b230e3825fionaxu            return i;
121f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu        }
122f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu
123f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu        @Override
124f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu        public int delete(Uri uri, String selection, String[] selectionArgs) {
12575ba09a17a669f4906268088a769836aa87d8241fionaxu            int count = 0;
12675ba09a17a669f4906268088a769836aa87d8241fionaxu            if (mNumRows > 0) {
12732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                // parse selection and selectionArgs
12832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                SelectionParams selectionParams = new SelectionParams();
12932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                selectionParams.parseSelectionParams(selection, selectionArgs);
13032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
13132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                List<Integer> deleteRows = new ArrayList<Integer>();
13232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                int i = -1;
13332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                for (ArrayList<Object> row : mListOfRows) {
13460a81bdb47cf64972c8edf5b0c51e8059765e5a0Amit Mahajan                    i++;
13560a81bdb47cf64972c8edf5b0c51e8059765e5a0Amit Mahajan                    // filter based on selection parameters if needed
13660a81bdb47cf64972c8edf5b0c51e8059765e5a0Amit Mahajan                    if (selection != null) {
13760a81bdb47cf64972c8edf5b0c51e8059765e5a0Amit Mahajan                        if (!selectionParams.isMatch(row)) {
138f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                            continue;
139153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                        }
14078867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan                    }
141153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                    if (uri.compareTo(sRawUri) == 0) {
142153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                        row.set(getColumnIndex("deleted"), "1");
143153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                    } else {
144153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                        // save index for removal
145153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                        deleteRows.add(i);
146153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                    }
147153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                    count++;
148153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                }
149153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan
150655bae990bdd7e4584491def4d30692e6173779cfionaxu                if (uri.compareTo(sRawUriPermanentDelete) == 0) {
151655bae990bdd7e4584491def4d30692e6173779cfionaxu                    for (i = deleteRows.size() - 1; i >= 0; i--) {
152655bae990bdd7e4584491def4d30692e6173779cfionaxu                        mListOfRows.remove(i);
153217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan                    }
154217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan                }
155217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan            }
15627f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan            return count;
15727f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        }
1581bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu
1591bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu        @Override
1601bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu        public Uri insert(Uri uri, ContentValues values) {
1611bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu            Uri newUri = null;
1626ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu            if (uri.compareTo(sRawUri) == 0) {
1636ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu                if (values != null) {
1646ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu                    mListOfRows.add(convertRawCVtoArrayList(values));
1656ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu                    mNumRows++;
1666ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu                    newUri = Uri.withAppendedPath(uri, "" + mNumRows);
1676ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu                }
168dbe4d7749d5524be575f629486874acdae721138Amit Mahajan            }
169dbe4d7749d5524be575f629486874acdae721138Amit Mahajan            logd("insert called, new numRows: " + mNumRows);
1707a1c1b02c8603c2bf2f3b401facb389528180eedPavel Zhamaitsiak            return newUri;
1717a1c1b02c8603c2bf2f3b401facb389528180eedPavel Zhamaitsiak        }
17232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
173af59a35e945d60fc9ffb305c494a695b35b8a942fionaxu        private ArrayList<Object> convertRawCVtoArrayList(ContentValues values) {
17432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            ArrayList<Object> newRow = new ArrayList<>();
17532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            for (String key : mRawColumns) {
176f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                if (values.containsKey(key)) {
177e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry                    newRow.add(values.getAsString(key));
178f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                } else if (key.equals("_id")) {
179f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                    newRow.add(mNumRows + 1);
180ec6e2f9f13bac23cdfa0de0a56826b21050b6487fionaxu                } else if (key.equals("deleted")) {
181ec6e2f9f13bac23cdfa0de0a56826b21050b6487fionaxu                    newRow.add("0");
182f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                } else {
18375ba09a17a669f4906268088a769836aa87d8241fionaxu                    newRow.add(null);
1849c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                }
1859c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            }
1869c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            return newRow;
1879c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        }
1889c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
1899c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        private class SelectionParams {
1909c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            String[] paramName = null;
1919c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            String[] paramValue = null;
1929c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
1939c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            private void parseSelectionParams(String selection, String[] selectionArgs) {
1949c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                if (selection != null) {
1959c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    selection = selection.toLowerCase();
1969c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    String[] selectionParams = selection.toLowerCase().split("and");
1979c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    int i = 0;
1989c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    int j = 0;
1999c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    paramName = new String[selectionParams.length];
2009c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    paramValue = new String[selectionParams.length];
2019c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    for (String param : selectionParams) {
2029c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        String[] paramWithArg = param.split("=");
2039c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        paramName[i] = paramWithArg[0].trim();
2049c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        if (param.contains("?")) {
2059c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                            paramValue[i] = selectionArgs[j];
2069c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                            j++;
2079c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        } else {
2089c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                            paramValue[i] = paramWithArg[1].trim();
2099c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        }
210655bae990bdd7e4584491def4d30692e6173779cfionaxu                        //logd(paramName[i] + " = " + paramValue[i]);
211655bae990bdd7e4584491def4d30692e6173779cfionaxu                        i++;
2129c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    }
2139c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                }
21432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            }
21532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
216655bae990bdd7e4584491def4d30692e6173779cfionaxu            private boolean isMatch(ArrayList<Object> row) {
21732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                for (int i = 0; i < paramName.length; i++) {
21832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                    int columnIndex = 0;
21932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                    for (String columnName : mRawColumns) {
22032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                        if (columnName.equals(paramName[i])) {
22132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                            if ((paramValue[i] == null && row.get(columnIndex) != null) ||
22232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                    (paramValue[i] != null &&
22332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                            !paramValue[i].equals(row.get(columnIndex)))) {
22432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                logd("Not a match due to " + columnName + ": " + paramValue[i] +
22532b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                        ", " + row.get(columnIndex));
22632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                return false;
22732b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                            } else {
22832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                // move on to next param
22932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                                break;
23032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                            }
2319c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        }
2329c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        columnIndex++;
2339c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    }
2349c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                }
23521e1b42d578d90611f76c37d58841543821502fdJack Yu                return true;
23632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            }
2379c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        }
2389c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
2399c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        @Override
2409c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
2419c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                            String sortOrder) {
2429c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            logd("query called for: " + selection);
2439c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            MatrixCursor cursor = new MatrixCursor(projection);
24432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            if (mNumRows > 0) {
2459c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                // parse selection and selectionArgs
2469c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                SelectionParams selectionParams = new SelectionParams();
2479c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                selectionParams.parseSelectionParams(selection, selectionArgs);
2489c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
2499c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                for (ArrayList<Object> row : mListOfRows) {
2509c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    ArrayList<Object> retRow = new ArrayList<>();
2519c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    // filter based on selection parameters if needed
2529c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    if (selection != null) {
2539c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        if (!selectionParams.isMatch(row)) {
2549c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                            continue;
2559c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        }
25632b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                    }
2579c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
2589c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    for (String columnName : projection) {
25932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                        int columnIndex = getColumnIndex(columnName);
2609c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                        retRow.add(row.get(columnIndex));
2619c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    }
2629c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    cursor.addRow(retRow);
2639c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                }
2649c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            }
2659c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            if (cursor != null) {
266f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan                logd("returning rows: " + cursor.getCount());
2679c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            }
2689c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            return cursor;
2699c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        }
27032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
2719c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        @Override
2729c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        public Bundle call(String method, String request, Bundle args) {
2739c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            return null;
27421e1b42d578d90611f76c37d58841543821502fdJack Yu        }
2759c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    }
2769c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
2779c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    private class GsmInboundSmsHandlerTestHandler extends HandlerThread {
2789c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
2799c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        private GsmInboundSmsHandlerTestHandler(String name) {
2809c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            super(name);
2819c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        }
2829c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu
283655bae990bdd7e4584491def4d30692e6173779cfionaxu        @Override
284217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        public void onLooperPrepared() {
2859c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(mContext,
2869c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu                    mSmsStorageMonitor, mPhone);
2879c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu            setReady(true);
2889c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        }
289325ea5a0aa71b9ff6134be71a84a7e1a288c70cbJack Yu    }
290325ea5a0aa71b9ff6134be71a84a7e1a288c70cbJack Yu
291ec6e2f9f13bac23cdfa0de0a56826b21050b6487fionaxu    private IState getCurrentState() {
29232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        try {
29332b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
29432b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan            method.setAccessible(true);
295f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan            return (IState) method.invoke(mGsmInboundSmsHandler);
296e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        } catch (Exception e) {
297e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry            fail(e.toString());
298e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry            return null;
29932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        }
3009c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    }
301af59a35e945d60fc9ffb305c494a695b35b8a942fionaxu
30232b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    @Before
3039c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    public void setUp() throws Exception {
3049c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu        super.setUp("GsmInboundSmsHandlerTest");
3051fe1dbf473755c4e812a1218f331759eccacb447Jack Yu
306217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        doReturn(true).when(mTelephonyManager).getSmsReceiveCapableForPhone(anyInt(), anyBoolean());
307655bae990bdd7e4584491def4d30692e6173779cfionaxu        doReturn(true).when(mSmsStorageMonitor).isStorageAvailable();
308655bae990bdd7e4584491def4d30692e6173779cfionaxu
309655bae990bdd7e4584491def4d30692e6173779cfionaxu        UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE);
310655bae990bdd7e4584491def4d30692e6173779cfionaxu        doReturn(true).when(userManager).isUserUnlocked();
311655bae990bdd7e4584491def4d30692e6173779cfionaxu
312655bae990bdd7e4584491def4d30692e6173779cfionaxu        try {
313655bae990bdd7e4584491def4d30692e6173779cfionaxu            doReturn(new int[]{UserHandle.USER_SYSTEM}).when(mIActivityManager).getRunningUserIds();
314655bae990bdd7e4584491def4d30692e6173779cfionaxu        } catch (RemoteException re) {
315655bae990bdd7e4584491def4d30692e6173779cfionaxu            fail("Unexpected RemoteException: " + re.getStackTrace());
316655bae990bdd7e4584491def4d30692e6173779cfionaxu        }
317655bae990bdd7e4584491def4d30692e6173779cfionaxu
318655bae990bdd7e4584491def4d30692e6173779cfionaxu        mSmsMessage.mWrappedSmsMessage = mGsmSmsMessage;
31927f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        mInboundSmsTrackerCV.put("destination_port", 1 << 16);
32027f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        mInboundSmsTrackerCV.put("pdu", HexDump.toHexString(mSmsPdu));
3216e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan        mInboundSmsTrackerCV.put("address", "1234567890");
32227f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        mInboundSmsTrackerCV.put("reference_number", 1);
32327f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        mInboundSmsTrackerCV.put("sequence", 1);
3246e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan        mInboundSmsTrackerCV.put("count", 1);
325871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan        mInboundSmsTrackerCV.put("date", System.currentTimeMillis());
326871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan        mInboundSmsTrackerCV.put("message_body", mMessageBody);
327ecac744a4e585e3c7af95ffa06fa3e711131200cAmit Mahajan
328ecac744a4e585e3c7af95ffa06fa3e711131200cAmit Mahajan        doReturn(1).when(mInboundSmsTracker).getMessageCount();
329655bae990bdd7e4584491def4d30692e6173779cfionaxu        doReturn(1).when(mInboundSmsTracker).getReferenceNumber();
330655bae990bdd7e4584491def4d30692e6173779cfionaxu        doReturn("1234567890").when(mInboundSmsTracker).getAddress();
331b9d551db1795b30598e2ce98cfae7106788c12d6fionaxu        doReturn(1).when(mInboundSmsTracker).getSequenceNumber();
33278867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan        doReturn(1).when(mInboundSmsTracker).getIndexOffset();
33327f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        doReturn(-1).when(mInboundSmsTracker).getDestPort();
33427f471647b2da3ff50620a766c048ebef8d45ae1Amit Mahajan        doReturn(mMessageBody).when(mInboundSmsTracker).getMessageBody();
33578867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan        doReturn(mSmsPdu).when(mInboundSmsTracker).getPdu();
336217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        doReturn(mInboundSmsTrackerCV.get("date")).when(mInboundSmsTracker).getTimestamp();
33778867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan        doReturn(mInboundSmsTrackerCV).when(mInboundSmsTracker).getContentValues();
338f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu
33978867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan        mContentProvider = new FakeSmsContentProvider();
340217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        ((MockContentResolver)mContext.getContentResolver()).addProvider(
341217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan                Telephony.Sms.CONTENT_URI.getAuthority(), mContentProvider);
342e415b7b5ae3afec0b7a24d85b930e8cca47499a6fionaxu
343217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        new GsmInboundSmsHandlerTestHandler(TAG).start();
344217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        waitUntilReady();
34527b650c406018355a88a41528db7859e232728a0Jack Yu    }
34627b650c406018355a88a41528db7859e232728a0Jack Yu
347dbe4d7749d5524be575f629486874acdae721138Amit Mahajan    @After
34832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan    public void tearDown() throws Exception {
349217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        // wait for wakelock to be released; timeout at 10s
350153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        int i = 0;
351153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        while (mGsmInboundSmsHandler.getWakeLock().isHeld() && i < 100) {
352153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan            waitForMs(100);
353153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan            i++;
354153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        }
355153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        assertFalse(mGsmInboundSmsHandler.getWakeLock().isHeld());
35678867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan        mGsmInboundSmsHandler = null;
35727b650c406018355a88a41528db7859e232728a0Jack Yu        super.tearDown();
35827b650c406018355a88a41528db7859e232728a0Jack Yu    }
35927b650c406018355a88a41528db7859e232728a0Jack Yu
36027b650c406018355a88a41528db7859e232728a0Jack Yu    private void transitionFromStartupToIdle() {
36127b650c406018355a88a41528db7859e232728a0Jack Yu        // verify initially in StartupState
36227b650c406018355a88a41528db7859e232728a0Jack Yu        assertEquals("StartupState", getCurrentState().getName());
36327b650c406018355a88a41528db7859e232728a0Jack Yu
36427b650c406018355a88a41528db7859e232728a0Jack Yu        // trigger transition to IdleState
36527b650c406018355a88a41528db7859e232728a0Jack Yu        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS);
36627b650c406018355a88a41528db7859e232728a0Jack Yu        waitForMs(50);
36727b650c406018355a88a41528db7859e232728a0Jack Yu
36827b650c406018355a88a41528db7859e232728a0Jack Yu        assertEquals("IdleState", getCurrentState().getName());
36927b650c406018355a88a41528db7859e232728a0Jack Yu    }
37027b650c406018355a88a41528db7859e232728a0Jack Yu
37127b650c406018355a88a41528db7859e232728a0Jack Yu    private void verifySmsIntentBroadcasts(int numPastBroadcasts) {
37227b650c406018355a88a41528db7859e232728a0Jack Yu        ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
373217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        verify(mContext, times(1 + numPastBroadcasts)).sendBroadcast(
374153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                intentArgumentCaptor.capture());
375153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION,
376153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan                intentArgumentCaptor.getAllValues().get(numPastBroadcasts).getAction());
377217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        assertEquals("WaitingState", getCurrentState().getName());
378217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan
379655bae990bdd7e4584491def4d30692e6173779cfionaxu        mContextFixture.sendBroadcastToOrderedBroadcastReceivers();
380655bae990bdd7e4584491def4d30692e6173779cfionaxu
381655bae990bdd7e4584491def4d30692e6173779cfionaxu        intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
382655bae990bdd7e4584491def4d30692e6173779cfionaxu        verify(mContext, times(2 + numPastBroadcasts)).sendBroadcast(
383655bae990bdd7e4584491def4d30692e6173779cfionaxu                intentArgumentCaptor.capture());
384655bae990bdd7e4584491def4d30692e6173779cfionaxu        assertEquals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION,
38578867803826b15ff95c8ee8c7c6f65dfb7ad258fAmit Mahajan                intentArgumentCaptor.getAllValues().get(numPastBroadcasts + 1).getAction());
3866ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu        assertEquals("WaitingState", getCurrentState().getName());
3876ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu
3886ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu        mContextFixture.sendBroadcastToOrderedBroadcastReceivers();
3896ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu        waitForMs(50);
3906ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu
3916ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu        assertEquals("IdleState", getCurrentState().getName());
3926ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu    }
39327b650c406018355a88a41528db7859e232728a0Jack Yu
39427b650c406018355a88a41528db7859e232728a0Jack Yu    @Test
39527b650c406018355a88a41528db7859e232728a0Jack Yu    @MediumTest
396217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan    public void testNewSms() {
39775ba09a17a669f4906268088a769836aa87d8241fionaxu        transitionFromStartupToIdle();
39875ba09a17a669f4906268088a769836aa87d8241fionaxu
399217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION
400f9b150b221db15e88b97a0b9c0971ca3c71c0313fionaxu        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS,
4011bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu                new AsyncResult(null, mSmsMessage, null));
4021bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu        waitForMs(100);
4031bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu
4041bcd7a866ddf8f6f63370c70972f057a4a1ba057Jack Yu        verifySmsIntentBroadcasts(0);
405ecac744a4e585e3c7af95ffa06fa3e711131200cAmit Mahajan
4067a1c1b02c8603c2bf2f3b401facb389528180eedPavel Zhamaitsiak        // send same SMS again, verify no broadcasts are sent
407217d4d9562a9476cf579dfc409b1278a02b18b87Amit Mahajan        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS,
40832b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan                new AsyncResult(null, mSmsMessage, null));
40932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        waitForMs(100);
41032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
411f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan        verify(mContext, times(2)).sendBroadcast(any(Intent.class));
412153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan        assertEquals("IdleState", getCurrentState().getName());
413153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan    }
414153077e0b2d9ff6f115a0739dac1d64931bffb91Amit Mahajan
4159c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    @Test
4169c96807d990cdd3f4bb2d3f0fd56a1e78a95b353Jack Yu    @MediumTest
417f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan    public void testNewSmsFromBlockedNumber_noBroadcastsSent() {
418f152b32a20be664788536a223b9ac7a52f69e4ddAmit Mahajan        String blockedNumber = "123456789";
41932b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        doReturn(blockedNumber).when(mInboundSmsTracker).getAddress();
42032b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan        mFakeBlockedNumberContentProvider.mBlockedNumbers.add(blockedNumber);
42132b5fbb1a340fa16e2c37c276517ef10a4934500Amit Mahajan
422e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        transitionFromStartupToIdle();
423e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry
424e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS,
4255eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry                new AsyncResult(null, mSmsMessage, null));
426e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        waitForMs(100);
427e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry
428e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        verify(mContext, never()).sendBroadcast(any(Intent.class));
4295eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        assertEquals("IdleState", getCurrentState().getName());
4305eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry    }
4315eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry
4325eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry    private void verifyDataSmsIntentBroadcasts(int numPastBroadcasts) {
4335eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
4345eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        verify(mContext, times(1 + numPastBroadcasts)).sendBroadcast(
4355eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry                intentArgumentCaptor.capture());
4365eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        assertEquals(Telephony.Sms.Intents.DATA_SMS_RECEIVED_ACTION,
4375eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry                intentArgumentCaptor.getAllValues().get(numPastBroadcasts).getAction());
4385eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        assertEquals("WaitingState", getCurrentState().getName());
4395eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry
4405eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        mContextFixture.sendBroadcastToOrderedBroadcastReceivers();
4415eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        waitForMs(50);
442e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry
443e2435e2d37c991bd6209a90cd884b5102939872eAbhijith Shastry        assertEquals("IdleState", getCurrentState().getName());
4446ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu    }
4456ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu
4466ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu    @Test
4476ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu    @MediumTest
4486ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu    public void testBroadcastSms() {
4496ba18ef5f3733709f16ef03b3d2b2de076b63c3efionaxu        transitionFromStartupToIdle();
45018ad8bf07feb9f6a9d187da236f3e56c055e941afionaxu
451        doReturn(0).when(mInboundSmsTracker).getDestPort();
452        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS,
453                mInboundSmsTracker);
454        waitForMs(100);
455
456        verifyDataSmsIntentBroadcasts(0);
457
458        // send same data sms again, and since it's not text sms it should be broadcast again
459        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS,
460                mInboundSmsTracker);
461        waitForMs(100);
462
463        verifyDataSmsIntentBroadcasts(1);
464    }
465
466    @Test
467    @MediumTest
468    public void testInjectSms() {
469        transitionFromStartupToIdle();
470
471        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_INJECT_SMS, new AsyncResult(null,
472                mSmsMessage, null));
473        waitForMs(100);
474
475        verifySmsIntentBroadcasts(0);
476
477        // inject same SMS again, verify no broadcasts are sent
478        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_INJECT_SMS, new AsyncResult(null,
479                mSmsMessage, null));
480        waitForMs(100);
481
482        verify(mContext, times(2)).sendBroadcast(any(Intent.class));
483        assertEquals("IdleState", getCurrentState().getName());
484    }
485
486    private void prepareMultiPartSms() {
487        // Part 1
488        mInboundSmsTrackerCVPart1 = new ContentValues();
489        mInboundSmsTrackerCVPart1.put("destination_port", 1 << 16);
490        mInboundSmsTrackerCVPart1.put("pdu", HexDump.toHexString(mSmsPdu));
491        mInboundSmsTrackerCVPart1.put("address", "1234567890");
492        mInboundSmsTrackerCVPart1.put("reference_number", 1);
493        mInboundSmsTrackerCVPart1.put("sequence", 1);
494        mInboundSmsTrackerCVPart1.put("count", 2);
495        mInboundSmsTrackerCVPart1.put("date", System.currentTimeMillis());
496        mInboundSmsTrackerCVPart1.put("message_body", mMessageBodyPart1);
497
498        doReturn(2).when(mInboundSmsTrackerPart1).getMessageCount();
499        doReturn(1).when(mInboundSmsTrackerPart1).getReferenceNumber();
500        doReturn("1234567890").when(mInboundSmsTrackerPart1).getAddress();
501        doReturn(1).when(mInboundSmsTrackerPart1).getSequenceNumber();
502        doReturn(1).when(mInboundSmsTrackerPart1).getIndexOffset();
503        doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort();
504        doReturn(mMessageBodyPart1).when(mInboundSmsTrackerPart1).getMessageBody();
505        doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu();
506        doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1).
507                getTimestamp();
508        doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues();
509
510        // Part 2
511        mInboundSmsTrackerCVPart2 = new ContentValues();
512        mInboundSmsTrackerCVPart2.put("destination_port", 1 << 16);
513        mInboundSmsTrackerCVPart2.put("pdu", HexDump.toHexString(mSmsPdu));
514        mInboundSmsTrackerCVPart2.put("address", "1234567890");
515        mInboundSmsTrackerCVPart2.put("reference_number", 1);
516        mInboundSmsTrackerCVPart2.put("sequence", 2);
517        mInboundSmsTrackerCVPart2.put("count", 2);
518        mInboundSmsTrackerCVPart2.put("date", System.currentTimeMillis());
519        mInboundSmsTrackerCVPart2.put("message_body", mMessageBodyPart2);
520
521        doReturn(2).when(mInboundSmsTrackerPart2).getMessageCount();
522        doReturn(1).when(mInboundSmsTrackerPart2).getReferenceNumber();
523        doReturn("1234567890").when(mInboundSmsTrackerPart2).getAddress();
524        doReturn(2).when(mInboundSmsTrackerPart2).getSequenceNumber();
525        doReturn(1).when(mInboundSmsTrackerPart2).getIndexOffset();
526        doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort();
527        doReturn(mMessageBodyPart2).when(mInboundSmsTrackerPart2).getMessageBody();
528        doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu();
529        doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2).
530                getTimestamp();
531        doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues();
532    }
533
534    @Test
535    @MediumTest
536    public void testMultiPartSms() {
537        transitionFromStartupToIdle();
538
539        // prepare SMS part 1 and part 2
540        prepareMultiPartSms();
541
542        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
543        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
544
545        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
546                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
547                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
548        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
549                mSmsMessage, null));
550        waitForMs(100);
551
552        // State machine should go back to idle and wait for second part
553        assertEquals("IdleState", getCurrentState().getName());
554
555        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
556                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
557                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
558        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
559                mSmsMessage, null));
560        waitForMs(100);
561
562        // verify broadcast intents
563        verifySmsIntentBroadcasts(0);
564
565        // if an additional copy of one of the segments above is received, it should not be kept in
566        // the db and should not be combined with any subsequent messages received from the same
567        // sender
568
569        // additional copy of part 2 of message
570        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
571                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
572                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
573        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
574                mSmsMessage, null));
575        waitForMs(100);
576
577        // verify no additional broadcasts sent
578        verify(mContext, times(2)).sendBroadcast(any(Intent.class));
579
580        // part 1 of new sms recieved from same sender with same parameters, just different
581        // timestamps, should not be combined with the additional part 2 received above
582
583        // call prepareMultiPartSms() to update timestamps
584        prepareMultiPartSms();
585
586        // part 1 of new sms
587        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
588                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
589                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
590        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
591                mSmsMessage, null));
592        waitForMs(100);
593
594        // verify no additional broadcasts sent
595        verify(mContext, times(2)).sendBroadcast(any(Intent.class));
596
597        assertEquals("IdleState", getCurrentState().getName());
598    }
599
600    @Test
601    @MediumTest
602    public void testMultiPartIncompleteSms() {
603        /**
604         * Test scenario: 2 messages are received with same address, ref number, count, and
605         * seqNumber, with count = 2 and seqNumber = 1. We should not try to merge these.
606         */
607        transitionFromStartupToIdle();
608
609        // prepare SMS part 1 and part 2
610        prepareMultiPartSms();
611        // change seqNumber in part 2 to 1
612        mInboundSmsTrackerCVPart2.put("sequence", 1);
613
614        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
615        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
616
617        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
618                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
619                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
620        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
621                mSmsMessage, null));
622        waitForMs(100);
623
624        // State machine should go back to idle and wait for second part
625        assertEquals("IdleState", getCurrentState().getName());
626
627        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
628                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
629                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
630        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
631                mSmsMessage, null));
632        waitForMs(100);
633
634        // verify no broadcasts sent
635        verify(mContext, never()).sendBroadcast(any(Intent.class));
636        // State machine should go back to idle
637        assertEquals("IdleState", getCurrentState().getName());
638    }
639
640    @Test
641    @MediumTest
642    public void testMultipartSmsFromBlockedNumber_noBroadcastsSent() {
643        mFakeBlockedNumberContentProvider.mBlockedNumbers.add("1234567890");
644
645        transitionFromStartupToIdle();
646
647        // prepare SMS part 1 and part 2
648        prepareMultiPartSms();
649
650        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
651        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
652        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
653                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
654                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
655
656        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
657                mSmsMessage, null));
658        waitForMs(100);
659
660        // State machine should go back to idle and wait for second part
661        assertEquals("IdleState", getCurrentState().getName());
662
663        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
664                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
665                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString());
666        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
667                mSmsMessage, null));
668        waitForMs(100);
669
670        verify(mContext, never()).sendBroadcast(any(Intent.class));
671        assertEquals("IdleState", getCurrentState().getName());
672    }
673
674    @Test
675    @MediumTest
676    public void testBroadcastUndeliveredUserLocked() throws Exception {
677        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
678        doReturn(0).when(mInboundSmsTracker).getDestPort();
679
680        // add a fake entry to db
681        ContentValues rawSms = new ContentValues();
682        mContentProvider.insert(sRawUri, rawSms);
683
684        // make it a single-part message
685        doReturn(1).when(mInboundSmsTracker).getMessageCount();
686
687        // user locked
688        UserManager userManager = (UserManager)mContext.getSystemService(Context.USER_SERVICE);
689        doReturn(false).when(userManager).isUserUnlocked();
690
691        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
692
693        // verify that a broadcast receiver is registered for current user (user == null) based on
694        // implementation in ContextFixture
695        verify(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), eq((UserHandle)null),
696                any(IntentFilter.class), eq((String)null), eq((Handler)null));
697
698        waitForMs(100);
699
700        // verify no broadcasts sent because due to !isUserUnlocked
701        verify(mContext, never()).sendBroadcast(any(Intent.class));
702
703        // when user unlocks the device, the message in db should be broadcast
704        doReturn(true).when(userManager).isUserUnlocked();
705        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED));
706        waitForMs(100);
707
708        verifyDataSmsIntentBroadcasts(1);
709    }
710
711    @Test
712    @MediumTest
713    public void testBroadcastUndeliveredUserUnlocked() throws Exception {
714        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
715        doReturn(0).when(mInboundSmsTracker).getDestPort();
716
717        // add a fake entry to db
718        ContentValues rawSms = new ContentValues();
719        mContentProvider.insert(sRawUri, rawSms);
720
721        // make it a single-part message
722        doReturn(1).when(mInboundSmsTracker).getMessageCount();
723
724        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
725        waitForMs(100);
726
727        // user is unlocked; intent should be broadcast right away
728        verifyDataSmsIntentBroadcasts(0);
729    }
730
731    @Test
732    @MediumTest
733    public void testBroadcastUndeliveredDeleted() throws Exception {
734        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
735        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
736        doReturn(0).when(mInboundSmsTracker).getDestPort();
737
738        //add a fake entry to db
739        ContentValues rawSms = new ContentValues();
740        rawSms.put("deleted", 1);
741        mContentProvider.insert(sRawUri, rawSms);
742
743        //make it a single-part message
744        doReturn(1).when(mInboundSmsTracker).getMessageCount();
745
746        //when user unlocks the device, broadcast should not be sent for new message
747        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED));
748        waitForMs(100);
749
750        verify(mContext, times(1)).sendBroadcast(any(Intent.class));
751        assertEquals("IdleState", getCurrentState().getName());
752
753    }
754
755    @Test
756    @MediumTest
757    public void testBroadcastUndeliveredMultiPart() throws Exception {
758        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
759
760        // prepare SMS part 1 and part 2
761        prepareMultiPartSms();
762
763        //add the 2 SMS parts to db
764        mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart1);
765        mContentProvider.insert(sRawUri, mInboundSmsTrackerCVPart2);
766
767        //return InboundSmsTracker objects corresponding to the 2 parts
768        doReturn(mInboundSmsTrackerPart1).doReturn(mInboundSmsTrackerPart2).
769                when(mTelephonyComponentFactory).makeInboundSmsTracker(any(Cursor.class),
770                anyBoolean());
771
772        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
773        waitForMs(100);
774
775        verifySmsIntentBroadcasts(0);
776    }
777}
778