17236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project/*
27236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
37236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
47236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
57236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * you may not use this file except in compliance with the License.
67236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * You may obtain a copy of the License at
77236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
87236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
97236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * See the License for the specific language governing permissions and
147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * limitations under the License.
157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project */
167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectpackage com.android.providers.telephony;
187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
19f27792fb80c6f533a250ec75867c9f2351ff9f04Dianne Hackbornimport android.app.AppOpsManager;
207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentProvider;
217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentValues;
227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.Context;
237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.UriMatcher;
247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.Cursor;
257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.DatabaseUtils;
267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper;
287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.net.Uri;
30e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.os.Binder;
3143f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasaniimport android.os.UserHandle;
327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.BaseColumns;
3386b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport android.provider.Telephony;
347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.CanonicalAddressesColumns;
357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Mms;
367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.MmsSms;
37e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.provider.Telephony.MmsSms.PendingMessages;
387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Sms;
39e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.provider.Telephony.Sms.Conversations;
407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Threads;
417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.ThreadsColumns;
427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.text.TextUtils;
437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.util.Log;
447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
45b1bae65bf18dc22762cf7b8210fdad836b3e4ee5Tom Taylorimport com.google.android.mms.pdu.PduHeaders;
467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4786b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport java.io.FileDescriptor;
4886b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport java.io.PrintWriter;
49e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.Arrays;
50e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.HashSet;
51e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.List;
52e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.Set;
53e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen
547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project/**
557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides the ability to query the MMS and SMS databases
567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * at the same time, mixing messages from both in a single thread
577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * (A.K.A. conversation).
587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * A virtual column, MmsSms.TYPE_DISCRIMINATOR_COLUMN, may be
607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * requested in the projection for a query.  Its value is either "mms"
617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * or "sms", depending on whether the message represented by the row
627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * is an MMS message or an SMS message, respectively.
637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class also provides the ability to find out what addresses
657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * participated in a particular thread.  It doesn't support updates
667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for either of these.
677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides a way to allocate and retrieve thread IDs.
697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This is done atomically through a query.  There is no insert URI
707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for this.
717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Finally, this class provides a way to delete or update all messages
737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * in a thread.
747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project */
757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectpublic class MmsSmsProvider extends ContentProvider {
767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final UriMatcher URI_MATCHER =
777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new UriMatcher(UriMatcher.NO_MATCH);
787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String LOG_TAG = "MmsSmsProvider";
79816e934a43bf705835bdb24503a85a14c4861991Tom Taylor    private static final boolean DEBUG = false;
807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String NO_DELETES_INSERTS_OR_UPDATES =
827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "MmsSmsProvider does not support deletes, inserts, or updates for this URI.";
83f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS                     = 0;
84f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_MESSAGES            = 1;
85f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_RECIPIENTS          = 2;
86f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_MESSAGES_BY_PHONE                 = 3;
87f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_THREAD_ID                         = 4;
88f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESS                 = 5;
89f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_PENDING_MSG                       = 6;
90f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_COMPLETE_CONVERSATIONS            = 7;
91f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_UNDELIVERED_MSG                   = 8;
92f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_SUBJECT             = 9;
93f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_NOTIFICATIONS                     = 10;
94f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_OBSOLETE_THREADS                  = 11;
95f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_DRAFT                             = 12;
96f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESSES               = 13;
97f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_SEARCH                            = 14;
988e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_SEARCH_SUGGEST                    = 15;
998e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_ALL          = 16;
1008e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID = 17;
1016a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner    private static final int URI_MESSAGE_ID_TO_THREAD              = 18;
1027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
1047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the name of the table that is used to store the queue of
1057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages(both MMS and SMS) to be sent/downloaded.
1067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
1077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public static final String TABLE_PENDING_MSG = "pending_msgs";
1087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1091ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    /**
1101ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     * the name of the table that is used to store the canonical addresses for both SMS and MMS.
1111ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     */
1121ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String TABLE_CANONICAL_ADDRESSES = "canonical_addresses";
1131ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
11415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor    /**
11515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor     * the name of the table that is used to store the conversation threads.
11615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor     */
11715156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor    static final String TABLE_THREADS = "threads";
11815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor
1197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These constants are used to construct union queries across the
1207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // MMS and SMS base tables.
1217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear in both the MMS ("pdu") and
1237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // SMS ("sms") message tables.
1247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_SMS_COLUMNS =
125cfb8bbdc3932473966d043fbd72b6c067933f2c1Ye Wen            { BaseColumns._ID, Mms.DATE, Mms.DATE_SENT, Mms.READ, Mms.THREAD_ID, Mms.LOCKED,
12672b147363200ff3f0bc467f23579042bd800ff13Wink Saville                    Mms.SUBSCRIPTION_ID };
1277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the MMS message
1297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_ONLY_COLUMNS = {
1317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.CONTENT_CLASS, Mms.CONTENT_LOCATION, Mms.CONTENT_TYPE,
1327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.DELIVERY_REPORT, Mms.EXPIRY, Mms.MESSAGE_CLASS, Mms.MESSAGE_ID,
1337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.MESSAGE_SIZE, Mms.MESSAGE_TYPE, Mms.MESSAGE_BOX, Mms.PRIORITY,
1347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_STATUS, Mms.RESPONSE_STATUS, Mms.RESPONSE_TEXT,
1357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.RETRIEVE_STATUS, Mms.RETRIEVE_TEXT_CHARSET, Mms.REPORT_ALLOWED,
1367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_REPORT, Mms.STATUS, Mms.SUBJECT, Mms.SUBJECT_CHARSET,
137f88d1d6733158144e9e0c87f29b446068edf0507Tom Taylor        Mms.TRANSACTION_ID, Mms.MMS_VERSION, Mms.TEXT_ONLY };
1387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the SMS message
1407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] SMS_ONLY_COLUMNS =
1427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            { "address", "body", "person", "reply_path_present",
143ddf267c20a697f66b8238538fb6ad31507724692Tom Taylor              "service_center", "status", "subject", "type", "error_code" };
1447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the "threads" table.
1467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] THREADS_COLUMNS = {
1477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        BaseColumns._ID,
1487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.DATE,
1497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.RECIPIENT_IDS,
1507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.MESSAGE_COUNT
1517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    };
1527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1531ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_1 =
1541ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns.ADDRESS };
1551ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1561ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_2 =
1571ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns._ID,
1581ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                    CanonicalAddressesColumns.ADDRESS };
1591ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS and SMS
1617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // message tables.
1627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] UNION_COLUMNS =
1637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new String[MMS_SMS_COLUMNS.length
1647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + MMS_ONLY_COLUMNS.length
1657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + SMS_ONLY_COLUMNS.length];
1667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS table.
1687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> MMS_COLUMNS = new HashSet<String>();
1697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the SMS table.
1717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> SMS_COLUMNS = new HashSet<String>();
1727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String VND_ANDROID_DIR_MMS_SMS =
1747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "vnd.android-dir/mms-sms";
1757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] ID_PROJECTION = { BaseColumns._ID };
1777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] EMPTY_STRING_ARRAY = new String[0];
1797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1803e1cba826743423642635cc7b03abe292470f4c4Tom Taylor    private static final String[] SEARCH_STRING = new String[1];
1813e1cba826743423642635cc7b03abe292470f4c4Tom Taylor    private static final String SEARCH_QUERY = "SELECT snippet(words, '', ' ', '', 1, 1) as " +
1823e1cba826743423642635cc7b03abe292470f4c4Tom Taylor            "snippet FROM words WHERE index_text MATCH ? ORDER BY snippet LIMIT 50;";
1833e1cba826743423642635cc7b03abe292470f4c4Tom Taylor
1847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String SMS_CONVERSATION_CONSTRAINT = "(" +
1857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Sms.TYPE + " != " + Sms.MESSAGE_TYPE_DRAFT + ")";
1867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String MMS_CONVERSATION_CONSTRAINT = "(" +
1887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS + " AND (" +
1897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_SEND_REQ + " OR " +
1907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF + " OR " +
1917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + "))";
1927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
19372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String getTextSearchQuery(String smsTable, String pduTable) {
19472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // Search on the words table but return the rows from the corresponding sms table
19572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String smsQuery = "SELECT "
19672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + smsTable + "._id AS _id,"
19772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "thread_id,"
19872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "address,"
19972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "body,"
20072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "date,"
20172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "date_sent,"
20272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "index_text,"
20372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "words._id "
20472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "FROM " + smsTable + ",words "
20572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "WHERE (index_text MATCH ? "
20672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND " + smsTable + "._id=words.source_id "
20772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND words.table_to_use=1)";
20872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
20972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // Search on the words table but return the rows from the corresponding parts table
21072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String mmsQuery = "SELECT "
21172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + "._id,"
21272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "thread_id,"
21372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "addr.address,"
21472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "part.text AS body,"
21572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + ".date,"
21672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + ".date_sent,"
21772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "index_text,"
21872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "words._id "
21972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "FROM " + pduTable + ",part,addr,words "
22072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "WHERE ((part.mid=" + pduTable + "._id) "
22172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (addr.msg_id=" + pduTable + "._id) "
22272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (addr.type=" + PduHeaders.TO + ") "
22372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (part.ct='text/plain') "
22472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (index_text MATCH ?) "
22572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (part._id = words.source_id) "
22672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (words.table_to_use=2))";
22772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
22872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // This code queries the sms and mms tables and returns a unified result set
22972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // of text matches.  We query the sms table which is pretty simple.  We also
23072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // query the pdu, part and addr table to get the mms result.  Note we're
23172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // using a UNION so we have to have the same number of result columns from
23272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // both queries.
23372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        return smsQuery + " UNION " + mmsQuery + " "
23472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "GROUP BY thread_id "
23572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "ORDER BY thread_id ASC, date DESC";
23672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    }
23701c75ba95b875674a83128defc6b267e522db346Chen Mike
2387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String AUTHORITY = "mms-sms";
2397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    static {
2417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations", URI_CONVERSATIONS);
2427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "complete-conversations", URI_COMPLETE_CONVERSATIONS);
2437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In these patterns, "#" is the thread ID.
2457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#", URI_CONVERSATIONS_MESSAGES);
2477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/recipients",
2497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_RECIPIENTS);
2507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/subject",
2537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_SUBJECT);
2547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // URI for deleting obsolete threads.
2567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations/obsolete", URI_OBSOLETE_THREADS);
2577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "messages/byphone/*",
2607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_MESSAGES_BY_PHONE);
2617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameter names are expected:
2637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "subject" and "recipient."  Multiple "recipient" parameters
2647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // may be present.
2657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "threadID", URI_THREAD_ID);
2667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to query the canonical address by given ID.
2687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "canonical-address/#", URI_CANONICAL_ADDRESS);
2697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
27037e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        // Use this pattern to query all canonical addresses.
27137e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        URI_MATCHER.addURI(AUTHORITY, "canonical-addresses", URI_CANONICAL_ADDRESSES);
272f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
27366d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "search", URI_SEARCH);
2748e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "searchSuggest", URI_SEARCH_SUGGEST);
27537e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick
2767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameters may be supplied:
2777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "protocol" and "message." For example:
2787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?
2797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return all pending messages;
2807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=sms
2817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Only return pending SMs;
2827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=mms&message=1
2837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return the the pending MM which ID equals '1'.
2847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //
2857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "pending", URI_PENDING_MSG);
2867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to get a list of undelivered messages.
2887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "undelivered", URI_UNDELIVERED_MSG);
2897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to see what delivery status reports (for
2917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // both MMS and SMS) have not been delivered to the user.
2927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "notifications", URI_NOTIFICATIONS);
2937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "draft", URI_DRAFT);
295f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
296f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked", URI_FIRST_LOCKED_MESSAGE_ALL);
297f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
298f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked/#", URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID);
299f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
3006a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "messageIdToThread", URI_MESSAGE_ID_TO_THREAD);
3017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        initializeColumnSets();
3027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
3037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private SQLiteOpenHelper mOpenHelper;
3057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
306845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa    private boolean mUseStrictPhoneNumberComparation;
307845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa
3087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
3097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public boolean onCreate() {
310b2ce2d37bc6efc0c37d8cee925d3ad65a01ea4bfYe Wen        setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
3115a3194d943854ec3c2ec5df18a95a5b04ab5efa1Ji Yang        mOpenHelper = MmsSmsDatabaseHelper.getInstanceForCe(getContext());
312845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa        mUseStrictPhoneNumberComparation =
313845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa            getContext().getResources().getBoolean(
314845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
3152d3a779b41d5a553c8615a906ee97da29907313eRoman Sorokin        TelephonyBackupAgent.DeferredSmsMmsRestoreService.startIfFilesExist(getContext());
3167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return true;
3177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
3187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
3207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Cursor query(Uri uri, String[] projection,
3217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs, String sortOrder) {
32272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // First check if restricted views of the "sms" and "pdu" tables should be used based on the
32372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // caller's identity. Only system, phone or the default sms app can have full access
32472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // of sms/mms data. For other apps, we present a restricted view which only contains sent
32572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // or received messages, without wap pushes.
32672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final boolean accessRestricted = ProviderUtil.isAccessRestricted(
32772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                getContext(), getCallingPackage(), Binder.getCallingUid());
32872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String pduTable = MmsProvider.getPduTable(accessRestricted);
32972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String smsTable = SmsProvider.getSmsTable(accessRestricted);
33072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
3317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
33372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final int match = URI_MATCHER.match(uri);
33472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        switch (match) {
3357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_COMPLETE_CONVERSATIONS:
33672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getCompleteConversations(projection, selection, sortOrder, smsTable,
33772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable);
3387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
3407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String simple = uri.getQueryParameter("simple");
3417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if ((simple != null) && simple.equals("true")) {
3427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    String threadType = uri.getQueryParameter("thread_type");
3437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    if (!TextUtils.isEmpty(threadType)) {
3447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection = concatSelections(
3457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                selection, Threads.TYPE + "=" + threadType);
3467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    }
3477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getSimpleConversations(
3487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                            projection, selection, selectionArgs, sortOrder);
3497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
3507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getConversations(
35172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            projection, selection, sortOrder, smsTable, pduTable);
3527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
3537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
355f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getConversationMessages(uri.getPathSegments().get(1), projection,
35672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selection, sortOrder, smsTable, pduTable);
3577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_RECIPIENTS:
3597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_SUBJECT:
3647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_MESSAGES_BY_PHONE:
3697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getMessagesByPhoneNumber(
37072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        uri.getPathSegments().get(2), projection, selection, sortOrder, smsTable,
37172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable);
3727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_THREAD_ID:
3747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                List<String> recipients = uri.getQueryParameters("recipient");
3757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getThreadId(recipients);
3777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CANONICAL_ADDRESS: {
3797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = "_id=" + uri.getPathSegments().get(1);
3807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
3817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : extraSelection + " AND " + selection;
3821ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3831ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_1,
3841ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        finalSelection,
3851ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3861ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
3871ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
3887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
39037e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick            case URI_CANONICAL_ADDRESSES:
3911ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3921ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_2,
3931ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selection,
3941ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3951ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
3961ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
39737e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick                break;
3988e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH_SUGGEST: {
3993e1cba826743423642635cc7b03abe292470f4c4Tom Taylor                SEARCH_STRING[0] = uri.getQueryParameter("pattern") + '*' ;
4009e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner
4019e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // find the words which match the pattern using the snippet function.  The
4029e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // snippet function parameters mainly describe how to format the result.
4039e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // See http://www.sqlite.org/fts3.html#section_4_2 for details.
4048e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                if (       sortOrder != null
4058e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selection != null
4068e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selectionArgs != null
4078e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || projection != null) {
4088e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    throw new IllegalArgumentException(
4098e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
4108e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "with this query");
4118e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
4128e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
4133e1cba826743423642635cc7b03abe292470f4c4Tom Taylor                cursor = db.rawQuery(SEARCH_QUERY, SEARCH_STRING);
4148e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                break;
4158e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
4166a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            case URI_MESSAGE_ID_TO_THREAD: {
4176a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // Given a message ID and an indicator for SMS vs. MMS return
4186a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // the thread id of the corresponding thread.
4196a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                try {
4206a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    long id = Long.parseLong(uri.getQueryParameter("row_id"));
4216a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    switch (Integer.parseInt(uri.getQueryParameter("table_to_use"))) {
4226a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 1:  // sms
4236a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.query(
42472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                smsTable,
4256a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { "thread_id" },
4266a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "_id=?",
4276a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { String.valueOf(id) },
4286a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
4296a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
4306a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null);
4316a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
4326a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 2:  // mms
43372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            String mmsQuery = "SELECT thread_id "
43472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "FROM " + pduTable + ",part "
43572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "WHERE ((part.mid=" + pduTable + "._id) "
43672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "AND " + "(part._id=?))";
4376a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.rawQuery(mmsQuery, new String[] { String.valueOf(id) });
4386a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
4396a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    }
4406a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                } catch (NumberFormatException ex) {
4416a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    // ignore... return empty cursor
4426a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                }
4436a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                break;
4446a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            }
4458e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH: {
44687bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                if (       sortOrder != null
44787bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selection != null
44887bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selectionArgs != null
449f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                        || projection != null) {
450f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                    throw new IllegalArgumentException(
451f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
452f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "with this query");
45366d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                }
45487bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor
4558e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                String searchString = uri.getQueryParameter("pattern") + "*";
4568e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
4578e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                try {
45872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                    cursor = db.rawQuery(getTextSearchQuery(smsTable, pduTable),
45972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            new String[] { searchString, searchString });
4608e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                } catch (Exception ex) {
4618e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    Log.e(LOG_TAG, "got exception: " + ex.toString());
4628e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
46366d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                break;
4648e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
4657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG: {
4667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String protoName = uri.getQueryParameter("protocol");
4677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String msgId = uri.getQueryParameter("message");
4687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                int proto = TextUtils.isEmpty(protoName) ? -1
4697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        : (protoName.equals("sms") ? MmsSms.SMS_PROTO : MmsSms.MMS_PROTO);
4707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = (proto != -1) ?
4727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        (PendingMessages.PROTO_TYPE + "=" + proto) : " 0=0 ";
4737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (!TextUtils.isEmpty(msgId)) {
4747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    extraSelection += " AND " + PendingMessages.MSG_ID + "=" + msgId;
4757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
4767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
4787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : ("(" + extraSelection + ") AND " + selection);
4797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalOrder = TextUtils.isEmpty(sortOrder)
4807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? PendingMessages.DUE_TIME : sortOrder;
4817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = db.query(TABLE_PENDING_MSG, null,
4827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        finalSelection, selectionArgs, null, null, finalOrder);
4837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_UNDELIVERED_MSG: {
4867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getUndeliveredMessages(projection, selection,
48772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selectionArgs, sortOrder, smsTable, pduTable);
4887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_DRAFT: {
49172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getDraftThread(projection, selection, sortOrder, smsTable, pduTable);
4927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
494f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID: {
495f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                long threadId;
496f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                try {
497f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    threadId = Long.parseLong(uri.getLastPathSegment());
498f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                } catch (NumberFormatException e) {
499f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    Log.e(LOG_TAG, "Thread ID must be a long.");
500f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    break;
501f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                }
502f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                cursor = getFirstLockedMessage(projection, "thread_id=" + Long.toString(threadId),
50372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        sortOrder, smsTable, pduTable);
504f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
505f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
506f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_ALL: {
50772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getFirstLockedMessage(
50872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        projection, selection, sortOrder, smsTable, pduTable);
509f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
510f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
5117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
5127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new IllegalStateException("Unrecognized URI:" + uri);
5137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5155926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (cursor != null) {
5165926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            cursor.setNotificationUri(getContext().getContentResolver(), MmsSms.CONTENT_URI);
5175926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        }
5187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
5197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address ID for this address.
5237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long getSingleAddressId(String address) {
5257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        boolean isEmail = Mms.isEmailAddress(address);
526e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        boolean isPhoneNumber = Mms.isPhoneNumber(address);
527e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
528e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // We lowercase all email addresses, but not addresses that aren't numbers, because
529e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // that would incorrectly turn an address such as "My Vodafone" into "my vodafone"
530e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // and the thread title would be incorrect when displayed in the UI.
5317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String refinedAddress = isEmail ? address.toLowerCase() : address;
532e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
533c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String selection = "address=?";
534c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String[] selectionArgs;
53514595cbe9045755a5aa2bd28989c147c4709268cWei Huang        long retVal = -1L;
536c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
537e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        if (!isPhoneNumber) {
538c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress };
539c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        } else {
54001c75ba95b875674a83128defc6b267e522db346Chen Mike            selection += " OR PHONE_NUMBERS_EQUAL(address, ?, " +
54101c75ba95b875674a83128defc6b267e522db346Chen Mike                        (mUseStrictPhoneNumberComparation ? 1 : 0) + ")";
542c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress, refinedAddress };
543c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        }
544c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
5457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
5467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
5487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
5497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            cursor = db.query(
5507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    "canonical_addresses", ID_PROJECTION,
5517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    selection, selectionArgs, null, null, null);
5527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.getCount() == 0) {
5547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                ContentValues contentValues = new ContentValues(1);
5557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                contentValues.put(CanonicalAddressesColumns.ADDRESS, refinedAddress);
5567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                db = mOpenHelper.getWritableDatabase();
55814595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = db.insert("canonical_addresses",
5597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        CanonicalAddressesColumns.ADDRESS, contentValues);
56014595cbe9045755a5aa2bd28989c147c4709268cWei Huang
561ea59f86662471e682f880b4916ce7588803f5605Wink Saville                Log.d(LOG_TAG, "getSingleAddressId: insert new canonical_address for " +
562ea59f86662471e682f880b4916ce7588803f5605Wink Saville                        /*address*/ "xxxxxx" + ", _id=" + retVal);
56314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
56414595cbe9045755a5aa2bd28989c147c4709268cWei Huang                return retVal;
5657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.moveToFirst()) {
56814595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
5697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } finally {
5717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor != null) {
5727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor.close();
5737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
57614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        return retVal;
5777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address IDs for these addresses.
5817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Set<Long> getAddressIds(List<String> addresses) {
5837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<Long> result = new HashSet<Long>(addresses.size());
5847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String address : addresses) {
5867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (!address.equals(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) {
5877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long id = getSingleAddressId(address);
5887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (id != -1L) {
5897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    result.add(id);
5907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
59114595cbe9045755a5aa2bd28989c147c4709268cWei Huang                    Log.e(LOG_TAG, "getAddressIds: address ID not found for " + address);
5927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
5937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
5967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a sorted array of the given Set of Longs.
6007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long[] getSortedSet(Set<Long> numbers) {
6027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.size();
6037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long[] result = new long[size];
6047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
6057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (Long number : numbers) {
6077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i++] = number;
6087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
60914595cbe9045755a5aa2bd28989c147c4709268cWei Huang
61014595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (size > 1) {
61114595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Arrays.sort(result);
61214595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
61314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
6157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a String of the numbers in the given array, in order,
6197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * separated by spaces.
6207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String getSpaceSeparatedNumbers(long[] numbers) {
6227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.length;
6237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        StringBuilder buffer = new StringBuilder();
6247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < size; i++) {
6267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (i != 0) {
6277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                buffer.append(' ');
6287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
6297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            buffer.append(numbers[i]);
6307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return buffer.toString();
6327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Insert a record for a new thread.
6367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private void insertThread(String recipientIds, int numberOfRecipients) {
6387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ContentValues values = new ContentValues(4);
6397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long date = System.currentTimeMillis();
6417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.DATE, date - date % 1000);
6427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.RECIPIENT_IDS, recipientIds);
6437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (numberOfRecipients > 1) {
6447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            values.put(Threads.TYPE, Threads.BROADCAST_THREAD);
6457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.MESSAGE_COUNT, 0);
6477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
64815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        long result = mOpenHelper.getWritableDatabase().insert(TABLE_THREADS, null, values);
64914595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Log.d(LOG_TAG, "insertThread: created new thread_id " + result +
650ea59f86662471e682f880b4916ce7588803f5605Wink Saville                " for recipientIds " + /*recipientIds*/ "xxxxxxx");
65114595cbe9045755a5aa2bd28989c147c4709268cWei Huang
65243f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani        getContext().getContentResolver().notifyChange(MmsSms.CONTENT_URI, null, true,
65343f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                UserHandle.USER_ALL);
6547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
65614595cbe9045755a5aa2bd28989c147c4709268cWei Huang    private static final String THREAD_QUERY =
65714595cbe9045755a5aa2bd28989c147c4709268cWei Huang            "SELECT _id FROM threads " + "WHERE recipient_ids=?";
65814595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread ID for this list of
6617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * recipients IDs.  If no thread exists with this ID, create
6627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * one and return it.  Callers should always use
6637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Threads.getThreadId to access this information.
6647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private synchronized Cursor getThreadId(List<String> recipients) {
66614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Set<Long> addressIds = getAddressIds(recipients);
66714595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String recipientIds = "";
668c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
6695926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (addressIds.size() == 0) {
6705926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            Log.e(LOG_TAG, "getThreadId: NO receipients specified -- NOT creating thread",
6715926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor                    new Exception());
6725926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            return null;
6735926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        } else if (addressIds.size() == 1) {
6745926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            // optimize for size==1, which should be most of the cases
67514595cbe9045755a5aa2bd28989c147c4709268cWei Huang            for (Long addressId : addressIds) {
67614595cbe9045755a5aa2bd28989c147c4709268cWei Huang                recipientIds = Long.toString(addressId);
67714595cbe9045755a5aa2bd28989c147c4709268cWei Huang            }
67814595cbe9045755a5aa2bd28989c147c4709268cWei Huang        } else {
67914595cbe9045755a5aa2bd28989c147c4709268cWei Huang            recipientIds = getSpaceSeparatedNumbers(getSortedSet(addressIds));
68014595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
6817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
68214595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
683ea59f86662471e682f880b4916ce7588803f5605Wink Saville            Log.d(LOG_TAG, "getThreadId: recipientIds (selectionArgs) =" +
684ea59f86662471e682f880b4916ce7588803f5605Wink Saville                    /*recipientIds*/ "xxxxxxx");
685b4ac04f7bd9d4f16ec181f368c42f89c96f83f55Tom Taylor        }
68614595cbe9045755a5aa2bd28989c147c4709268cWei Huang
68714595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String[] selectionArgs = new String[] { recipientIds };
68815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor
6897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
69015156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        db.beginTransaction();
69115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        Cursor cursor = null;
69215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        try {
69315156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            // Find the thread with the given recipients
69415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
6957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
69615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            if (cursor.getCount() == 0) {
69715156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                // No thread with those recipients exists, so create the thread.
69815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                cursor.close();
69914595cbe9045755a5aa2bd28989c147c4709268cWei Huang
70015156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                Log.d(LOG_TAG, "getThreadId: create new thread_id for recipients " +
70115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                        /*recipients*/ "xxxxxxxx");
70215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                insertThread(recipientIds, recipients.size());
70314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
70415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                // The thread was just created, now find it and return it.
70515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
70615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            }
70715156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            db.setTransactionSuccessful();
70815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        } catch (Throwable ex) {
70915156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            Log.e(LOG_TAG, ex.getMessage(), ex);
71015156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        } finally {
71115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            db.endTransaction();
7127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
7136a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner
71415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        if (cursor != null && cursor.getCount() > 1) {
71514595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Log.w(LOG_TAG, "getThreadId: why is cursorCount=" + cursor.getCount());
71669e6ffada415d44c72d908ad9e152da51b190642Tom Taylor        }
7177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
7187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String concatSelections(String selection1, String selection2) {
7217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (TextUtils.isEmpty(selection1)) {
7227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection2;
7237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else if (TextUtils.isEmpty(selection2)) {
7247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1;
7257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else {
7267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1 + " AND " + selection2;
7277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
7287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the union of all columns
7327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * in both the MMS and SMS messages tables.  Otherwise, return the
7337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * given projection.
7347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullMessageProjection(
7367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
7377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? UNION_COLUMNS : projection;
7387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the set of all columns in
7427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the threads table.  Otherwise, return the given projection.
7437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullThreadsProjection(
7457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
7467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? THREADS_COLUMNS : projection;
7477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null sort order is given, return "normalized_date ASC".
7517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Otherwise, return the given sort order.
7527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String handleNullSortOrder (String sortOrder) {
7547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return sortOrder == null ? "normalized_date ASC" : sortOrder;
7557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return existing threads in the database.
7597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getSimpleConversations(String[] projection, String selection,
7617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
76215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        return mOpenHelper.getReadableDatabase().query(TABLE_THREADS, projection,
7637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, selectionArgs, null, null, " date DESC");
7647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread which has draft in both MMS and SMS.
7687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
7707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
7727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT _id, thread_id, ...
7737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
7747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box = 3 AND ...
7757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
7767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT _id, thread_id, ...
7777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
7787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE type = 3 AND ...
7797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *          )
7807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   ;
7817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getDraftThread(String[] projection, String selection,
78372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
7847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerProjection = new String[] {BaseColumns._ID, Conversations.THREAD_ID};
7857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
7867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
7877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
78872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
78972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
7907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
7927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
7937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
7947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_DRAFTS),
795f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
7967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
7977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
7987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
7997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Sms.TYPE + "=" + Sms.MESSAGE_TYPE_DRAFT),
800f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
8017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
8027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
8047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
8067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
8077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
8097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
8117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
813f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                projection, null, null, null, sortOrder, null);
8147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
8167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
8197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the most recent message in each conversation in both MMS
8207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
8217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
8237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
8257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT thread_id AS tid, date * 1000 AS normalized_date, ...
8267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
8277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box != 3 AND ...
8287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
8297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date)
8307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
8317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT thread_id AS tid, date AS normalized_date, ...
8327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
8337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE ...
8347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
8357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date))
8367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     GROUP BY tid
8377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     HAVING normalized_date = MAX(normalized_date);
8387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * The msg_box != 3 comparisons ensure that we don't include draft
8407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages.
8417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
8427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversations(String[] projection, String selection,
84372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
8447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
8457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
8467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
84772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
84872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
8497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
8517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
8527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1000);
8537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
8547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1);
8557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
8567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
8577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
858f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, MMS_CONVERSATION_CONSTRAINT),
8597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
8607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
8617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
8627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
863f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
8647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
8657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
8667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
8687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
8707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
8717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
8737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
8757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
877f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columns, null, "tid",
8787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "normalized_date = MAX(normalized_date)", sortOrder, null);
8797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
8817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
884f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Return the first locked message found in the union of MMS
885f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * and SMS messages.
886f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
887f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Use this query:
888f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
889816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *  SELECT _id FROM pdu GROUP BY _id HAVING locked=1 UNION SELECT _id FROM sms GROUP
890816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *      BY _id HAVING locked=1 LIMIT 1
891f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
892816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     * We limit by 1 because we're only interested in knowing if
893f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * there is *any* locked message, not the actual messages themselves.
894f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     */
895f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private Cursor getFirstLockedMessage(String[] projection, String selection,
89672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
897f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
898f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
899f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
90072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
90172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
902f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
903816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        String[] idColumn = new String[] { BaseColumns._ID };
904816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
905f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor        // NOTE: buildUnionSubQuery *ignores* selectionArgs
906f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
907816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
908816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "mms",
909f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
910816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
911816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
912f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
913816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
914816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "sms",
915f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
916816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
917816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
918f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
919f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
920f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        unionQueryBuilder.setDistinct(true);
921f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
922f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String unionQuery = unionQueryBuilder.buildUnionQuery(
923816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                new String[] { mmsSubQuery, smsSubQuery }, null, "1");
924f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
925816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        Cursor cursor = mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
926f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
927f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        if (DEBUG) {
928816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "getFirstLockedMessage query: " + unionQuery);
929816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "cursor count: " + cursor.getCount());
930f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        }
931816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        return cursor;
932f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    }
933f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
934f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    /**
9357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return every message in each conversation in both MMS
9367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
9377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getCompleteConversations(String[] projection,
93972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String selection, String sortOrder, String smsTable, String pduTable) {
94072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String unionQuery = buildConversationQuery(projection, selection, sortOrder, smsTable,
94172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable);
9427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
9447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date and thread_id to the list of columns for an
9487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * inner projection.  This is necessary so that the outer query
9497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * can have access to these columns even if the caller hasn't
9507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * requested them in the result.
9517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String[] makeProjectionWithDateAndThreadId(
9537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
9547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
9557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 2];
9567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "thread_id AS tid";
9587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[1] = "date * " + dateMultiple + " AS normalized_date";
9597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < projectionSize; i++) {
9607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i + 2] = projection[i];
9617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
9637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages for this thread ID.
9677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationMessages(
9697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
97072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
9717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
9727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
9737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
9747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
9757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
9767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(
9797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "thread_id = " + threadIdString);
98072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String unionQuery = buildConversationQuery(projection, finalSelection, sortOrder, smsTable,
98172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable);
9827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
9847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages whose recipients
9887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * included this phone number.
9897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
9917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
993670c495b6e0489569f60a38a79770dd4ac44500awhliang     *   FROM pdu, (SELECT msg_id AS address_msg_id
9947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *              FROM addr
995c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              WHERE (address='<phoneNumber>' OR
996c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              PHONE_NUMBERS_EQUAL(addr.address, '<phoneNumber>', 1/0)))
9977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             AS matching_addresses
998670c495b6e0489569f60a38a79770dd4ac44500awhliang     *   WHERE pdu._id = matching_addresses.address_msg_id
9997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION
10007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
10017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   FROM sms
1002c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *   WHERE (address='<phoneNumber>' OR PHONE_NUMBERS_EQUAL(sms.address, '<phoneNumber>', 1/0));
10037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
10047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getMessagesByPhoneNumber(
10057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String phoneNumber, String[] projection, String selection,
100672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
10077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String escapedPhoneNumber = DatabaseUtils.sqlEscapeString(phoneNumber);
10087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection =
10097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
10107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
101172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable + "._id = matching_addresses.address_msg_id");
10127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection =
10137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
10147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
1015c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        "(address=" + escapedPhoneNumber + " OR PHONE_NUMBERS_EQUAL(address, " +
1016845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                        escapedPhoneNumber +
1017c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        (mUseStrictPhoneNumberComparation ? ", 1))" : ", 0))"));
10187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
10197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
10207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
10227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
10237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(
102472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable +
1025670c495b6e0489569f60a38a79770dd4ac44500awhliang                ", (SELECT msg_id AS address_msg_id " +
1026c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                "FROM addr WHERE (address=" + escapedPhoneNumber +
1027c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                " OR PHONE_NUMBERS_EQUAL(addr.address, " +
1028845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                escapedPhoneNumber +
1029c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                (mUseStrictPhoneNumberComparation ? ", 1))) " : ", 0))) ") +
10307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "AS matching_addresses");
103172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
10327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
10347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
10357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, MMS_COLUMNS,
1036f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "mms", finalMmsSelection, null, null);
10377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
10387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, SMS_COLUMNS,
1039f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "sms", finalSmsSelection, null, null);
10407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
10417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
10437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
10457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, sortOrder, null);
10467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
10487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
10517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the conversation of certain thread ID.
10527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
10537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationById(
10547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
10557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
10567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
10577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
10587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
10597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
10607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
10617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
10627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String extraSelection = "_id=" + threadIdString;
10647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, extraSelection);
10657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
10667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullThreadsProjection(projection);
10677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        queryBuilder.setDistinct(true);
106915156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        queryBuilder.setTables(TABLE_THREADS);
10707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return queryBuilder.query(
10717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mOpenHelper.getReadableDatabase(), columns, finalSelection,
10727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selectionArgs, sortOrder, null, null);
10737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
107572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String joinPduAndPendingMsgTables(String pduTable) {
107672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        return pduTable + " LEFT JOIN " + TABLE_PENDING_MSG
107772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + " ON " + pduTable + "._id = pending_msgs.msg_id";
10787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
108072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String[] createMmsProjection(String[] old, String pduTable) {
10817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] newProjection = new String[old.length];
10827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < old.length; i++) {
10837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (old[i].equals(BaseColumns._ID)) {
108472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                newProjection[i] = pduTable + "._id";
10857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            } else {
10867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                newProjection[i] = old[i];
10877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
10887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
10897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return newProjection;
10907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getUndeliveredMessages(
10937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, String selection, String[] selectionArgs,
109472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
109572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String[] mmsProjection = createMmsProjection(projection, pduTable);
10967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
10987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
10997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
110072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables(pduTable));
110172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
11027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection = concatSelections(
11047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, Mms.MESSAGE_BOX + " = " + Mms.MESSAGE_BOX_OUTBOX);
11057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection = concatSelections(
11067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_OUTBOX
11077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_FAILED
11087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_QUEUED + ")");
11097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
11117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
11127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
11137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mmsColumns, 1000);
11147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
11157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                smsColumns, 1);
11167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
111872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        columnsPresentInTable.add(pduTable + "._id");
11197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
11207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
11217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
1122f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columnsPresentInTable, 1, "mms", finalMmsSelection,
11237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
11247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
11257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
1126f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                SMS_COLUMNS, 1, "sms", finalSmsSelection,
11277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
11287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
11297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
11317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
11337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery }, null, null);
11347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
11367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
11387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
1140f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
11417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
11437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
11467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date to the list of columns for an inner
11477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * projection.
11487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
11497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] makeProjectionWithNormalizedDate(
11507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
11517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
11527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 1];
11537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "date * " + dateMultiple + " AS normalized_date";
11557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        System.arraycopy(projection, 0, result, 1, projectionSize);
11567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
11577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String buildConversationQuery(String[] projection,
116072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String selection, String sortOrder, String smsTable, String pduTable) {
116172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String[] mmsProjection = createMmsProjection(projection, pduTable);
11627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
11647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
11657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
11677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
116872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables(pduTable));
116972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
11707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
11727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
11737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithNormalizedDate(mmsColumns, 1000);
11747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithNormalizedDate(smsColumns, 1);
11757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
117772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        columnsPresentInTable.add(pduTable + "._id");
11787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
11797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSelection = concatSelections(selection,
11817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS);
11827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
11837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
11847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                columnsPresentInTable, 0, "mms",
11857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(mmsSelection, MMS_CONVERSATION_CONSTRAINT),
1186f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
11887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection, SMS_COLUMNS,
11897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                0, "sms", concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
1190f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
11927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
11947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
11967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery },
11977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                handleNullSortOrder(sortOrder), null);
11987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
12007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
12027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return outerQueryBuilder.buildQuery(
1204f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
12057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public String getType(Uri uri) {
12097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return VND_ANDROID_DIR_MMS_SMS;
12107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int delete(Uri uri, String selection,
12147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs) {
12157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Context context = getContext();
12177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
1218f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
12197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
12207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
12217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long threadId;
12227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                try {
12237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    threadId = Long.parseLong(uri.getLastPathSegment());
12247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } catch (NumberFormatException e) {
12257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    Log.e(LOG_TAG, "Thread ID must be a long.");
12267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    break;
12277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
12287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = deleteConversation(uri, selection, selectionArgs);
12297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSmsDatabaseHelper.updateThread(db, threadId);
12307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
12327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = MmsProvider.deleteMessages(context, db,
12337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                        selection, selectionArgs, uri)
12347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        + db.delete("sms", selection, selectionArgs);
1235c2bd355a1ebb364c76576c81fb19a1d5e5a7b2a5Snild Dolkow                // Intentionally don't pass the selection variable to updateThreads.
123687bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // When we pass in "locked=0" there, the thread will get excluded from
123787bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // the selection and not get updated.
1238c2bd355a1ebb364c76576c81fb19a1d5e5a7b2a5Snild Dolkow                MmsSmsDatabaseHelper.updateThreads(db, null, null);
12397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_OBSOLETE_THREADS:
124115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                affectedRows = db.delete(TABLE_THREADS,
12424b14c35e9e44d5df2b5340141f2b24bab351c603Tom Taylor                        "_id NOT IN (SELECT DISTINCT thread_id FROM sms where thread_id NOT NULL " +
12434b14c35e9e44d5df2b5340141f2b24bab351c603Tom Taylor                        "UNION SELECT DISTINCT thread_id FROM pdu where thread_id NOT NULL)", null);
12447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
1246b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
12477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
125043f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani            context.getContentResolver().notifyChange(MmsSms.CONTENT_URI, null, true,
125143f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                    UserHandle.USER_ALL);
12527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
12547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
12577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Delete the conversation with the given thread ID.
12587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
12597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private int deleteConversation(Uri uri, String selection, String[] selectionArgs) {
12607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String threadId = uri.getLastPathSegment();
12617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id = " + threadId);
12647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return MmsProvider.deleteMessages(getContext(), db, finalSelection,
12657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                          selectionArgs, uri)
12667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.delete("sms", finalSelection, selectionArgs);
12677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Uri insert(Uri uri, ContentValues values) {
1271b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
1272b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1273b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            long rowId = db.insert(TABLE_PENDING_MSG, null, values);
1274b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            return Uri.parse(uri + "/" + rowId);
1275b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        }
1276b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
12777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int update(Uri uri, ContentValues values,
12817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs) {
1282e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        final int callerUid = Binder.getCallingUid();
128372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String callerPkg = getCallingPackage();
12847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
12867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
12877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
12887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String threadIdString = uri.getPathSegments().get(1);
12897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = updateConversation(threadIdString, values,
129072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selection, selectionArgs, callerUid, callerPkg);
12917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12921ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG:
12947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = db.update(TABLE_PENDING_MSG, values, selection, null);
12957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12961ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12971ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            case URI_CANONICAL_ADDRESS: {
12981ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String extraSelection = "_id=" + uri.getPathSegments().get(1);
12991ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String finalSelection = TextUtils.isEmpty(selection)
13001ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        ? extraSelection : extraSelection + " AND " + selection;
13011ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
13021ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                affectedRows = db.update(TABLE_CANONICAL_ADDRESSES, values, finalSelection, null);
13031ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                break;
13041ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            }
13051ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
130682fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen            case URI_CONVERSATIONS: {
130782fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                final ContentValues finalValues = new ContentValues(1);
130882fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                if (values.containsKey(Threads.ARCHIVED)) {
130982fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                    // Only allow update archived
131082fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                    finalValues.put(Threads.ARCHIVED, values.getAsBoolean(Threads.ARCHIVED));
131182fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                }
131282fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                affectedRows = db.update(TABLE_THREADS, finalValues, selection, selectionArgs);
131382fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                break;
131482fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen            }
131582fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen
13167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
13177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new UnsupportedOperationException(
1318b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                        NO_DELETES_INSERTS_OR_UPDATES + uri);
13197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
13227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            getContext().getContentResolver().notifyChange(
132343f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                    MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
13247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
13267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
13277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
132872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private int updateConversation(String threadIdString, ContentValues values, String selection,
132972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String[] selectionArgs, int callerUid, String callerPkg) {
13307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
13317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
13327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
13337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
13347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return 0;
1335e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen
1336e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        }
1337e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
1338e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // CREATOR should not be changed by non-SYSTEM/PHONE apps
133972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            Log.w(LOG_TAG, callerPkg + " tries to update CREATOR");
1340e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // Sms.CREATOR and Mms.CREATOR are same. But let's do this
1341e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // twice in case the names may differ in the future
1342e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            values.remove(Sms.CREATOR);
1343e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            values.remove(Mms.CREATOR);
13447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
13477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id=" + threadIdString);
13487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return db.update(MmsProvider.TABLE_PDU, values, finalSelection, selectionArgs)
13497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.update("sms", values, finalSelection, selectionArgs);
13507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
13517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
13537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Construct Sets of Strings containing exactly the columns
13547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * present in each table.  We will use this when constructing
13557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION queries across the MMS and SMS tables.
13567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
13577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static void initializeColumnSets() {
13587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int commonColumnCount = MMS_SMS_COLUMNS.length;
13597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int mmsOnlyColumnCount = MMS_ONLY_COLUMNS.length;
13607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int smsOnlyColumnCount = SMS_ONLY_COLUMNS.length;
13617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> unionColumns = new HashSet<String>();
13627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < commonColumnCount; i++) {
13647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
13657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
13667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_SMS_COLUMNS[i]);
13677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < mmsOnlyColumnCount; i++) {
13697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_ONLY_COLUMNS[i]);
13707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_ONLY_COLUMNS[i]);
13717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < smsOnlyColumnCount; i++) {
13737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(SMS_ONLY_COLUMNS[i]);
13747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(SMS_ONLY_COLUMNS[i]);
13757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
13787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String columnName : unionColumns) {
13797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            UNION_COLUMNS[i++] = columnName;
13807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
138286b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen
138386b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    @Override
138486b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
138586b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        // Dump default SMS app
138686b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(getContext());
138786b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        if (TextUtils.isEmpty(defaultSmsApp)) {
138886b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen            defaultSmsApp = "None";
138986b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        }
139086b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        writer.println("Default SMS app: " + defaultSmsApp);
139186b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    }
13927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project}
1393