MmsSmsProvider.java revision 5926996da70fff9275e948d1cf8a0f17b52a5e14
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
1966d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagnerimport java.util.Arrays;
2066d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagnerimport java.util.HashSet;
2166d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagnerimport java.util.List;
2266d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagnerimport java.util.Set;
237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentProvider;
257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentValues;
267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.Context;
277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.UriMatcher;
287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.Cursor;
297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.DatabaseUtils;
307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper;
327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.net.Uri;
347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.BaseColumns;
357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.CanonicalAddressesColumns;
367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Mms;
377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.MmsSms;
387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Sms;
397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Threads;
407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.ThreadsColumns;
417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.MmsSms.PendingMessages;
427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Sms.Conversations;
437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.text.TextUtils;
447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.util.Log;
457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
46b1bae65bf18dc22762cf7b8210fdad836b3e4ee5Tom Taylorimport com.google.android.mms.pdu.PduHeaders;
477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project/**
497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides the ability to query the MMS and SMS databases
507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * at the same time, mixing messages from both in a single thread
517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * (A.K.A. conversation).
527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * A virtual column, MmsSms.TYPE_DISCRIMINATOR_COLUMN, may be
547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * requested in the projection for a query.  Its value is either "mms"
557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * or "sms", depending on whether the message represented by the row
567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * is an MMS message or an SMS message, respectively.
577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class also provides the ability to find out what addresses
597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * participated in a particular thread.  It doesn't support updates
607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for either of these.
617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides a way to allocate and retrieve thread IDs.
637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This is done atomically through a query.  There is no insert URI
647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for this.
657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Finally, this class provides a way to delete or update all messages
677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * in a thread.
687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project */
697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectpublic class MmsSmsProvider extends ContentProvider {
707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final UriMatcher URI_MATCHER =
717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new UriMatcher(UriMatcher.NO_MATCH);
727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String LOG_TAG = "MmsSmsProvider";
73816e934a43bf705835bdb24503a85a14c4861991Tom Taylor    private static final boolean DEBUG = false;
747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String NO_DELETES_INSERTS_OR_UPDATES =
767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "MmsSmsProvider does not support deletes, inserts, or updates for this URI.";
77f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS                     = 0;
78f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_MESSAGES            = 1;
79f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_RECIPIENTS          = 2;
80f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_MESSAGES_BY_PHONE                 = 3;
81f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_THREAD_ID                         = 4;
82f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESS                 = 5;
83f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_PENDING_MSG                       = 6;
84f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_COMPLETE_CONVERSATIONS            = 7;
85f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_UNDELIVERED_MSG                   = 8;
86f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_SUBJECT             = 9;
87f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_NOTIFICATIONS                     = 10;
88f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_OBSOLETE_THREADS                  = 11;
89f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_DRAFT                             = 12;
90f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESSES               = 13;
91f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_SEARCH                            = 14;
928e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_SEARCH_SUGGEST                    = 15;
938e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_ALL          = 16;
948e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID = 17;
956a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner    private static final int URI_MESSAGE_ID_TO_THREAD              = 18;
967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the name of the table that is used to store the queue of
997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages(both MMS and SMS) to be sent/downloaded.
1007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
1017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public static final String TABLE_PENDING_MSG = "pending_msgs";
1027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1031ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    /**
1041ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     * the name of the table that is used to store the canonical addresses for both SMS and MMS.
1051ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     */
1061ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String TABLE_CANONICAL_ADDRESSES = "canonical_addresses";
1071ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These constants are used to construct union queries across the
1097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // MMS and SMS base tables.
1107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear in both the MMS ("pdu") and
1127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // SMS ("sms") message tables.
1137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_SMS_COLUMNS =
114ea5c40c18a83bd984da79ecda301bd5a7cd9daa1Fredrik Roubert            { BaseColumns._ID, Mms.DATE, Mms.DATE_SENT, Mms.READ, Mms.THREAD_ID, Mms.LOCKED };
1157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the MMS message
1177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_ONLY_COLUMNS = {
1197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.CONTENT_CLASS, Mms.CONTENT_LOCATION, Mms.CONTENT_TYPE,
1207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.DELIVERY_REPORT, Mms.EXPIRY, Mms.MESSAGE_CLASS, Mms.MESSAGE_ID,
1217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.MESSAGE_SIZE, Mms.MESSAGE_TYPE, Mms.MESSAGE_BOX, Mms.PRIORITY,
1227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_STATUS, Mms.RESPONSE_STATUS, Mms.RESPONSE_TEXT,
1237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.RETRIEVE_STATUS, Mms.RETRIEVE_TEXT_CHARSET, Mms.REPORT_ALLOWED,
1247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_REPORT, Mms.STATUS, Mms.SUBJECT, Mms.SUBJECT_CHARSET,
1257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.TRANSACTION_ID, Mms.MMS_VERSION };
1267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the SMS message
1287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] SMS_ONLY_COLUMNS =
1307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            { "address", "body", "person", "reply_path_present",
131ddf267c20a697f66b8238538fb6ad31507724692Tom Taylor              "service_center", "status", "subject", "type", "error_code" };
1327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the "threads" table.
1347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] THREADS_COLUMNS = {
1357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        BaseColumns._ID,
1367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.DATE,
1377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.RECIPIENT_IDS,
1387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.MESSAGE_COUNT
1397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    };
1407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1411ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_1 =
1421ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns.ADDRESS };
1431ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1441ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_2 =
1451ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns._ID,
1461ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                    CanonicalAddressesColumns.ADDRESS };
1471ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS and SMS
1497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // message tables.
1507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] UNION_COLUMNS =
1517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new String[MMS_SMS_COLUMNS.length
1527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + MMS_ONLY_COLUMNS.length
1537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + SMS_ONLY_COLUMNS.length];
1547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS table.
1567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> MMS_COLUMNS = new HashSet<String>();
1577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the SMS table.
1597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> SMS_COLUMNS = new HashSet<String>();
1607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String VND_ANDROID_DIR_MMS_SMS =
1627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "vnd.android-dir/mms-sms";
1637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] ID_PROJECTION = { BaseColumns._ID };
1657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] EMPTY_STRING_ARRAY = new String[0];
1677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String SMS_CONVERSATION_CONSTRAINT = "(" +
1697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Sms.TYPE + " != " + Sms.MESSAGE_TYPE_DRAFT + ")";
1707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String MMS_CONVERSATION_CONSTRAINT = "(" +
1727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS + " AND (" +
1737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_SEND_REQ + " OR " +
1747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF + " OR " +
1757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + "))";
1767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
17701c75ba95b875674a83128defc6b267e522db346Chen Mike    // Search on the words table but return the rows from the corresponding sms table
17801c75ba95b875674a83128defc6b267e522db346Chen Mike    private static final String SMS_QUERY =
179ea5c40c18a83bd984da79ecda301bd5a7cd9daa1Fredrik Roubert            "SELECT sms._id AS _id,thread_id,address,body,date,date_sent,index_text,words._id " +
18076e665b3042222aa6d65eccb0f84618f387837aaMark Wagner            "FROM sms,words WHERE (index_text MATCH ? " +
18101c75ba95b875674a83128defc6b267e522db346Chen Mike            "AND sms._id=words.source_id AND words.table_to_use=1)";
18201c75ba95b875674a83128defc6b267e522db346Chen Mike
18301c75ba95b875674a83128defc6b267e522db346Chen Mike    // Search on the words table but return the rows from the corresponding parts table
18401c75ba95b875674a83128defc6b267e522db346Chen Mike    private static final String MMS_QUERY =
18501c75ba95b875674a83128defc6b267e522db346Chen Mike            "SELECT pdu._id,thread_id,addr.address,part.text " +
186ea5c40c18a83bd984da79ecda301bd5a7cd9daa1Fredrik Roubert            "AS body,pdu.date,pdu.date_sent,index_text,words._id " +
18701c75ba95b875674a83128defc6b267e522db346Chen Mike            "FROM pdu,part,addr,words WHERE ((part.mid=pdu._id) AND " +
18801c75ba95b875674a83128defc6b267e522db346Chen Mike            "(addr.msg_id=pdu._id) AND " +
18901c75ba95b875674a83128defc6b267e522db346Chen Mike            "(addr.type=" + PduHeaders.TO + ") AND " +
19001c75ba95b875674a83128defc6b267e522db346Chen Mike            "(part.ct='text/plain') AND " +
19176e665b3042222aa6d65eccb0f84618f387837aaMark Wagner            "(index_text MATCH ?) AND " +
19201c75ba95b875674a83128defc6b267e522db346Chen Mike            "(part._id = words.source_id) AND " +
19301c75ba95b875674a83128defc6b267e522db346Chen Mike            "(words.table_to_use=2))";
19401c75ba95b875674a83128defc6b267e522db346Chen Mike
19501c75ba95b875674a83128defc6b267e522db346Chen Mike    // This code queries the sms and mms tables and returns a unified result set
19601c75ba95b875674a83128defc6b267e522db346Chen Mike    // of text matches.  We query the sms table which is pretty simple.  We also
1979081ab6bd08fa66bac28d65f0ce4fca14b6954a6Jean-Baptiste Queru    // query the pdu, part and addr table to get the mms result.  Notet we're
19801c75ba95b875674a83128defc6b267e522db346Chen Mike    // using a UNION so we have to have the same number of result columns from
19901c75ba95b875674a83128defc6b267e522db346Chen Mike    // both queries.
20001c75ba95b875674a83128defc6b267e522db346Chen Mike    private static final String SMS_MMS_QUERY =
20101c75ba95b875674a83128defc6b267e522db346Chen Mike            SMS_QUERY + " UNION " + MMS_QUERY +
20201c75ba95b875674a83128defc6b267e522db346Chen Mike            " GROUP BY thread_id ORDER BY thread_id ASC, date DESC";
20301c75ba95b875674a83128defc6b267e522db346Chen Mike
2047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String AUTHORITY = "mms-sms";
2057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    static {
2077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations", URI_CONVERSATIONS);
2087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "complete-conversations", URI_COMPLETE_CONVERSATIONS);
2097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In these patterns, "#" is the thread ID.
2117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#", URI_CONVERSATIONS_MESSAGES);
2137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/recipients",
2157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_RECIPIENTS);
2167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/subject",
2197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_SUBJECT);
2207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // URI for deleting obsolete threads.
2227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations/obsolete", URI_OBSOLETE_THREADS);
2237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "messages/byphone/*",
2267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_MESSAGES_BY_PHONE);
2277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameter names are expected:
2297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "subject" and "recipient."  Multiple "recipient" parameters
2307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // may be present.
2317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "threadID", URI_THREAD_ID);
2327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to query the canonical address by given ID.
2347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "canonical-address/#", URI_CANONICAL_ADDRESS);
2357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
23637e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        // Use this pattern to query all canonical addresses.
23737e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        URI_MATCHER.addURI(AUTHORITY, "canonical-addresses", URI_CANONICAL_ADDRESSES);
238f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
23966d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "search", URI_SEARCH);
2408e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "searchSuggest", URI_SEARCH_SUGGEST);
24137e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick
2427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameters may be supplied:
2437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "protocol" and "message." For example:
2447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?
2457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return all pending messages;
2467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=sms
2477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Only return pending SMs;
2487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=mms&message=1
2497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return the the pending MM which ID equals '1'.
2507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //
2517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "pending", URI_PENDING_MSG);
2527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to get a list of undelivered messages.
2547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "undelivered", URI_UNDELIVERED_MSG);
2557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to see what delivery status reports (for
2577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // both MMS and SMS) have not been delivered to the user.
2587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "notifications", URI_NOTIFICATIONS);
2597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "draft", URI_DRAFT);
261f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
262f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked", URI_FIRST_LOCKED_MESSAGE_ALL);
263f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
264f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked/#", URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID);
265f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
2666a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "messageIdToThread", URI_MESSAGE_ID_TO_THREAD);
2677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        initializeColumnSets();
2687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
2697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private SQLiteOpenHelper mOpenHelper;
2717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
272845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa    private boolean mUseStrictPhoneNumberComparation;
273845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa
2747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
2757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public boolean onCreate() {
2767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
277845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa        mUseStrictPhoneNumberComparation =
278845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa            getContext().getResources().getBoolean(
279845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
2807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return true;
2817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
2827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
2847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Cursor query(Uri uri, String[] projection,
2857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs, String sortOrder) {
2867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
2877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
2887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
2897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_COMPLETE_CONVERSATIONS:
290f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getCompleteConversations(projection, selection, sortOrder);
2917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
2927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
2937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String simple = uri.getQueryParameter("simple");
2947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if ((simple != null) && simple.equals("true")) {
2957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    String threadType = uri.getQueryParameter("thread_type");
2967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    if (!TextUtils.isEmpty(threadType)) {
2977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection = concatSelections(
2987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                selection, Threads.TYPE + "=" + threadType);
2997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    }
3007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getSimpleConversations(
3017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                            projection, selection, selectionArgs, sortOrder);
3027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
3037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getConversations(
304f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                            projection, selection, sortOrder);
3057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
3067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
308f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getConversationMessages(uri.getPathSegments().get(1), projection,
309f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                        selection, sortOrder);
3107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_RECIPIENTS:
3127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_SUBJECT:
3177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_MESSAGES_BY_PHONE:
3227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getMessagesByPhoneNumber(
323f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                        uri.getPathSegments().get(2), projection, selection, sortOrder);
3247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_THREAD_ID:
3267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                List<String> recipients = uri.getQueryParameters("recipient");
3277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getThreadId(recipients);
3297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CANONICAL_ADDRESS: {
3317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = "_id=" + uri.getPathSegments().get(1);
3327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
3337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : extraSelection + " AND " + selection;
3341ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3351ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_1,
3361ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        finalSelection,
3371ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3381ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
3391ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
3407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
34237e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick            case URI_CANONICAL_ADDRESSES:
3431ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3441ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_2,
3451ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selection,
3461ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3471ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
3481ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
34937e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick                break;
3508e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH_SUGGEST: {
3518e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                String searchString = uri.getQueryParameter("pattern");
3529e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner
3539e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // find the words which match the pattern using the snippet function.  The
3549e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // snippet function parameters mainly describe how to format the result.
3559e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // See http://www.sqlite.org/fts3.html#section_4_2 for details.
3569e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                String query = String.format("SELECT snippet(words, '', ' ', '', 1, 1) as snippet FROM words WHERE index_text MATCH '%s*' ORDER BY snippet LIMIT 50;", searchString);
3578e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                if (       sortOrder != null
3588e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selection != null
3598e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selectionArgs != null
3608e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || projection != null) {
3618e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    throw new IllegalArgumentException(
3628e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
3638e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "with this query");
3648e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
3658e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
3668e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                cursor = db.rawQuery(query, null);
3678e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                break;
3688e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
3696a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            case URI_MESSAGE_ID_TO_THREAD: {
3706a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // Given a message ID and an indicator for SMS vs. MMS return
3716a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // the thread id of the corresponding thread.
3726a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                try {
3736a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    long id = Long.parseLong(uri.getQueryParameter("row_id"));
3746a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    switch (Integer.parseInt(uri.getQueryParameter("table_to_use"))) {
3756a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 1:  // sms
3766a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.query(
3776a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "sms",
3786a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { "thread_id" },
3796a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "_id=?",
3806a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { String.valueOf(id) },
3816a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
3826a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
3836a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null);
3846a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
3856a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 2:  // mms
3866a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            String mmsQuery =
3876a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "SELECT thread_id FROM pdu,part WHERE ((part.mid=pdu._id) AND " +
3886a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "(part._id=?))";
3896a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.rawQuery(mmsQuery, new String[] { String.valueOf(id) });
3906a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
3916a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    }
3926a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                } catch (NumberFormatException ex) {
3936a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    // ignore... return empty cursor
3946a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                }
3956a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                break;
3966a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            }
3978e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH: {
39887bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                if (       sortOrder != null
39987bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selection != null
40087bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selectionArgs != null
401f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                        || projection != null) {
402f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                    throw new IllegalArgumentException(
403f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
404f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "with this query");
40566d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                }
40687bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor
4078e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                String searchString = uri.getQueryParameter("pattern") + "*";
4088e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
4098e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                try {
41001c75ba95b875674a83128defc6b267e522db346Chen Mike                    cursor = db.rawQuery(SMS_MMS_QUERY, new String[] { searchString, searchString });
4118e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                } catch (Exception ex) {
4128e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    Log.e(LOG_TAG, "got exception: " + ex.toString());
4138e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
41466d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                break;
4158e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
4167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG: {
4177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String protoName = uri.getQueryParameter("protocol");
4187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String msgId = uri.getQueryParameter("message");
4197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                int proto = TextUtils.isEmpty(protoName) ? -1
4207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        : (protoName.equals("sms") ? MmsSms.SMS_PROTO : MmsSms.MMS_PROTO);
4217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = (proto != -1) ?
4237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        (PendingMessages.PROTO_TYPE + "=" + proto) : " 0=0 ";
4247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (!TextUtils.isEmpty(msgId)) {
4257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    extraSelection += " AND " + PendingMessages.MSG_ID + "=" + msgId;
4267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
4277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
4297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : ("(" + extraSelection + ") AND " + selection);
4307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalOrder = TextUtils.isEmpty(sortOrder)
4317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? PendingMessages.DUE_TIME : sortOrder;
4327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = db.query(TABLE_PENDING_MSG, null,
4337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        finalSelection, selectionArgs, null, null, finalOrder);
4347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_UNDELIVERED_MSG: {
4377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getUndeliveredMessages(projection, selection,
4387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
4397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_DRAFT: {
442f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getDraftThread(projection, selection, sortOrder);
4437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
445f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID: {
446f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                long threadId;
447f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                try {
448f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    threadId = Long.parseLong(uri.getLastPathSegment());
449f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                } catch (NumberFormatException e) {
450f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    Log.e(LOG_TAG, "Thread ID must be a long.");
451f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    break;
452f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                }
453f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                cursor = getFirstLockedMessage(projection, "thread_id=" + Long.toString(threadId),
454f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                        sortOrder);
455f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
456f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
457f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_ALL: {
458f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getFirstLockedMessage(projection, selection, sortOrder);
459f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
460f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
4617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
4627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new IllegalStateException("Unrecognized URI:" + uri);
4637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
4647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4655926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (cursor != null) {
4665926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            cursor.setNotificationUri(getContext().getContentResolver(), MmsSms.CONTENT_URI);
4675926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        }
4687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
4697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
4707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
4727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address ID for this address.
4737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
4747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long getSingleAddressId(String address) {
4757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        boolean isEmail = Mms.isEmailAddress(address);
476e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        boolean isPhoneNumber = Mms.isPhoneNumber(address);
477e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
478e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // We lowercase all email addresses, but not addresses that aren't numbers, because
479e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // that would incorrectly turn an address such as "My Vodafone" into "my vodafone"
480e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // and the thread title would be incorrect when displayed in the UI.
4817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String refinedAddress = isEmail ? address.toLowerCase() : address;
482e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
483c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String selection = "address=?";
484c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String[] selectionArgs;
48514595cbe9045755a5aa2bd28989c147c4709268cWei Huang        long retVal = -1L;
486c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
487e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        if (!isPhoneNumber) {
488c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress };
489c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        } else {
49001c75ba95b875674a83128defc6b267e522db346Chen Mike            selection += " OR PHONE_NUMBERS_EQUAL(address, ?, " +
49101c75ba95b875674a83128defc6b267e522db346Chen Mike                        (mUseStrictPhoneNumberComparation ? 1 : 0) + ")";
492c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress, refinedAddress };
493c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        }
494c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
4957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
4967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
4987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
4997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            cursor = db.query(
5007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    "canonical_addresses", ID_PROJECTION,
5017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    selection, selectionArgs, null, null, null);
5027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.getCount() == 0) {
5047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                ContentValues contentValues = new ContentValues(1);
5057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                contentValues.put(CanonicalAddressesColumns.ADDRESS, refinedAddress);
5067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                db = mOpenHelper.getWritableDatabase();
50814595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = db.insert("canonical_addresses",
5097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        CanonicalAddressesColumns.ADDRESS, contentValues);
51014595cbe9045755a5aa2bd28989c147c4709268cWei Huang
511ea59f86662471e682f880b4916ce7588803f5605Wink Saville                Log.d(LOG_TAG, "getSingleAddressId: insert new canonical_address for " +
512ea59f86662471e682f880b4916ce7588803f5605Wink Saville                        /*address*/ "xxxxxx" + ", _id=" + retVal);
51314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
51414595cbe9045755a5aa2bd28989c147c4709268cWei Huang                return retVal;
5157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.moveToFirst()) {
51814595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
5197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } finally {
5217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor != null) {
5227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor.close();
5237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
52614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        return retVal;
5277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address IDs for these addresses.
5317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Set<Long> getAddressIds(List<String> addresses) {
5337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<Long> result = new HashSet<Long>(addresses.size());
5347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String address : addresses) {
5367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (!address.equals(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) {
5377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long id = getSingleAddressId(address);
5387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (id != -1L) {
5397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    result.add(id);
5407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
54114595cbe9045755a5aa2bd28989c147c4709268cWei Huang                    Log.e(LOG_TAG, "getAddressIds: address ID not found for " + address);
5427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
5437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
5467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a sorted array of the given Set of Longs.
5507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long[] getSortedSet(Set<Long> numbers) {
5527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.size();
5537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long[] result = new long[size];
5547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
5557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (Long number : numbers) {
5577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i++] = number;
5587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
55914595cbe9045755a5aa2bd28989c147c4709268cWei Huang
56014595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (size > 1) {
56114595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Arrays.sort(result);
56214595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
56314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
5647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
5657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a String of the numbers in the given array, in order,
5697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * separated by spaces.
5707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String getSpaceSeparatedNumbers(long[] numbers) {
5727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.length;
5737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        StringBuilder buffer = new StringBuilder();
5747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < size; i++) {
5767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (i != 0) {
5777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                buffer.append(' ');
5787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            buffer.append(numbers[i]);
5807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return buffer.toString();
5827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Insert a record for a new thread.
5867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private void insertThread(String recipientIds, int numberOfRecipients) {
5887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ContentValues values = new ContentValues(4);
5897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long date = System.currentTimeMillis();
5917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.DATE, date - date % 1000);
5927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.RECIPIENT_IDS, recipientIds);
5937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (numberOfRecipients > 1) {
5947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            values.put(Threads.TYPE, Threads.BROADCAST_THREAD);
5957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.MESSAGE_COUNT, 0);
5977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
59814595cbe9045755a5aa2bd28989c147c4709268cWei Huang        long result = mOpenHelper.getWritableDatabase().insert("threads", null, values);
59914595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Log.d(LOG_TAG, "insertThread: created new thread_id " + result +
600ea59f86662471e682f880b4916ce7588803f5605Wink Saville                " for recipientIds " + /*recipientIds*/ "xxxxxxx");
60114595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        getContext().getContentResolver().notifyChange(MmsSms.CONTENT_URI, null);
6037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
60514595cbe9045755a5aa2bd28989c147c4709268cWei Huang    private static final String THREAD_QUERY =
60614595cbe9045755a5aa2bd28989c147c4709268cWei Huang            "SELECT _id FROM threads " + "WHERE recipient_ids=?";
60714595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread ID for this list of
6107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * recipients IDs.  If no thread exists with this ID, create
6117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * one and return it.  Callers should always use
6127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Threads.getThreadId to access this information.
6137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private synchronized Cursor getThreadId(List<String> recipients) {
61514595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Set<Long> addressIds = getAddressIds(recipients);
61614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String recipientIds = "";
617c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
6185926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (addressIds.size() == 0) {
6195926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            Log.e(LOG_TAG, "getThreadId: NO receipients specified -- NOT creating thread",
6205926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor                    new Exception());
6215926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            return null;
6225926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        } else if (addressIds.size() == 1) {
6235926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            // optimize for size==1, which should be most of the cases
62414595cbe9045755a5aa2bd28989c147c4709268cWei Huang            for (Long addressId : addressIds) {
62514595cbe9045755a5aa2bd28989c147c4709268cWei Huang                recipientIds = Long.toString(addressId);
62614595cbe9045755a5aa2bd28989c147c4709268cWei Huang            }
62714595cbe9045755a5aa2bd28989c147c4709268cWei Huang        } else {
62814595cbe9045755a5aa2bd28989c147c4709268cWei Huang            recipientIds = getSpaceSeparatedNumbers(getSortedSet(addressIds));
62914595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
6307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
63114595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
632ea59f86662471e682f880b4916ce7588803f5605Wink Saville            Log.d(LOG_TAG, "getThreadId: recipientIds (selectionArgs) =" +
633ea59f86662471e682f880b4916ce7588803f5605Wink Saville                    /*recipientIds*/ "xxxxxxx");
634b4ac04f7bd9d4f16ec181f368c42f89c96f83f55Tom Taylor        }
63514595cbe9045755a5aa2bd28989c147c4709268cWei Huang
63614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String[] selectionArgs = new String[] { recipientIds };
6377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
63814595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Cursor cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
6397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (cursor.getCount() == 0) {
6417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            cursor.close();
64214595cbe9045755a5aa2bd28989c147c4709268cWei Huang
643ea59f86662471e682f880b4916ce7588803f5605Wink Saville            Log.d(LOG_TAG, "getThreadId: create new thread_id for recipients " +
644ea59f86662471e682f880b4916ce7588803f5605Wink Saville                    /*recipients*/ "xxxxxxxx");
6457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            insertThread(recipientIds, recipients.size());
64614595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            db = mOpenHelper.getReadableDatabase();  // In case insertThread closed it
64814595cbe9045755a5aa2bd28989c147c4709268cWei Huang            cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
6497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6506a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner
65114595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (cursor.getCount() > 1) {
65214595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Log.w(LOG_TAG, "getThreadId: why is cursorCount=" + cursor.getCount());
65369e6ffada415d44c72d908ad9e152da51b190642Tom Taylor        }
6547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
6567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String concatSelections(String selection1, String selection2) {
6597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (TextUtils.isEmpty(selection1)) {
6607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection2;
6617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else if (TextUtils.isEmpty(selection2)) {
6627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1;
6637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else {
6647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1 + " AND " + selection2;
6657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the union of all columns
6707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * in both the MMS and SMS messages tables.  Otherwise, return the
6717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * given projection.
6727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullMessageProjection(
6747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
6757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? UNION_COLUMNS : projection;
6767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the set of all columns in
6807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the threads table.  Otherwise, return the given projection.
6817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullThreadsProjection(
6837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
6847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? THREADS_COLUMNS : projection;
6857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null sort order is given, return "normalized_date ASC".
6897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Otherwise, return the given sort order.
6907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String handleNullSortOrder (String sortOrder) {
6927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return sortOrder == null ? "normalized_date ASC" : sortOrder;
6937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return existing threads in the database.
6977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getSimpleConversations(String[] projection, String selection,
6997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
7007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().query("threads", projection,
7017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, selectionArgs, null, null, " date DESC");
7027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread which has draft in both MMS and SMS.
7067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
7087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
7107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT _id, thread_id, ...
7117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
7127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box = 3 AND ...
7137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
7147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT _id, thread_id, ...
7157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
7167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE type = 3 AND ...
7177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *          )
7187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   ;
7197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getDraftThread(String[] projection, String selection,
721f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String sortOrder) {
7227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerProjection = new String[] {BaseColumns._ID, Conversations.THREAD_ID};
7237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
7247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
7257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(MmsProvider.TABLE_PDU);
7277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
7287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
7307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
7317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
7327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_DRAFTS),
733f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
7347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
7357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
7367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
7377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Sms.TYPE + "=" + Sms.MESSAGE_TYPE_DRAFT),
738f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
7397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
7407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
7427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
7447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
7457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
7477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
7497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
751f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                projection, null, null, null, sortOrder, null);
7527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
7547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the most recent message in each conversation in both MMS
7587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
7597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
7617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
7637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT thread_id AS tid, date * 1000 AS normalized_date, ...
7647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
7657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box != 3 AND ...
7667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
7677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date)
7687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
7697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT thread_id AS tid, date AS normalized_date, ...
7707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
7717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE ...
7727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
7737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date))
7747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     GROUP BY tid
7757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     HAVING normalized_date = MAX(normalized_date);
7767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * The msg_box != 3 comparisons ensure that we don't include draft
7787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages.
7797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversations(String[] projection, String selection,
781f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String sortOrder) {
7827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
7837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
7847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(MmsProvider.TABLE_PDU);
7867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
7877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
7897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
7907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1000);
7917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
7927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1);
7937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
7947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
7957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
796f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, MMS_CONVERSATION_CONSTRAINT),
7977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
7987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
7997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
8007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
801f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
8027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
8037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
8047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
8067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
8087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
8097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
8117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
8137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
815f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columns, null, "tid",
8167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "normalized_date = MAX(normalized_date)", sortOrder, null);
8177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
8197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
822f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Return the first locked message found in the union of MMS
823f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * and SMS messages.
824f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
825f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Use this query:
826f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
827816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *  SELECT _id FROM pdu GROUP BY _id HAVING locked=1 UNION SELECT _id FROM sms GROUP
828816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *      BY _id HAVING locked=1 LIMIT 1
829f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
830816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     * We limit by 1 because we're only interested in knowing if
831f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * there is *any* locked message, not the actual messages themselves.
832f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     */
833f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private Cursor getFirstLockedMessage(String[] projection, String selection,
834f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String sortOrder) {
835f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
836f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
837f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
838f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        mmsQueryBuilder.setTables(MmsProvider.TABLE_PDU);
839f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
840f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
841816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        String[] idColumn = new String[] { BaseColumns._ID };
842816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
843f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor        // NOTE: buildUnionSubQuery *ignores* selectionArgs
844f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
845816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
846816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "mms",
847f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
848816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
849816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
850f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
851816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
852816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "sms",
853f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
854816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
855816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
856f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
857f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
858f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        unionQueryBuilder.setDistinct(true);
859f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
860f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String unionQuery = unionQueryBuilder.buildUnionQuery(
861816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                new String[] { mmsSubQuery, smsSubQuery }, null, "1");
862f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
863816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        Cursor cursor = mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
864f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
865f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        if (DEBUG) {
866816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "getFirstLockedMessage query: " + unionQuery);
867816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "cursor count: " + cursor.getCount());
868f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        }
869816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        return cursor;
870f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    }
871f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
872f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    /**
8737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return every message in each conversation in both MMS
8747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
8757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
8767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getCompleteConversations(String[] projection,
877f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String selection, String sortOrder) {
878f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor        String unionQuery = buildConversationQuery(projection, selection, sortOrder);
8797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
8817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
8847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date and thread_id to the list of columns for an
8857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * inner projection.  This is necessary so that the outer query
8867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * can have access to these columns even if the caller hasn't
8877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * requested them in the result.
8887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
8897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String[] makeProjectionWithDateAndThreadId(
8907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
8917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
8927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 2];
8937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "thread_id AS tid";
8957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[1] = "date * " + dateMultiple + " AS normalized_date";
8967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < projectionSize; i++) {
8977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i + 2] = projection[i];
8987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
8997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
9007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages for this thread ID.
9047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationMessages(
9067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
907f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String sortOrder) {
9087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
9097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
9107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
9117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
9127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
9137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(
9167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "thread_id = " + threadIdString);
917f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor        String unionQuery = buildConversationQuery(projection, finalSelection, sortOrder);
9187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
9207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages whose recipients
9247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * included this phone number.
9257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
9277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
9297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   FROM pdu, (SELECT _id AS address_id
9307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *              FROM addr
931c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              WHERE (address='<phoneNumber>' OR
932c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              PHONE_NUMBERS_EQUAL(addr.address, '<phoneNumber>', 1/0)))
9337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             AS matching_addresses
9347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   WHERE pdu._id = matching_addresses.address_id
9357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION
9367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
9377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   FROM sms
938c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *   WHERE (address='<phoneNumber>' OR PHONE_NUMBERS_EQUAL(sms.address, '<phoneNumber>', 1/0));
9397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getMessagesByPhoneNumber(
9417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String phoneNumber, String[] projection, String selection,
942f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String sortOrder) {
9437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String escapedPhoneNumber = DatabaseUtils.sqlEscapeString(phoneNumber);
9447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection =
9457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
9467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
9477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        "pdu._id = matching_addresses.address_id");
9487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection =
9497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
9507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
951c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        "(address=" + escapedPhoneNumber + " OR PHONE_NUMBERS_EQUAL(address, " +
952845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                        escapedPhoneNumber +
953c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        (mUseStrictPhoneNumberComparation ? ", 1))" : ", 0))"));
9547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
9557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
9567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
9587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
9597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(
9607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsProvider.TABLE_PDU +
9617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                ", (SELECT _id AS address_id " +
962c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                "FROM addr WHERE (address=" + escapedPhoneNumber +
963c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                " OR PHONE_NUMBERS_EQUAL(addr.address, " +
964845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                escapedPhoneNumber +
965c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                (mUseStrictPhoneNumberComparation ? ", 1))) " : ", 0))) ") +
9667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "AS matching_addresses");
9677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
9687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
9707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
9717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, MMS_COLUMNS,
972f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "mms", finalMmsSelection, null, null);
9737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
9747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, SMS_COLUMNS,
975f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "sms", finalSmsSelection, null, null);
9767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
9777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
9797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
9817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, sortOrder, null);
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 conversation of certain thread ID.
9887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationById(
9907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
9917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
9927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
9937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
9947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
9957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
9967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
9977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String extraSelection = "_id=" + threadIdString;
10007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, extraSelection);
10017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
10027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullThreadsProjection(projection);
10037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        queryBuilder.setDistinct(true);
10057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        queryBuilder.setTables("threads");
10067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return queryBuilder.query(
10077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mOpenHelper.getReadableDatabase(), columns, finalSelection,
10087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selectionArgs, sortOrder, null, null);
10097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String joinPduAndPendingMsgTables() {
10127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return MmsProvider.TABLE_PDU + " LEFT JOIN " + TABLE_PENDING_MSG
10137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " ON pdu._id = pending_msgs.msg_id";
10147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] createMmsProjection(String[] old) {
10177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] newProjection = new String[old.length];
10187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < old.length; i++) {
10197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (old[i].equals(BaseColumns._ID)) {
10207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                newProjection[i] = "pdu._id";
10217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            } else {
10227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                newProjection[i] = old[i];
10237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
10247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
10257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return newProjection;
10267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getUndeliveredMessages(
10297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, String selection, String[] selectionArgs,
10307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String sortOrder) {
10317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsProjection = createMmsProjection(projection);
10327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
10347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
10357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables());
10377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
10387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection = concatSelections(
10407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, Mms.MESSAGE_BOX + " = " + Mms.MESSAGE_BOX_OUTBOX);
10417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection = concatSelections(
10427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_OUTBOX
10437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_FAILED
10447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_QUEUED + ")");
10457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
10477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
10487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
10497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mmsColumns, 1000);
10507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
10517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                smsColumns, 1);
10527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
10547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add("pdu._id");
10557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
10567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
10577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
1058f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columnsPresentInTable, 1, "mms", finalMmsSelection,
10597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
10607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
10617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
1062f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                SMS_COLUMNS, 1, "sms", finalSmsSelection,
10637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
10647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
10657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
10677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
10697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery }, null, null);
10707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
10727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
10747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
1076f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
10777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
10797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
10827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date to the list of columns for an inner
10837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * projection.
10847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
10857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] makeProjectionWithNormalizedDate(
10867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
10877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
10887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 1];
10897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "date * " + dateMultiple + " AS normalized_date";
10917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        System.arraycopy(projection, 0, result, 1, projectionSize);
10927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
10937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String buildConversationQuery(String[] projection,
1096f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor            String selection, String sortOrder) {
10977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsProjection = createMmsProjection(projection);
10987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
11007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
11017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
11037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
11047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables());
11057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setTables(SmsProvider.TABLE_SMS);
11067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
11087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
11097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithNormalizedDate(mmsColumns, 1000);
11107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithNormalizedDate(smsColumns, 1);
11117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
11137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add("pdu._id");
11147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
11157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSelection = concatSelections(selection,
11177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS);
11187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
11197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
11207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                columnsPresentInTable, 0, "mms",
11217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(mmsSelection, MMS_CONVERSATION_CONSTRAINT),
1122f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
11247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection, SMS_COLUMNS,
11257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                0, "sms", concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
1126f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
11287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
11307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
11327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery },
11337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                handleNullSortOrder(sortOrder), 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        return outerQueryBuilder.buildQuery(
1140f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
11417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
11447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public String getType(Uri uri) {
11457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return VND_ANDROID_DIR_MMS_SMS;
11467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
11497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int delete(Uri uri, String selection,
11507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs) {
11517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
11527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Context context = getContext();
11537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
1154f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
11557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
11567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
11577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long threadId;
11587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                try {
11597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    threadId = Long.parseLong(uri.getLastPathSegment());
11607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } catch (NumberFormatException e) {
11617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    Log.e(LOG_TAG, "Thread ID must be a long.");
11627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    break;
11637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
11647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = deleteConversation(uri, selection, selectionArgs);
11657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSmsDatabaseHelper.updateThread(db, threadId);
11667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
11677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
11687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = MmsProvider.deleteMessages(context, db,
11697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                        selection, selectionArgs, uri)
11707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        + db.delete("sms", selection, selectionArgs);
117187bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // Intentionally don't pass the selection variable to updateAllThreads.
117287bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // When we pass in "locked=0" there, the thread will get excluded from
117387bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // the selection and not get updated.
117487bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                MmsSmsDatabaseHelper.updateAllThreads(db, null, null);
11757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
11767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_OBSOLETE_THREADS:
11777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = db.delete("threads",
11787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        "_id NOT IN (SELECT DISTINCT thread_id FROM sms " +
11797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        "UNION SELECT DISTINCT thread_id FROM pdu)", null);
11807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
11817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
1182b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
11837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
11847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
11867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            context.getContentResolver().notifyChange(MmsSms.CONTENT_URI, null);
11877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
11887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
11897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
11927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Delete the conversation with the given thread ID.
11937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
11947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private int deleteConversation(Uri uri, String selection, String[] selectionArgs) {
11957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String threadId = uri.getLastPathSegment();
11967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
11987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id = " + threadId);
11997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return MmsProvider.deleteMessages(getContext(), db, finalSelection,
12007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                          selectionArgs, uri)
12017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.delete("sms", finalSelection, selectionArgs);
12027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Uri insert(Uri uri, ContentValues values) {
1206b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
1207b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1208b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            long rowId = db.insert(TABLE_PENDING_MSG, null, values);
1209b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            return Uri.parse(uri + "/" + rowId);
1210b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        }
1211b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
12127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int update(Uri uri, ContentValues values,
12167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs) {
12177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
12197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
12207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
12217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String threadIdString = uri.getPathSegments().get(1);
12227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = updateConversation(threadIdString, values,
12237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection, selectionArgs);
12247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12251ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG:
12277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = db.update(TABLE_PENDING_MSG, values, selection, null);
12287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12291ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12301ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            case URI_CANONICAL_ADDRESS: {
12311ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String extraSelection = "_id=" + uri.getPathSegments().get(1);
12321ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String finalSelection = TextUtils.isEmpty(selection)
12331ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        ? extraSelection : extraSelection + " AND " + selection;
12341ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12351ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                affectedRows = db.update(TABLE_CANONICAL_ADDRESSES, values, finalSelection, null);
12361ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                break;
12371ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            }
12381ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
12407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new UnsupportedOperationException(
1241b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                        NO_DELETES_INSERTS_OR_UPDATES + uri);
12427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
12457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            getContext().getContentResolver().notifyChange(
12467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    MmsSms.CONTENT_URI, null);
12477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
12497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private int updateConversation(
12527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, ContentValues values, String selection,
12537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs) {
12547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
12557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
12567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
12577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
12587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return 0;
12597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id=" + threadIdString);
12637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return db.update(MmsProvider.TABLE_PDU, values, finalSelection, selectionArgs)
12647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.update("sms", values, finalSelection, selectionArgs);
12657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
12687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Construct Sets of Strings containing exactly the columns
12697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * present in each table.  We will use this when constructing
12707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION queries across the MMS and SMS tables.
12717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
12727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static void initializeColumnSets() {
12737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int commonColumnCount = MMS_SMS_COLUMNS.length;
12747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int mmsOnlyColumnCount = MMS_ONLY_COLUMNS.length;
12757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int smsOnlyColumnCount = SMS_ONLY_COLUMNS.length;
12767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> unionColumns = new HashSet<String>();
12777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < commonColumnCount; i++) {
12797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
12807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
12817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_SMS_COLUMNS[i]);
12827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < mmsOnlyColumnCount; i++) {
12847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_ONLY_COLUMNS[i]);
12857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_ONLY_COLUMNS[i]);
12867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < smsOnlyColumnCount; i++) {
12887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(SMS_ONLY_COLUMNS[i]);
12897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(SMS_ONLY_COLUMNS[i]);
12907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
12937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String columnName : unionColumns) {
12947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            UNION_COLUMNS[i++] = columnName;
12957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project}
1298