17236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project/*
27236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
37236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
47236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
57236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * you may not use this file except in compliance with the License.
67236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * You may obtain a copy of the License at
77236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
87236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
97236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * See the License for the specific language governing permissions and
147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * limitations under the License.
157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project */
167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectpackage com.android.providers.telephony;
187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
19f27792fb80c6f533a250ec75867c9f2351ff9f04Dianne Hackbornimport android.app.AppOpsManager;
207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentProvider;
217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.ContentValues;
227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.Context;
237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.content.UriMatcher;
247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.Cursor;
257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.DatabaseUtils;
267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteDatabase;
277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper;
287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder;
297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.net.Uri;
30e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.os.Binder;
31785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylorimport android.os.Bundle;
3243f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasaniimport android.os.UserHandle;
337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.BaseColumns;
3486b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport android.provider.Telephony;
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;
38e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.provider.Telephony.MmsSms.PendingMessages;
397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Sms;
40e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport android.provider.Telephony.Sms.Conversations;
417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.Threads;
427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectimport android.provider.Telephony.ThreadsColumns;
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
4886b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport java.io.FileDescriptor;
4986b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wenimport java.io.PrintWriter;
50e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.Arrays;
51e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.HashSet;
52e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.List;
53e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wenimport java.util.Set;
54e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen
557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project/**
567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides the ability to query the MMS and SMS databases
577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * at the same time, mixing messages from both in a single thread
587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * (A.K.A. conversation).
597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * A virtual column, MmsSms.TYPE_DISCRIMINATOR_COLUMN, may be
617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * requested in the projection for a query.  Its value is either "mms"
627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * or "sms", depending on whether the message represented by the row
637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * is an MMS message or an SMS message, respectively.
647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class also provides the ability to find out what addresses
667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * participated in a particular thread.  It doesn't support updates
677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for either of these.
687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This class provides a way to allocate and retrieve thread IDs.
707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * This is done atomically through a query.  There is no insert URI
717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * for this.
727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project *
737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * Finally, this class provides a way to delete or update all messages
747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project * in a thread.
757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project */
767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Projectpublic class MmsSmsProvider extends ContentProvider {
777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final UriMatcher URI_MATCHER =
787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new UriMatcher(UriMatcher.NO_MATCH);
797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String LOG_TAG = "MmsSmsProvider";
80816e934a43bf705835bdb24503a85a14c4861991Tom Taylor    private static final boolean DEBUG = false;
817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String NO_DELETES_INSERTS_OR_UPDATES =
837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "MmsSmsProvider does not support deletes, inserts, or updates for this URI.";
84f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS                     = 0;
85f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_MESSAGES            = 1;
86f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_RECIPIENTS          = 2;
87f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_MESSAGES_BY_PHONE                 = 3;
88f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_THREAD_ID                         = 4;
89f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESS                 = 5;
90f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_PENDING_MSG                       = 6;
91f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_COMPLETE_CONVERSATIONS            = 7;
92f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_UNDELIVERED_MSG                   = 8;
93f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CONVERSATIONS_SUBJECT             = 9;
94f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_NOTIFICATIONS                     = 10;
95f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_OBSOLETE_THREADS                  = 11;
96f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_DRAFT                             = 12;
97f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_CANONICAL_ADDRESSES               = 13;
98f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private static final int URI_SEARCH                            = 14;
998e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_SEARCH_SUGGEST                    = 15;
1008e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_ALL          = 16;
1018e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner    private static final int URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID = 17;
1026a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner    private static final int URI_MESSAGE_ID_TO_THREAD              = 18;
1037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
1057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the name of the table that is used to store the queue of
1067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages(both MMS and SMS) to be sent/downloaded.
1077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
1087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public static final String TABLE_PENDING_MSG = "pending_msgs";
1097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1101ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    /**
1111ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     * the name of the table that is used to store the canonical addresses for both SMS and MMS.
1121ecf192c60625c5227336430ee36705c13ae06e2Wei Huang     */
1131ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String TABLE_CANONICAL_ADDRESSES = "canonical_addresses";
1141ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
11515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor    /**
11615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor     * the name of the table that is used to store the conversation threads.
11715156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor     */
11815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor    static final String TABLE_THREADS = "threads";
11915156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor
1207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These constants are used to construct union queries across the
1217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // MMS and SMS base tables.
1227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear in both the MMS ("pdu") and
1247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // SMS ("sms") message tables.
1257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_SMS_COLUMNS =
126cfb8bbdc3932473966d043fbd72b6c067933f2c1Ye Wen            { BaseColumns._ID, Mms.DATE, Mms.DATE_SENT, Mms.READ, Mms.THREAD_ID, Mms.LOCKED,
12772b147363200ff3f0bc467f23579042bd800ff13Wink Saville                    Mms.SUBSCRIPTION_ID };
1287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the MMS message
1307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] MMS_ONLY_COLUMNS = {
1327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.CONTENT_CLASS, Mms.CONTENT_LOCATION, Mms.CONTENT_TYPE,
1337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.DELIVERY_REPORT, Mms.EXPIRY, Mms.MESSAGE_CLASS, Mms.MESSAGE_ID,
1347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.MESSAGE_SIZE, Mms.MESSAGE_TYPE, Mms.MESSAGE_BOX, Mms.PRIORITY,
1357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_STATUS, Mms.RESPONSE_STATUS, Mms.RESPONSE_TEXT,
1367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.RETRIEVE_STATUS, Mms.RETRIEVE_TEXT_CHARSET, Mms.REPORT_ALLOWED,
1377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Mms.READ_REPORT, Mms.STATUS, Mms.SUBJECT, Mms.SUBJECT_CHARSET,
138f88d1d6733158144e9e0c87f29b446068edf0507Tom Taylor        Mms.TRANSACTION_ID, Mms.MMS_VERSION, Mms.TEXT_ONLY };
1397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are the columns that appear only in the SMS message
1417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // table.
1427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] SMS_ONLY_COLUMNS =
1437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            { "address", "body", "person", "reply_path_present",
144ddf267c20a697f66b8238538fb6ad31507724692Tom Taylor              "service_center", "status", "subject", "type", "error_code" };
1457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the "threads" table.
1477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] THREADS_COLUMNS = {
1487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        BaseColumns._ID,
1497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.DATE,
1507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.RECIPIENT_IDS,
1517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ThreadsColumns.MESSAGE_COUNT
1527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    };
1537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1541ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_1 =
1551ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns.ADDRESS };
1561ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1571ecf192c60625c5227336430ee36705c13ae06e2Wei Huang    private static final String[] CANONICAL_ADDRESSES_COLUMNS_2 =
1581ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            new String[] { CanonicalAddressesColumns._ID,
1591ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                    CanonicalAddressesColumns.ADDRESS };
1601ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
1617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS and SMS
1627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // message tables.
1637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] UNION_COLUMNS =
1647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            new String[MMS_SMS_COLUMNS.length
1657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + MMS_ONLY_COLUMNS.length
1667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                       + SMS_ONLY_COLUMNS.length];
1677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the MMS table.
1697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> MMS_COLUMNS = new HashSet<String>();
1707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    // These are all the columns that appear in the SMS table.
1727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final Set<String> SMS_COLUMNS = new HashSet<String>();
1737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String VND_ANDROID_DIR_MMS_SMS =
1757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            "vnd.android-dir/mms-sms";
1767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] ID_PROJECTION = { BaseColumns._ID };
1787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String[] EMPTY_STRING_ARRAY = new String[0];
1807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1813e1cba826743423642635cc7b03abe292470f4c4Tom Taylor    private static final String[] SEARCH_STRING = new String[1];
1823e1cba826743423642635cc7b03abe292470f4c4Tom Taylor    private static final String SEARCH_QUERY = "SELECT snippet(words, '', ' ', '', 1, 1) as " +
1833e1cba826743423642635cc7b03abe292470f4c4Tom Taylor            "snippet FROM words WHERE index_text MATCH ? ORDER BY snippet LIMIT 50;";
1843e1cba826743423642635cc7b03abe292470f4c4Tom Taylor
1857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String SMS_CONVERSATION_CONSTRAINT = "(" +
1867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Sms.TYPE + " != " + Sms.MESSAGE_TYPE_DRAFT + ")";
1877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
1887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String MMS_CONVERSATION_CONSTRAINT = "(" +
1897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS + " AND (" +
1907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_SEND_REQ + " OR " +
1917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF + " OR " +
1927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + "))";
1937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
19472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String getTextSearchQuery(String smsTable, String pduTable) {
19572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // Search on the words table but return the rows from the corresponding sms table
19672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String smsQuery = "SELECT "
19772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + smsTable + "._id AS _id,"
19872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "thread_id,"
19972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "address,"
20072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "body,"
20172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "date,"
20272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "date_sent,"
20372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "index_text,"
20472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "words._id "
20572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "FROM " + smsTable + ",words "
20672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "WHERE (index_text MATCH ? "
20772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND " + smsTable + "._id=words.source_id "
20872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND words.table_to_use=1)";
20972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
21072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // Search on the words table but return the rows from the corresponding parts table
21172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String mmsQuery = "SELECT "
21272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + "._id,"
21372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "thread_id,"
21472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "addr.address,"
21572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "part.text AS body,"
21672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + ".date,"
21772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + pduTable + ".date_sent,"
21872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "index_text,"
21972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "words._id "
22072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "FROM " + pduTable + ",part,addr,words "
22172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "WHERE ((part.mid=" + pduTable + "._id) "
22272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (addr.msg_id=" + pduTable + "._id) "
22372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (addr.type=" + PduHeaders.TO + ") "
22472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (part.ct='text/plain') "
22572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (index_text MATCH ?) "
22672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (part._id = words.source_id) "
22772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "AND (words.table_to_use=2))";
22872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
22972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // This code queries the sms and mms tables and returns a unified result set
23072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // of text matches.  We query the sms table which is pretty simple.  We also
23172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // query the pdu, part and addr table to get the mms result.  Note we're
23272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // using a UNION so we have to have the same number of result columns from
23372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // both queries.
23472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        return smsQuery + " UNION " + mmsQuery + " "
23572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "GROUP BY thread_id "
23672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + "ORDER BY thread_id ASC, date DESC";
23772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    }
23801c75ba95b875674a83128defc6b267e522db346Chen Mike
2397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static final String AUTHORITY = "mms-sms";
2407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    static {
2427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations", URI_CONVERSATIONS);
2437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "complete-conversations", URI_COMPLETE_CONVERSATIONS);
2447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In these patterns, "#" is the thread ID.
2467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#", URI_CONVERSATIONS_MESSAGES);
2487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/recipients",
2507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_RECIPIENTS);
2517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "conversations/#/subject",
2547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_CONVERSATIONS_SUBJECT);
2557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // URI for deleting obsolete threads.
2577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "conversations/obsolete", URI_OBSOLETE_THREADS);
2587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(
2607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                AUTHORITY, "messages/byphone/*",
2617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                URI_MESSAGES_BY_PHONE);
2627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameter names are expected:
2647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "subject" and "recipient."  Multiple "recipient" parameters
2657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // may be present.
2667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "threadID", URI_THREAD_ID);
2677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to query the canonical address by given ID.
2697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "canonical-address/#", URI_CANONICAL_ADDRESS);
2707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
27137e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        // Use this pattern to query all canonical addresses.
27237e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick        URI_MATCHER.addURI(AUTHORITY, "canonical-addresses", URI_CANONICAL_ADDRESSES);
273f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
27466d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "search", URI_SEARCH);
2758e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "searchSuggest", URI_SEARCH_SUGGEST);
27637e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick
2777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // In this pattern, two query parameters may be supplied:
2787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // "protocol" and "message." For example:
2797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?
2807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return all pending messages;
2817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=sms
2827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Only return pending SMs;
2837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //   content://mms-sms/pending?protocol=mms&message=1
2847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //       -> Return the the pending MM which ID equals '1'.
2857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        //
2867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "pending", URI_PENDING_MSG);
2877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to get a list of undelivered messages.
2897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "undelivered", URI_UNDELIVERED_MSG);
2907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // Use this pattern to see what delivery status reports (for
2927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        // both MMS and SMS) have not been delivered to the user.
2937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "notifications", URI_NOTIFICATIONS);
2947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
2957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        URI_MATCHER.addURI(AUTHORITY, "draft", URI_DRAFT);
296f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
297f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked", URI_FIRST_LOCKED_MESSAGE_ALL);
298f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
299f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        URI_MATCHER.addURI(AUTHORITY, "locked/#", URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID);
300f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
3016a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner        URI_MATCHER.addURI(AUTHORITY, "messageIdToThread", URI_MESSAGE_ID_TO_THREAD);
3027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        initializeColumnSets();
3037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
3047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private SQLiteOpenHelper mOpenHelper;
3067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
307845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa    private boolean mUseStrictPhoneNumberComparation;
308845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa
309785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor    private static final String METHOD_IS_RESTORING = "is_restoring";
310785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor    private static final String IS_RESTORING_KEY = "restoring";
311785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor
3127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
3137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public boolean onCreate() {
314b2ce2d37bc6efc0c37d8cee925d3ad65a01ea4bfYe Wen        setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
3155a3194d943854ec3c2ec5df18a95a5b04ab5efa1Ji Yang        mOpenHelper = MmsSmsDatabaseHelper.getInstanceForCe(getContext());
316845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa        mUseStrictPhoneNumberComparation =
317845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa            getContext().getResources().getBoolean(
318845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                    com.android.internal.R.bool.config_use_strict_phone_number_comparation);
3192d3a779b41d5a553c8615a906ee97da29907313eRoman Sorokin        TelephonyBackupAgent.DeferredSmsMmsRestoreService.startIfFilesExist(getContext());
3207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return true;
3217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
3227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
3247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Cursor query(Uri uri, String[] projection,
3257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs, String sortOrder) {
32672f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // First check if restricted views of the "sms" and "pdu" tables should be used based on the
32772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // caller's identity. Only system, phone or the default sms app can have full access
32872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // of sms/mms data. For other apps, we present a restricted view which only contains sent
32972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        // or received messages, without wap pushes.
33072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final boolean accessRestricted = ProviderUtil.isAccessRestricted(
33172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                getContext(), getCallingPackage(), Binder.getCallingUid());
33272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String pduTable = MmsProvider.getPduTable(accessRestricted);
33372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String smsTable = SmsProvider.getSmsTable(accessRestricted);
33472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen
3357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
3367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
33772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final int match = URI_MATCHER.match(uri);
33872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        switch (match) {
3397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_COMPLETE_CONVERSATIONS:
34072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getCompleteConversations(projection, selection, sortOrder, smsTable,
34172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable);
3427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
3447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String simple = uri.getQueryParameter("simple");
3457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if ((simple != null) && simple.equals("true")) {
3467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    String threadType = uri.getQueryParameter("thread_type");
3477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    if (!TextUtils.isEmpty(threadType)) {
3487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection = concatSelections(
3497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                selection, Threads.TYPE + "=" + threadType);
3507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    }
3517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getSimpleConversations(
3527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                            projection, selection, selectionArgs, sortOrder);
3537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
3547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    cursor = getConversations(
35572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            projection, selection, sortOrder, smsTable, pduTable);
3567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
3577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
359f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                cursor = getConversationMessages(uri.getPathSegments().get(1), projection,
36072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selection, sortOrder, smsTable, pduTable);
3617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_RECIPIENTS:
3637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_SUBJECT:
3687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getConversationById(
3697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        uri.getPathSegments().get(1), projection, selection,
3707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selectionArgs, sortOrder);
3717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_MESSAGES_BY_PHONE:
3737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getMessagesByPhoneNumber(
37472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        uri.getPathSegments().get(2), projection, selection, sortOrder, smsTable,
37572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable);
3767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_THREAD_ID:
3787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                List<String> recipients = uri.getQueryParameters("recipient");
3797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
3807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getThreadId(recipients);
3817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CANONICAL_ADDRESS: {
3837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = "_id=" + uri.getPathSegments().get(1);
3847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
3857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : extraSelection + " AND " + selection;
3861ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3871ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_1,
3881ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        finalSelection,
3891ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3901ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
3911ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
3927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
3937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
39437e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick            case URI_CANONICAL_ADDRESSES:
3951ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                cursor = db.query(TABLE_CANONICAL_ADDRESSES,
3961ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        CANONICAL_ADDRESSES_COLUMNS_2,
3971ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selection,
3981ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        selectionArgs,
3991ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        null, null,
4001ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        sortOrder);
40137e4424493bb364eac8ae07c3d5fce52bebf735dFicus Kirkpatrick                break;
4028e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH_SUGGEST: {
4033e1cba826743423642635cc7b03abe292470f4c4Tom Taylor                SEARCH_STRING[0] = uri.getQueryParameter("pattern") + '*' ;
4049e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner
4059e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // find the words which match the pattern using the snippet function.  The
4069e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // snippet function parameters mainly describe how to format the result.
4079e1fd44679b2de6df6af2c1e8b6bf191e799f4a9Mark Wagner                // See http://www.sqlite.org/fts3.html#section_4_2 for details.
4088e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                if (       sortOrder != null
4098e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selection != null
4108e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || selectionArgs != null
4118e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                        || projection != null) {
4128e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    throw new IllegalArgumentException(
4138e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
4148e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                            "with this query");
4158e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
4168e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
4173e1cba826743423642635cc7b03abe292470f4c4Tom Taylor                cursor = db.rawQuery(SEARCH_QUERY, SEARCH_STRING);
4188e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                break;
4198e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
4206a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            case URI_MESSAGE_ID_TO_THREAD: {
4216a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // Given a message ID and an indicator for SMS vs. MMS return
4226a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                // the thread id of the corresponding thread.
4236a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                try {
4246a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    long id = Long.parseLong(uri.getQueryParameter("row_id"));
4256a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    switch (Integer.parseInt(uri.getQueryParameter("table_to_use"))) {
4266a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 1:  // sms
4276a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.query(
42872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                smsTable,
4296a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { "thread_id" },
4306a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                "_id=?",
4316a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                new String[] { String.valueOf(id) },
4326a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
4336a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null,
4346a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                                null);
4356a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
4366a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                        case 2:  // mms
43772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            String mmsQuery = "SELECT thread_id "
43872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "FROM " + pduTable + ",part "
43972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "WHERE ((part.mid=" + pduTable + "._id) "
44072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                                    + "AND " + "(part._id=?))";
4416a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            cursor = db.rawQuery(mmsQuery, new String[] { String.valueOf(id) });
4426a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                            break;
4436a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    }
4446a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                } catch (NumberFormatException ex) {
4456a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                    // ignore... return empty cursor
4466a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                }
4476a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner                break;
4486a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner            }
4498e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            case URI_SEARCH: {
45087bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                if (       sortOrder != null
45187bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selection != null
45287bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                        || selectionArgs != null
453f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                        || projection != null) {
454f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                    throw new IllegalArgumentException(
455f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "do not specify sortOrder, selection, selectionArgs, or projection" +
456f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner                            "with this query");
45766d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                }
45887bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor
4598e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                String searchString = uri.getQueryParameter("pattern") + "*";
4608e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner
4618e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                try {
46272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                    cursor = db.rawQuery(getTextSearchQuery(smsTable, pduTable),
46372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                            new String[] { searchString, searchString });
4648e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                } catch (Exception ex) {
4658e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                    Log.e(LOG_TAG, "got exception: " + ex.toString());
4668e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner                }
46766d373c4797c53207e8f1ea97f3dc5541f390152Mark Wagner                break;
4688e5ee782690175e9cfb9a37f600f207b952ba8a6Mark Wagner            }
4697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG: {
4707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String protoName = uri.getQueryParameter("protocol");
4717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String msgId = uri.getQueryParameter("message");
4727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                int proto = TextUtils.isEmpty(protoName) ? -1
4737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        : (protoName.equals("sms") ? MmsSms.SMS_PROTO : MmsSms.MMS_PROTO);
4747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String extraSelection = (proto != -1) ?
4767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        (PendingMessages.PROTO_TYPE + "=" + proto) : " 0=0 ";
4777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (!TextUtils.isEmpty(msgId)) {
4787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    extraSelection += " AND " + PendingMessages.MSG_ID + "=" + msgId;
4797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
4807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
4817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalSelection = TextUtils.isEmpty(selection)
4827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? extraSelection : ("(" + extraSelection + ") AND " + selection);
4837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String finalOrder = TextUtils.isEmpty(sortOrder)
4847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        ? PendingMessages.DUE_TIME : sortOrder;
4857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = db.query(TABLE_PENDING_MSG, null,
4867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        finalSelection, selectionArgs, null, null, finalOrder);
4877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_UNDELIVERED_MSG: {
4907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor = getUndeliveredMessages(projection, selection,
49172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selectionArgs, sortOrder, smsTable, pduTable);
4927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
4947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_DRAFT: {
49572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getDraftThread(projection, selection, sortOrder, smsTable, pduTable);
4967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
4977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
498f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_BY_THREAD_ID: {
499f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                long threadId;
500f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                try {
501f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    threadId = Long.parseLong(uri.getLastPathSegment());
502f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                } catch (NumberFormatException e) {
503f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    Log.e(LOG_TAG, "Thread ID must be a long.");
504f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                    break;
505f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                }
506f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                cursor = getFirstLockedMessage(projection, "thread_id=" + Long.toString(threadId),
50772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        sortOrder, smsTable, pduTable);
508f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
509f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
510f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            case URI_FIRST_LOCKED_MESSAGE_ALL: {
51172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                cursor = getFirstLockedMessage(
51272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        projection, selection, sortOrder, smsTable, pduTable);
513f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor                break;
514f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor            }
5157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
5167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new IllegalStateException("Unrecognized URI:" + uri);
5177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5195926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (cursor != null) {
5205926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            cursor.setNotificationUri(getContext().getContentResolver(), MmsSms.CONTENT_URI);
5215926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        }
5227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
5237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address ID for this address.
5277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long getSingleAddressId(String address) {
5297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        boolean isEmail = Mms.isEmailAddress(address);
530e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        boolean isPhoneNumber = Mms.isPhoneNumber(address);
531e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
532e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // We lowercase all email addresses, but not addresses that aren't numbers, because
533e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // that would incorrectly turn an address such as "My Vodafone" into "my vodafone"
534e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        // and the thread title would be incorrect when displayed in the UI.
5357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String refinedAddress = isEmail ? address.toLowerCase() : address;
536e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor
537c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String selection = "address=?";
538c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        String[] selectionArgs;
53914595cbe9045755a5aa2bd28989c147c4709268cWei Huang        long retVal = -1L;
540c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
541e8a24ddaa58295f173fbf37fe3c0acb0d8569118Tom Taylor        if (!isPhoneNumber) {
542c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress };
543c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        } else {
54401c75ba95b875674a83128defc6b267e522db346Chen Mike            selection += " OR PHONE_NUMBERS_EQUAL(address, ?, " +
54501c75ba95b875674a83128defc6b267e522db346Chen Mike                        (mUseStrictPhoneNumberComparation ? 1 : 0) + ")";
546c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang            selectionArgs = new String[] { refinedAddress, refinedAddress };
547c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang        }
548c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
5497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Cursor cursor = null;
5507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
5527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
5537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            cursor = db.query(
5547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    "canonical_addresses", ID_PROJECTION,
5557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    selection, selectionArgs, null, null, null);
5567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.getCount() == 0) {
5587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                ContentValues contentValues = new ContentValues(1);
5597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                contentValues.put(CanonicalAddressesColumns.ADDRESS, refinedAddress);
5607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                db = mOpenHelper.getWritableDatabase();
56214595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = db.insert("canonical_addresses",
5637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        CanonicalAddressesColumns.ADDRESS, contentValues);
56414595cbe9045755a5aa2bd28989c147c4709268cWei Huang
565ea59f86662471e682f880b4916ce7588803f5605Wink Saville                Log.d(LOG_TAG, "getSingleAddressId: insert new canonical_address for " +
566ea59f86662471e682f880b4916ce7588803f5605Wink Saville                        /*address*/ "xxxxxx" + ", _id=" + retVal);
56714595cbe9045755a5aa2bd28989c147c4709268cWei Huang
56814595cbe9045755a5aa2bd28989c147c4709268cWei Huang                return retVal;
5697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor.moveToFirst()) {
57214595cbe9045755a5aa2bd28989c147c4709268cWei Huang                retVal = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
5737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } finally {
5757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (cursor != null) {
5767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                cursor.close();
5777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
58014595cbe9045755a5aa2bd28989c147c4709268cWei Huang        return retVal;
5817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
5827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
5847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the canonical address IDs for these addresses.
5857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
5867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Set<Long> getAddressIds(List<String> addresses) {
5877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<Long> result = new HashSet<Long>(addresses.size());
5887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
5897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String address : addresses) {
5907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (!address.equals(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) {
5917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long id = getSingleAddressId(address);
5927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                if (id != -1L) {
5937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    result.add(id);
5947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } else {
59514595cbe9045755a5aa2bd28989c147c4709268cWei Huang                    Log.e(LOG_TAG, "getAddressIds: address ID not found for " + address);
5967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
5977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
5987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
5997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
6007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a sorted array of the given Set of Longs.
6047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private long[] getSortedSet(Set<Long> numbers) {
6067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.size();
6077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long[] result = new long[size];
6087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
6097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (Long number : numbers) {
6117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i++] = number;
6127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
61314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
61414595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (size > 1) {
61514595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Arrays.sort(result);
61614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
61714595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
6197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return a String of the numbers in the given array, in order,
6237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * separated by spaces.
6247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String getSpaceSeparatedNumbers(long[] numbers) {
6267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int size = numbers.length;
6277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        StringBuilder buffer = new StringBuilder();
6287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < size; i++) {
6307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (i != 0) {
6317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                buffer.append(' ');
6327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
6337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            buffer.append(numbers[i]);
6347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return buffer.toString();
6367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Insert a record for a new thread.
6407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private void insertThread(String recipientIds, int numberOfRecipients) {
6427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        ContentValues values = new ContentValues(4);
6437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
6447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        long date = System.currentTimeMillis();
6457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.DATE, date - date % 1000);
6467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.RECIPIENT_IDS, recipientIds);
6477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (numberOfRecipients > 1) {
6487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            values.put(Threads.TYPE, Threads.BROADCAST_THREAD);
6497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
6507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        values.put(ThreadsColumns.MESSAGE_COUNT, 0);
6517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
65215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        long result = mOpenHelper.getWritableDatabase().insert(TABLE_THREADS, null, values);
65314595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Log.d(LOG_TAG, "insertThread: created new thread_id " + result +
654ea59f86662471e682f880b4916ce7588803f5605Wink Saville                " for recipientIds " + /*recipientIds*/ "xxxxxxx");
65514595cbe9045755a5aa2bd28989c147c4709268cWei Huang
65643f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani        getContext().getContentResolver().notifyChange(MmsSms.CONTENT_URI, null, true,
65743f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                UserHandle.USER_ALL);
6587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
6597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
66014595cbe9045755a5aa2bd28989c147c4709268cWei Huang    private static final String THREAD_QUERY =
66114595cbe9045755a5aa2bd28989c147c4709268cWei Huang            "SELECT _id FROM threads " + "WHERE recipient_ids=?";
66214595cbe9045755a5aa2bd28989c147c4709268cWei Huang
6637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
6647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread ID for this list of
6657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * recipients IDs.  If no thread exists with this ID, create
6667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * one and return it.  Callers should always use
6677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Threads.getThreadId to access this information.
6687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
6697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private synchronized Cursor getThreadId(List<String> recipients) {
67014595cbe9045755a5aa2bd28989c147c4709268cWei Huang        Set<Long> addressIds = getAddressIds(recipients);
67114595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String recipientIds = "";
672c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang
6735926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        if (addressIds.size() == 0) {
6745926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            Log.e(LOG_TAG, "getThreadId: NO receipients specified -- NOT creating thread",
6755926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor                    new Exception());
6765926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            return null;
6775926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor        } else if (addressIds.size() == 1) {
6785926996da70fff9275e948d1cf8a0f17b52a5e14Tom Taylor            // optimize for size==1, which should be most of the cases
67914595cbe9045755a5aa2bd28989c147c4709268cWei Huang            for (Long addressId : addressIds) {
68014595cbe9045755a5aa2bd28989c147c4709268cWei Huang                recipientIds = Long.toString(addressId);
68114595cbe9045755a5aa2bd28989c147c4709268cWei Huang            }
68214595cbe9045755a5aa2bd28989c147c4709268cWei Huang        } else {
68314595cbe9045755a5aa2bd28989c147c4709268cWei Huang            recipientIds = getSpaceSeparatedNumbers(getSortedSet(addressIds));
68414595cbe9045755a5aa2bd28989c147c4709268cWei Huang        }
6857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
68614595cbe9045755a5aa2bd28989c147c4709268cWei Huang        if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
687ea59f86662471e682f880b4916ce7588803f5605Wink Saville            Log.d(LOG_TAG, "getThreadId: recipientIds (selectionArgs) =" +
688ea59f86662471e682f880b4916ce7588803f5605Wink Saville                    /*recipientIds*/ "xxxxxxx");
689b4ac04f7bd9d4f16ec181f368c42f89c96f83f55Tom Taylor        }
69014595cbe9045755a5aa2bd28989c147c4709268cWei Huang
69114595cbe9045755a5aa2bd28989c147c4709268cWei Huang        String[] selectionArgs = new String[] { recipientIds };
69215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor
6937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
69415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        db.beginTransaction();
69515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        Cursor cursor = null;
69615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        try {
69715156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            // Find the thread with the given recipients
69815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
6997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
70015156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            if (cursor.getCount() == 0) {
70115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                // No thread with those recipients exists, so create the thread.
70215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                cursor.close();
70314595cbe9045755a5aa2bd28989c147c4709268cWei Huang
70415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                Log.d(LOG_TAG, "getThreadId: create new thread_id for recipients " +
70515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                        /*recipients*/ "xxxxxxxx");
70615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                insertThread(recipientIds, recipients.size());
70714595cbe9045755a5aa2bd28989c147c4709268cWei Huang
70815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                // The thread was just created, now find it and return it.
70915156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
71015156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            }
71115156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            db.setTransactionSuccessful();
71215156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        } catch (Throwable ex) {
71315156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            Log.e(LOG_TAG, ex.getMessage(), ex);
71415156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        } finally {
71515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor            db.endTransaction();
7167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
7176a917909c55d1535f8d5a213a4dadf19bc79b1b8Mark Wagner
71815156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        if (cursor != null && cursor.getCount() > 1) {
71914595cbe9045755a5aa2bd28989c147c4709268cWei Huang            Log.w(LOG_TAG, "getThreadId: why is cursorCount=" + cursor.getCount());
72069e6ffada415d44c72d908ad9e152da51b190642Tom Taylor        }
7217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return cursor;
7227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String concatSelections(String selection1, String selection2) {
7257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (TextUtils.isEmpty(selection1)) {
7267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection2;
7277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else if (TextUtils.isEmpty(selection2)) {
7287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1;
7297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } else {
7307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return selection1 + " AND " + selection2;
7317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
7327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the union of all columns
7367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * in both the MMS and SMS messages tables.  Otherwise, return the
7377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * given projection.
7387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullMessageProjection(
7407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
7417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? UNION_COLUMNS : projection;
7427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null projection is given, return the set of all columns in
7467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * the threads table.  Otherwise, return the given projection.
7477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] handleNullThreadsProjection(
7497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection) {
7507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return projection == null ? THREADS_COLUMNS : projection;
7517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * If a null sort order is given, return "normalized_date ASC".
7557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Otherwise, return the given sort order.
7567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String handleNullSortOrder (String sortOrder) {
7587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return sortOrder == null ? "normalized_date ASC" : sortOrder;
7597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return existing threads in the database.
7637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getSimpleConversations(String[] projection, String selection,
7657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
76615156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        return mOpenHelper.getReadableDatabase().query(TABLE_THREADS, projection,
7677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, selectionArgs, null, null, " date DESC");
7687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
7697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
7717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the thread which has draft in both MMS and SMS.
7727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
7747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
7757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
7767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT _id, thread_id, ...
7777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
7787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box = 3 AND ...
7797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
7807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT _id, thread_id, ...
7817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
7827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE type = 3 AND ...
7837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *          )
7847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   ;
7857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
7867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getDraftThread(String[] projection, String selection,
78772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
7887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerProjection = new String[] {BaseColumns._ID, Conversations.THREAD_ID};
7897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
7907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
7917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
79272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
79372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
7947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
7957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
7967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
7977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
7987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_DRAFTS),
799f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
8007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
8017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerProjection,
8027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
8037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(selection, Sms.TYPE + "=" + Sms.MESSAGE_TYPE_DRAFT),
804f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
8057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
8067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
8087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
8107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
8117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
8137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
8157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
817f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                projection, null, null, null, sortOrder, null);
8187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
8207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
8237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the most recent message in each conversation in both MMS
8247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
8257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
8277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   SELECT ...
8297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     FROM (SELECT thread_id AS tid, date * 1000 AS normalized_date, ...
8307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM pdu
8317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE msg_box != 3 AND ...
8327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
8337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date)
8347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           UNION
8357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *           SELECT thread_id AS tid, date AS normalized_date, ...
8367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             FROM sms
8377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             WHERE ...
8387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             GROUP BY thread_id
8397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             HAVING date = MAX(date))
8407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     GROUP BY tid
8417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *     HAVING normalized_date = MAX(normalized_date);
8427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
8437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * The msg_box != 3 comparisons ensure that we don't include draft
8447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * messages.
8457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
8467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversations(String[] projection, String selection,
84772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
8487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
8497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
8507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
85172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
85272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
8537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
8557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
8567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1000);
8577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
8587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                UNION_COLUMNS, 1);
8597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
8607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
8617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MMS_COLUMNS, 1, "mms",
862f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, MMS_CONVERSATION_CONSTRAINT),
8637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
8647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
8657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
8667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                SMS_COLUMNS, 1, "sms",
867f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
8687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "thread_id", "date = MAX(date)");
8697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
8707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
8727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
8747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, null, null);
8757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
8777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
8797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
881f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columns, null, "tid",
8827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "normalized_date = MAX(normalized_date)", sortOrder, null);
8837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
8857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
8867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
8877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
888f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Return the first locked message found in the union of MMS
889f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * and SMS messages.
890f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
891f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * Use this query:
892f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
893816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *  SELECT _id FROM pdu GROUP BY _id HAVING locked=1 UNION SELECT _id FROM sms GROUP
894816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     *      BY _id HAVING locked=1 LIMIT 1
895f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     *
896816e934a43bf705835bdb24503a85a14c4861991Tom Taylor     * We limit by 1 because we're only interested in knowing if
897f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     * there is *any* locked message, not the actual messages themselves.
898f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor     */
899f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    private Cursor getFirstLockedMessage(String[] projection, String selection,
90072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
901f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
902f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
903f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
90472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(pduTable);
90572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
906f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
907816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        String[] idColumn = new String[] { BaseColumns._ID };
908816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
909f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor        // NOTE: buildUnionSubQuery *ignores* selectionArgs
910f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
911816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
912816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "mms",
913f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
914816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
915816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
916f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
917816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                MmsSms.TYPE_DISCRIMINATOR_COLUMN, idColumn,
918816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                null, 1, "sms",
919f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                selection,
920816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                BaseColumns._ID, "locked=1");
921816e934a43bf705835bdb24503a85a14c4861991Tom Taylor
922f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
923f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
924f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        unionQueryBuilder.setDistinct(true);
925f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
926f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        String unionQuery = unionQueryBuilder.buildUnionQuery(
927816e934a43bf705835bdb24503a85a14c4861991Tom Taylor                new String[] { mmsSubQuery, smsSubQuery }, null, "1");
928f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
929816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        Cursor cursor = mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
930f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
931f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        if (DEBUG) {
932816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "getFirstLockedMessage query: " + unionQuery);
933816e934a43bf705835bdb24503a85a14c4861991Tom Taylor            Log.v("MmsSmsProvider", "cursor count: " + cursor.getCount());
934f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor        }
935816e934a43bf705835bdb24503a85a14c4861991Tom Taylor        return cursor;
936f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    }
937f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor
938f0a7f15a4e5ef5a1d9cb5bb509cbbaac80b1297dTom Taylor    /**
9397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return every message in each conversation in both MMS
9407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * and SMS.
9417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getCompleteConversations(String[] projection,
94372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String selection, String sortOrder, String smsTable, String pduTable) {
94472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String unionQuery = buildConversationQuery(projection, selection, sortOrder, smsTable,
94572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable);
9467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
9487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date and thread_id to the list of columns for an
9527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * inner projection.  This is necessary so that the outer query
9537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * can have access to these columns even if the caller hasn't
9547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * requested them in the result.
9557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private String[] makeProjectionWithDateAndThreadId(
9577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
9587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
9597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 2];
9607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "thread_id AS tid";
9627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[1] = "date * " + dateMultiple + " AS normalized_date";
9637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < projectionSize; i++) {
9647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            result[i + 2] = projection[i];
9657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
9677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages for this thread ID.
9717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
9727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationMessages(
9737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
97472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
9757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
9767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
9777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
9787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
9797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
9807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
9817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(
9837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "thread_id = " + threadIdString);
98472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String unionQuery = buildConversationQuery(projection, finalSelection, sortOrder, smsTable,
98572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable);
9867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
9887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
9897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
9907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
9917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the union of MMS and SMS messages whose recipients
9927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * included this phone number.
9937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Use this query:
9957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *
9967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
997670c495b6e0489569f60a38a79770dd4ac44500awhliang     *   FROM pdu, (SELECT msg_id AS address_msg_id
9987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *              FROM addr
999c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              WHERE (address='<phoneNumber>' OR
1000c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *              PHONE_NUMBERS_EQUAL(addr.address, '<phoneNumber>', 1/0)))
10017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *             AS matching_addresses
1002670c495b6e0489569f60a38a79770dd4ac44500awhliang     *   WHERE pdu._id = matching_addresses.address_msg_id
10037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION
10047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * SELECT ...
10057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     *   FROM sms
1006c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang     *   WHERE (address='<phoneNumber>' OR PHONE_NUMBERS_EQUAL(sms.address, '<phoneNumber>', 1/0));
10077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
10087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getMessagesByPhoneNumber(
10097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String phoneNumber, String[] projection, String selection,
101072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
10117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String escapedPhoneNumber = DatabaseUtils.sqlEscapeString(phoneNumber);
10127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection =
10137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
10147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
101572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        pduTable + "._id = matching_addresses.address_msg_id");
10167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection =
10177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(
10187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        selection,
1019c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        "(address=" + escapedPhoneNumber + " OR PHONE_NUMBERS_EQUAL(address, " +
1020845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                        escapedPhoneNumber +
1021c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                        (mUseStrictPhoneNumberComparation ? ", 1))" : ", 0))"));
10227236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
10237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
10247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
10267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
10277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setTables(
102872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                pduTable +
1029670c495b6e0489569f60a38a79770dd4ac44500awhliang                ", (SELECT msg_id AS address_msg_id " +
1030c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                "FROM addr WHERE (address=" + escapedPhoneNumber +
1031c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                " OR PHONE_NUMBERS_EQUAL(addr.address, " +
1032845a9163dffcbd1073930b8b334df27728418201Daisuke Miyakawa                escapedPhoneNumber +
1033c818d636af8c4f3d8a0d332634d1e73a5215d06bWei Huang                (mUseStrictPhoneNumberComparation ? ", 1))) " : ", 0))) ") +
10347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                "AS matching_addresses");
103572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
10367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullMessageProjection(projection);
10387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
10397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, MMS_COLUMNS,
1040f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "mms", finalMmsSelection, null, null);
10417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
10427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, columns, SMS_COLUMNS,
1043f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                0, "sms", finalSmsSelection, null, null);
10447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
10457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
10477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
10497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { mmsSubQuery, smsSubQuery }, sortOrder, null);
10507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(unionQuery, EMPTY_STRING_ARRAY);
10527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
10557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Return the conversation of certain thread ID.
10567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
10577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getConversationById(
10587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String threadIdString, String[] projection, String selection,
10597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs, String sortOrder) {
10607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
10617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
10627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
10637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
10647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return null;
10657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
10667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String extraSelection = "_id=" + threadIdString;
10687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, extraSelection);
10697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
10707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] columns = handleNullThreadsProjection(projection);
10717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        queryBuilder.setDistinct(true);
107315156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor        queryBuilder.setTables(TABLE_THREADS);
10747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return queryBuilder.query(
10757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mOpenHelper.getReadableDatabase(), columns, finalSelection,
10767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selectionArgs, sortOrder, null, null);
10777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
107972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String joinPduAndPendingMsgTables(String pduTable) {
108072f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        return pduTable + " LEFT JOIN " + TABLE_PENDING_MSG
108172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                + " ON " + pduTable + "._id = pending_msgs.msg_id";
10827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
108472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private static String[] createMmsProjection(String[] old, String pduTable) {
10857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] newProjection = new String[old.length];
10867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < old.length; i++) {
10877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            if (old[i].equals(BaseColumns._ID)) {
108872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                newProjection[i] = pduTable + "._id";
10897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            } else {
10907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                newProjection[i] = old[i];
10917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            }
10927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
10937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return newProjection;
10947236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
10957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
10967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private Cursor getUndeliveredMessages(
10977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, String selection, String[] selectionArgs,
109872f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String sortOrder, String smsTable, String pduTable) {
109972f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String[] mmsProjection = createMmsProjection(projection, pduTable);
11007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
11027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
11037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
110472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables(pduTable));
110572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
11067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalMmsSelection = concatSelections(
11087236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, Mms.MESSAGE_BOX + " = " + Mms.MESSAGE_BOX_OUTBOX);
11097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSmsSelection = concatSelections(
11107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                selection, "(" + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_OUTBOX
11117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_FAILED
11127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + " OR " + Sms.TYPE + " = " + Sms.MESSAGE_TYPE_QUEUED + ")");
11137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
11157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
11167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithDateAndThreadId(
11177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                mmsColumns, 1000);
11187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithDateAndThreadId(
11197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                smsColumns, 1);
11207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
112272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        columnsPresentInTable.add(pduTable + "._id");
11237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
11247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
11257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
1126f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                columnsPresentInTable, 1, "mms", finalMmsSelection,
11277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
11287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
11297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection,
1130f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                SMS_COLUMNS, 1, "sms", finalSmsSelection,
11317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                null, null);
11327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
11337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
11357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
11377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery }, null, null);
11387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11397236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
11407236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11417236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
11427236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String outerQuery = outerQueryBuilder.buildQuery(
1144f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
11457236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11467236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return mOpenHelper.getReadableDatabase().rawQuery(outerQuery, EMPTY_STRING_ARRAY);
11477236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
11507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Add normalized date to the list of columns for an inner
11517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * projection.
11527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
11537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String[] makeProjectionWithNormalizedDate(
11547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] projection, int dateMultiple) {
11557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int projectionSize = projection.length;
11567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] result = new String[projectionSize + 1];
11577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        result[0] = "date * " + dateMultiple + " AS normalized_date";
11597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        System.arraycopy(projection, 0, result, 1, projectionSize);
11607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return result;
11617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
11627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static String buildConversationQuery(String[] projection,
116472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String selection, String sortOrder, String smsTable, String pduTable) {
116572f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        String[] mmsProjection = createMmsProjection(projection, pduTable);
11667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
11687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
11697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        mmsQueryBuilder.setDistinct(true);
11717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        smsQueryBuilder.setDistinct(true);
117272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        mmsQueryBuilder.setTables(joinPduAndPendingMsgTables(pduTable));
117372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        smsQueryBuilder.setTables(smsTable);
11747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] smsColumns = handleNullMessageProjection(projection);
11767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] mmsColumns = handleNullMessageProjection(mmsProjection);
11777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerMmsProjection = makeProjectionWithNormalizedDate(mmsColumns, 1000);
11787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String[] innerSmsProjection = makeProjectionWithNormalizedDate(smsColumns, 1);
11797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> columnsPresentInTable = new HashSet<String>(MMS_COLUMNS);
118172f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        columnsPresentInTable.add(pduTable + "._id");
11827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        columnsPresentInTable.add(PendingMessages.ERROR_TYPE);
11837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSelection = concatSelections(selection,
11857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                Mms.MESSAGE_BOX + " != " + Mms.MESSAGE_BOX_DRAFTS);
11867236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(
11877236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerMmsProjection,
11887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                columnsPresentInTable, 0, "mms",
11897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                concatSelections(mmsSelection, MMS_CONVERSATION_CONSTRAINT),
1190f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(
11927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSms.TYPE_DISCRIMINATOR_COLUMN, innerSmsProjection, SMS_COLUMNS,
11937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                0, "sms", concatSelections(selection, SMS_CONVERSATION_CONSTRAINT),
1194f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                null, null);
11957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
11967236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        unionQueryBuilder.setDistinct(true);
11987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
11997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String unionQuery = unionQueryBuilder.buildUnionQuery(
12007236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                new String[] { smsSubQuery, mmsSubQuery },
12017236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                handleNullSortOrder(sortOrder), null);
12027236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12037236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
12047236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12057236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        outerQueryBuilder.setTables("(" + unionQuery + ")");
12067236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return outerQueryBuilder.buildQuery(
1208f008a619299d15bab78b989aef301d97a3930ca3Tom Taylor                smsColumns, null, null, null, sortOrder, null);
12097236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12107236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12117236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12127236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public String getType(Uri uri) {
12137236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return VND_ANDROID_DIR_MMS_SMS;
12147236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12157236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12167236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12177236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int delete(Uri uri, String selection,
12187236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String[] selectionArgs) {
12197236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Context context = getContext();
12217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
1222f0a9e90721310bed023a9ff1f176f1b5e05a14f7Mark Wagner
12237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
12247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
12257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                long threadId;
12267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                try {
12277236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    threadId = Long.parseLong(uri.getLastPathSegment());
12287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                } catch (NumberFormatException e) {
12297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    Log.e(LOG_TAG, "Thread ID must be a long.");
12307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                    break;
12317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                }
12327236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = deleteConversation(uri, selection, selectionArgs);
12337236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                MmsSmsDatabaseHelper.updateThread(db, threadId);
12347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS:
12367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = MmsProvider.deleteMessages(context, db,
12377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                        selection, selectionArgs, uri)
12387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                        + db.delete("sms", selection, selectionArgs);
1239c2bd355a1ebb364c76576c81fb19a1d5e5a7b2a5Snild Dolkow                // Intentionally don't pass the selection variable to updateThreads.
124087bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // When we pass in "locked=0" there, the thread will get excluded from
124187bfe142b5c163e19fb9e60d558bbeb513ca150cTom Taylor                // the selection and not get updated.
1242c2bd355a1ebb364c76576c81fb19a1d5e5a7b2a5Snild Dolkow                MmsSmsDatabaseHelper.updateThreads(db, null, null);
12437236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12447236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_OBSOLETE_THREADS:
124515156cd6afcc7ed57ac7be40ef2d32a615e83599Tom Taylor                affectedRows = db.delete(TABLE_THREADS,
12464b14c35e9e44d5df2b5340141f2b24bab351c603Tom Taylor                        "_id NOT IN (SELECT DISTINCT thread_id FROM sms where thread_id NOT NULL " +
12474b14c35e9e44d5df2b5340141f2b24bab351c603Tom Taylor                        "UNION SELECT DISTINCT thread_id FROM pdu where thread_id NOT NULL)", null);
12487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
1250b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
12517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
125443f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani            context.getContentResolver().notifyChange(MmsSms.CONTENT_URI, null, true,
125543f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                    UserHandle.USER_ALL);
12567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
12577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
12587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
12617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Delete the conversation with the given thread ID.
12627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
12637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private int deleteConversation(Uri uri, String selection, String[] selectionArgs) {
12647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String threadId = uri.getLastPathSegment();
12657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id = " + threadId);
12687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return MmsProvider.deleteMessages(getContext(), db, finalSelection,
12697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                                          selectionArgs, uri)
12707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.delete("sms", finalSelection, selectionArgs);
12717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public Uri insert(Uri uri, ContentValues values) {
1275b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        if (URI_MATCHER.match(uri) == URI_PENDING_MSG) {
1276b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1277b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            long rowId = db.insert(TABLE_PENDING_MSG, null, values);
1278b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor            return Uri.parse(uri + "/" + rowId);
1279b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        }
1280b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor        throw new UnsupportedOperationException(NO_DELETES_INSERTS_OR_UPDATES + uri);
12817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
12827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
12837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    @Override
12847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    public int update(Uri uri, ContentValues values,
12857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            String selection, String[] selectionArgs) {
1286e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        final int callerUid = Binder.getCallingUid();
128772f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen        final String callerPkg = getCallingPackage();
12887236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
12897236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int affectedRows = 0;
12907236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        switch(URI_MATCHER.match(uri)) {
12917236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_CONVERSATIONS_MESSAGES:
12927236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                String threadIdString = uri.getPathSegments().get(1);
12937236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = updateConversation(threadIdString, values,
129472f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen                        selection, selectionArgs, callerUid, callerPkg);
12957236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
12961ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
12977236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            case URI_PENDING_MSG:
12987236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                affectedRows = db.update(TABLE_PENDING_MSG, values, selection, null);
12997236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                break;
13001ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
13011ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            case URI_CANONICAL_ADDRESS: {
13021ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String extraSelection = "_id=" + uri.getPathSegments().get(1);
13031ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                String finalSelection = TextUtils.isEmpty(selection)
13041ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                        ? extraSelection : extraSelection + " AND " + selection;
13051ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
13061ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                affectedRows = db.update(TABLE_CANONICAL_ADDRESSES, values, finalSelection, null);
13071ecf192c60625c5227336430ee36705c13ae06e2Wei Huang                break;
13081ecf192c60625c5227336430ee36705c13ae06e2Wei Huang            }
13091ecf192c60625c5227336430ee36705c13ae06e2Wei Huang
131082fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen            case URI_CONVERSATIONS: {
131182fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                final ContentValues finalValues = new ContentValues(1);
131282fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                if (values.containsKey(Threads.ARCHIVED)) {
131382fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                    // Only allow update archived
131482fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                    finalValues.put(Threads.ARCHIVED, values.getAsBoolean(Threads.ARCHIVED));
131582fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                }
131682fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                affectedRows = db.update(TABLE_THREADS, finalValues, selection, selectionArgs);
131782fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen                break;
131882fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen            }
131982fc72b94a54eb3c70bcfbb1effd9b3a9b775af9Ye Wen
13207236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            default:
13217236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                throw new UnsupportedOperationException(
1322b91bcae9fa009787f165591fd7fc4c8f2f2dfd99Tom Taylor                        NO_DELETES_INSERTS_OR_UPDATES + uri);
13237236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13247236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13257236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        if (affectedRows > 0) {
13267236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            getContext().getContentResolver().notifyChange(
132743f9fb234aabe569b342af78bdaf85effbd85f10Amith Yamasani                    MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
13287236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13297236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return affectedRows;
13307236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
13317236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
133272f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen    private int updateConversation(String threadIdString, ContentValues values, String selection,
133372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            String[] selectionArgs, int callerUid, String callerPkg) {
13347236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        try {
13357236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Long.parseLong(threadIdString);
13367236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        } catch (NumberFormatException exception) {
13377236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            Log.e(LOG_TAG, "Thread ID must be a Long.");
13387236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            return 0;
1339e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen
1340e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        }
1341e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen        if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
1342e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // CREATOR should not be changed by non-SYSTEM/PHONE apps
134372f135589e5d705bcac4a3db3019e4d9d2d04d36Ye Wen            Log.w(LOG_TAG, callerPkg + " tries to update CREATOR");
1344e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // Sms.CREATOR and Mms.CREATOR are same. But let's do this
1345e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            // twice in case the names may differ in the future
1346e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            values.remove(Sms.CREATOR);
1347e07acb9f6a77d9753900224a4caefd5a8aec97eeYe Wen            values.remove(Mms.CREATOR);
13487236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13497236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13507236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
13517236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        String finalSelection = concatSelections(selection, "thread_id=" + threadIdString);
13527236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        return db.update(MmsProvider.TABLE_PDU, values, finalSelection, selectionArgs)
13537236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project                + db.update("sms", values, finalSelection, selectionArgs);
13547236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
13557236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13567236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    /**
13577236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * Construct Sets of Strings containing exactly the columns
13587236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * present in each table.  We will use this when constructing
13597236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     * UNION queries across the MMS and SMS tables.
13607236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project     */
13617236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    private static void initializeColumnSets() {
13627236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int commonColumnCount = MMS_SMS_COLUMNS.length;
13637236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int mmsOnlyColumnCount = MMS_ONLY_COLUMNS.length;
13647236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int smsOnlyColumnCount = SMS_ONLY_COLUMNS.length;
13657236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        Set<String> unionColumns = new HashSet<String>();
13667236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13677236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < commonColumnCount; i++) {
13687236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
13697236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(MMS_SMS_COLUMNS[i]);
13707236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_SMS_COLUMNS[i]);
13717236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13727236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < mmsOnlyColumnCount; i++) {
13737236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            MMS_COLUMNS.add(MMS_ONLY_COLUMNS[i]);
13747236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(MMS_ONLY_COLUMNS[i]);
13757236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13767236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (int i = 0; i < smsOnlyColumnCount; i++) {
13777236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            SMS_COLUMNS.add(SMS_ONLY_COLUMNS[i]);
13787236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            unionColumns.add(SMS_ONLY_COLUMNS[i]);
13797236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13807236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project
13817236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        int i = 0;
13827236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        for (String columnName : unionColumns) {
13837236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project            UNION_COLUMNS[i++] = columnName;
13847236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project        }
13857236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project    }
138686b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen
138786b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    @Override
138886b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
138986b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        // Dump default SMS app
139086b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(getContext());
139186b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        if (TextUtils.isEmpty(defaultSmsApp)) {
139286b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen            defaultSmsApp = "None";
139386b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        }
139486b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen        writer.println("Default SMS app: " + defaultSmsApp);
139586b8a2cfb7558ec500b4de46bac3d873eaf6028fYe Wen    }
1396785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor
1397785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor    @Override
1398785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor    public Bundle call(String method, String arg, Bundle extras) {
1399785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor        if (METHOD_IS_RESTORING.equals(method)) {
1400785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor            Bundle result = new Bundle();
1401785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor            result.putBoolean(IS_RESTORING_KEY, TelephonyBackupAgent.getIsRestoring());
1402785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor            return result;
1403785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor        }
1404785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor        Log.w(LOG_TAG, "Ignored unsupported " + method + " call");
1405785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor        return null;
1406785f9214b0da4bacf4c78ae90f08c535ab04c5a5Tom Taylor    }
14077236c3ad7ff01dd5ece14a2cabbf5ce3a570d793The Android Open Source Project}
1408