1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2007-2008 Esmertec AG.
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2007-2008 The Android Open Source Project
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.mmslib.pdu;
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentUris;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.DatabaseUtils;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.sqlite.SQLiteException;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.MediaStore;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.Mms;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.Mms.Addr;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.Mms.Part;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.MmsSms;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.provider.Telephony.MmsSms.PendingMessages;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.ArrayMap;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.v4.util.SimpleArrayMap;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.PhoneNumberUtils;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.Log;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.SparseArray;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.SparseIntArray;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.InvalidHeaderValueException;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.MmsException;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.SqliteWrapper;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.util.DownloadDrmHelper;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.util.DrmConvertSession;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.util.PduCache;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.mmslib.util.PduCacheEntry;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsSmsUtils;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ContentType;
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.OsUtil;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.ByteArrayOutputStream;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.File;
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.FileNotFoundException;
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.IOException;
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.InputStream;
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.OutputStream;
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.UnsupportedEncodingException;
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.HashSet;
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Map;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * This class is the high-level manager of PDU storage.
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class PduPersister {
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = "PduPersister";
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final boolean LOCAL_LOGV = false;
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * The uri of temporary drm objects.
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final String TEMPORARY_DRM_OBJECT_URI =
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            "content://mms/" + Long.MAX_VALUE + "/part";
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Indicate that we transiently failed to process a MM.
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PROC_STATUS_TRANSIENT_FAILURE = 1;
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Indicate that we permanently failed to process a MM.
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PROC_STATUS_PERMANENTLY_FAILURE = 2;
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Indicate that we have successfully processed a MM.
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PROC_STATUS_COMPLETED = 3;
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final String BEGIN_VCARD = "BEGIN:VCARD";
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static PduPersister sPersister;
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final PduCache PDU_CACHE_INSTANCE;
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int[] ADDRESS_FIELDS = new int[]{
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PduHeaders.BCC,
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PduHeaders.CC,
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PduHeaders.FROM,
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PduHeaders.TO
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final String[] PDU_PROJECTION = new String[]{
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms._ID,
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MESSAGE_BOX,
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.THREAD_ID,
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.RETRIEVE_TEXT,
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.SUBJECT,
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.CONTENT_LOCATION,
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.CONTENT_TYPE,
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MESSAGE_CLASS,
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MESSAGE_ID,
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.RESPONSE_TEXT,
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.TRANSACTION_ID,
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.CONTENT_CLASS,
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.DELIVERY_REPORT,
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MESSAGE_TYPE,
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MMS_VERSION,
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.PRIORITY,
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.READ_REPORT,
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.READ_STATUS,
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.REPORT_ALLOWED,
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.RETRIEVE_STATUS,
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.STATUS,
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.DATE,
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.DELIVERY_TIME,
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.EXPIRY,
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.MESSAGE_SIZE,
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.SUBJECT_CHARSET,
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.RETRIEVE_TEXT_CHARSET,
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.READ,
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Mms.SEEN,
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_ID                    = 0;
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MESSAGE_BOX           = 1;
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_THREAD_ID             = 2;
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_RETRIEVE_TEXT         = 3;
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_SUBJECT               = 4;
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_CONTENT_LOCATION      = 5;
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_CONTENT_TYPE          = 6;
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MESSAGE_CLASS         = 7;
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MESSAGE_ID            = 8;
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_RESPONSE_TEXT         = 9;
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_TRANSACTION_ID        = 10;
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_CONTENT_CLASS         = 11;
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_DELIVERY_REPORT       = 12;
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MESSAGE_TYPE          = 13;
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MMS_VERSION           = 14;
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_PRIORITY              = 15;
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_READ_REPORT           = 16;
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_READ_STATUS           = 17;
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_REPORT_ALLOWED        = 18;
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_RETRIEVE_STATUS       = 19;
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_STATUS                = 20;
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_DATE                  = 21;
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_DELIVERY_TIME         = 22;
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_EXPIRY                = 23;
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_MESSAGE_SIZE          = 24;
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_SUBJECT_CHARSET       = 25;
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_RETRIEVE_TEXT_CHARSET = 26;
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_READ                  = 27;
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final int PDU_COLUMN_SEEN                  = 28;
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String[] PART_PROJECTION = new String[] {
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part._ID,
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.CHARSET,
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.CONTENT_DISPOSITION,
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.CONTENT_ID,
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.CONTENT_LOCATION,
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.CONTENT_TYPE,
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.FILENAME,
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.NAME,
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Part.TEXT
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_ID                  = 0;
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_CHARSET             = 1;
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_CONTENT_DISPOSITION = 2;
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_CONTENT_ID          = 3;
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_CONTENT_LOCATION    = 4;
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_CONTENT_TYPE        = 5;
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_FILENAME            = 6;
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_NAME                = 7;
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PART_COLUMN_TEXT                = 8;
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SimpleArrayMap<Uri, Integer> MESSAGE_BOX_MAP;
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // These map are used for convenience in persist() and load().
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseIntArray CHARSET_COLUMN_INDEX_MAP;
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseIntArray ENCODED_STRING_COLUMN_INDEX_MAP;
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseIntArray TEXT_STRING_COLUMN_INDEX_MAP;
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseIntArray OCTET_COLUMN_INDEX_MAP;
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseIntArray LONG_COLUMN_INDEX_MAP;
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseArray<String> CHARSET_COLUMN_NAME_MAP;
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseArray<String> ENCODED_STRING_COLUMN_NAME_MAP;
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseArray<String> TEXT_STRING_COLUMN_NAME_MAP;
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseArray<String> OCTET_COLUMN_NAME_MAP;
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final SparseArray<String> LONG_COLUMN_NAME_MAP;
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static {
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MESSAGE_BOX_MAP = new SimpleArrayMap<Uri, Integer>();
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MESSAGE_BOX_MAP.put(Mms.Inbox.CONTENT_URI, Mms.MESSAGE_BOX_INBOX);
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MESSAGE_BOX_MAP.put(Mms.Sent.CONTENT_URI, Mms.MESSAGE_BOX_SENT);
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MESSAGE_BOX_MAP.put(Mms.Draft.CONTENT_URI, Mms.MESSAGE_BOX_DRAFTS);
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        MESSAGE_BOX_MAP.put(Mms.Outbox.CONTENT_URI, Mms.MESSAGE_BOX_OUTBOX);
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_INDEX_MAP = new SparseIntArray();
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT_CHARSET);
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT_CHARSET);
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_NAME_MAP = new SparseArray<String>();
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT_CHARSET);
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT_CHARSET);
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Encoded string field code -> column index/name map.
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_INDEX_MAP = new SparseIntArray();
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT);
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT);
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_NAME_MAP = new SparseArray<String>();
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT);
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT);
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Text string field code -> column index/name map.
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP = new SparseIntArray();
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_LOCATION, PDU_COLUMN_CONTENT_LOCATION);
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_TYPE, PDU_COLUMN_CONTENT_TYPE);
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_CLASS, PDU_COLUMN_MESSAGE_CLASS);
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_ID, PDU_COLUMN_MESSAGE_ID);
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RESPONSE_TEXT, PDU_COLUMN_RESPONSE_TEXT);
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.TRANSACTION_ID, PDU_COLUMN_TRANSACTION_ID);
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP = new SparseArray<String>();
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_LOCATION, Mms.CONTENT_LOCATION);
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_TYPE, Mms.CONTENT_TYPE);
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_CLASS, Mms.MESSAGE_CLASS);
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_ID, Mms.MESSAGE_ID);
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.RESPONSE_TEXT, Mms.RESPONSE_TEXT);
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.TRANSACTION_ID, Mms.TRANSACTION_ID);
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Octet field code -> column index/name map.
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP = new SparseIntArray();
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_CLASS, PDU_COLUMN_CONTENT_CLASS);
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_REPORT, PDU_COLUMN_DELIVERY_REPORT);
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_TYPE, PDU_COLUMN_MESSAGE_TYPE);
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MMS_VERSION, PDU_COLUMN_MMS_VERSION);
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.PRIORITY, PDU_COLUMN_PRIORITY);
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_REPORT, PDU_COLUMN_READ_REPORT);
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_STATUS, PDU_COLUMN_READ_STATUS);
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.REPORT_ALLOWED, PDU_COLUMN_REPORT_ALLOWED);
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_STATUS, PDU_COLUMN_RETRIEVE_STATUS);
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.STATUS, PDU_COLUMN_STATUS);
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP = new SparseArray<String>();
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_CLASS, Mms.CONTENT_CLASS);
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_REPORT, Mms.DELIVERY_REPORT);
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_TYPE, Mms.MESSAGE_TYPE);
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MMS_VERSION, Mms.MMS_VERSION);
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.PRIORITY, Mms.PRIORITY);
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_REPORT, Mms.READ_REPORT);
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_STATUS, Mms.READ_STATUS);
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.REPORT_ALLOWED, Mms.REPORT_ALLOWED);
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_STATUS, Mms.RETRIEVE_STATUS);
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OCTET_COLUMN_NAME_MAP.put(PduHeaders.STATUS, Mms.STATUS);
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Long field code -> column index/name map.
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_INDEX_MAP = new SparseIntArray();
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DATE, PDU_COLUMN_DATE);
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_TIME, PDU_COLUMN_DELIVERY_TIME);
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_INDEX_MAP.put(PduHeaders.EXPIRY, PDU_COLUMN_EXPIRY);
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_SIZE, PDU_COLUMN_MESSAGE_SIZE);
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_NAME_MAP = new SparseArray<String>();
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_NAME_MAP.put(PduHeaders.DATE, Mms.DATE);
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_TIME, Mms.DELIVERY_TIME);
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_NAME_MAP.put(PduHeaders.EXPIRY, Mms.EXPIRY);
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LONG_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_SIZE, Mms.MESSAGE_SIZE);
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PDU_CACHE_INSTANCE = PduCache.getInstance();
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private final Context mContext;
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private final ContentResolver mContentResolver;
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private PduPersister(final Context context) {
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContext = context;
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContentResolver = context.getContentResolver();
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /** Get(or create if not exist) an instance of PduPersister */
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static PduPersister getPduPersister(final Context context) {
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if ((sPersister == null) || !context.equals(sPersister.mContext)) {
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sPersister = new PduPersister(context);
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LOCAL_LOGV) {
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.v(TAG, "PduPersister getPduPersister");
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return sPersister;
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void setEncodedStringValueToHeaders(
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Cursor c, final int columnIndex,
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduHeaders headers, final int mapColumn) {
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String s = c.getString(columnIndex);
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if ((s != null) && (s.length() > 0)) {
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int charsetColumnIndex = CHARSET_COLUMN_INDEX_MAP.get(mapColumn);
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int charset = c.getInt(charsetColumnIndex);
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final EncodedStringValue value = new EncodedStringValue(
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    charset, getBytes(s));
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            headers.setEncodedStringValue(value, mapColumn);
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void setTextStringToHeaders(
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Cursor c, final int columnIndex,
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduHeaders headers, final int mapColumn) {
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String s = c.getString(columnIndex);
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (s != null) {
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            headers.setTextString(getBytes(s), mapColumn);
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void setOctetToHeaders(
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Cursor c, final int columnIndex,
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduHeaders headers, final int mapColumn) throws InvalidHeaderValueException {
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!c.isNull(columnIndex)) {
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int b = c.getInt(columnIndex);
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            headers.setOctet(b, mapColumn);
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void setLongToHeaders(
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Cursor c, final int columnIndex,
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduHeaders headers, final int mapColumn) {
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!c.isNull(columnIndex)) {
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long l = c.getLong(columnIndex);
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            headers.setLongInteger(l, mapColumn);
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private Integer getIntegerFromPartColumn(final Cursor c, final int columnIndex) {
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!c.isNull(columnIndex)) {
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return c.getInt(columnIndex);
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private byte[] getByteArrayFromPartColumn(final Cursor c, final int columnIndex) {
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!c.isNull(columnIndex)) {
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return getBytes(c.getString(columnIndex));
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private PduPart[] loadParts(final long msgId) throws MmsException {
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Cursor c = SqliteWrapper.query(mContext, mContentResolver,
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Uri.parse("content://mms/" + msgId + "/part"),
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PART_PROJECTION, null, null, null);
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PduPart[] parts = null;
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if ((c == null) || (c.getCount() == 0)) {
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (LOCAL_LOGV) {
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "loadParts(" + msgId + "): no part to load.");
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return null;
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int partCount = c.getCount();
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int partIdx = 0;
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            parts = new PduPart[partCount];
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            while (c.moveToNext()) {
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final PduPart part = new PduPart();
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Integer charset = getIntegerFromPartColumn(
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_CHARSET);
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (charset != null) {
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setCharset(charset);
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] contentDisposition = getByteArrayFromPartColumn(
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_CONTENT_DISPOSITION);
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (contentDisposition != null) {
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setContentDisposition(contentDisposition);
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] contentId = getByteArrayFromPartColumn(
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_CONTENT_ID);
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (contentId != null) {
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setContentId(contentId);
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] contentLocation = getByteArrayFromPartColumn(
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_CONTENT_LOCATION);
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (contentLocation != null) {
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setContentLocation(contentLocation);
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] contentType = getByteArrayFromPartColumn(
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_CONTENT_TYPE);
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (contentType != null) {
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setContentType(contentType);
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    throw new MmsException("Content-Type must be set.");
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] fileName = getByteArrayFromPartColumn(
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_FILENAME);
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (fileName != null) {
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setFilename(fileName);
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final byte[] name = getByteArrayFromPartColumn(
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        c, PART_COLUMN_NAME);
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (name != null) {
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setName(name);
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Construct a Uri for this part.
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final long partId = c.getLong(PART_COLUMN_ID);
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Uri partURI = Uri.parse("content://mms/part/" + partId);
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                part.setDataUri(partURI);
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // For images/audio/video, we won't keep their data in Part
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // because their renderer accept Uri as source.
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String type = toIsoString(contentType);
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!ContentType.isImageType(type)
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        && !ContentType.isAudioType(type)
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        && !ContentType.isVideoType(type)) {
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    InputStream is = null;
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Store simple string values directly in the database instead of an
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // external file.  This makes the text searchable and retrieval slightly
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // faster.
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type)
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            || ContentType.TEXT_HTML.equals(type)) {
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final String text = c.getString(PART_COLUMN_TEXT);
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final byte[] blob = new EncodedStringValue(
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                charset != null ? charset : CharacterSets.DEFAULT_CHARSET,
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                text != null ? text : "")
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                .getTextString();
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        baos.write(blob, 0, blob.length);
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        try {
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            is = mContentResolver.openInputStream(partURI);
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final byte[] buffer = new byte[256];
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            int len = is.read(buffer);
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            while (len >= 0) {
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                baos.write(buffer, 0, len);
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                len = is.read(buffer);
471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        } catch (final IOException e) {
473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            Log.e(TAG, "Failed to load part data", e);
474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            c.close();
475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            throw new MmsException(e);
476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        } finally {
477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (is != null) {
478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                try {
479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    is.close();
480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                } catch (final IOException e) {
481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    Log.e(TAG, "Failed to close stream", e);
482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                } // Ignore
483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setData(baos.toByteArray());
487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                parts[partIdx++] = part;
489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (c != null) {
492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                c.close();
493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return parts;
497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void loadAddress(final long msgId, final PduHeaders headers) {
500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Cursor c = SqliteWrapper.query(mContext, mContentResolver,
501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Uri.parse("content://mms/" + msgId + "/addr"),
502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new String[]{Addr.ADDRESS, Addr.CHARSET, Addr.TYPE},
503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                null, null, null);
504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (c != null) {
506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                while (c.moveToNext()) {
508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final String addr = c.getString(0);
509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (!TextUtils.isEmpty(addr)) {
510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final int addrType = c.getInt(2);
511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        switch (addrType) {
512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            case PduHeaders.FROM:
513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                headers.setEncodedStringValue(
514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                        addrType);
516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                break;
517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            case PduHeaders.TO:
518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            case PduHeaders.CC:
519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            case PduHeaders.BCC:
520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                headers.appendEncodedStringValue(
521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
522d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                        addrType);
523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                break;
524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            default:
525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                Log.e(TAG, "Unknown address type: " + addrType);
526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                break;
527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
529d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
530d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } finally {
531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                c.close();
532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Load a PDU from a given cursor
538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
539d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param c The cursor
540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return A parsed PDU from the database row
541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public GenericPdu load(final Cursor c) throws MmsException {
543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PduHeaders headers = new PduHeaders();
544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long msgId = c.getLong(PDU_COLUMN_ID);
545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Fill in the headers from the PDU columns
546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        loadHeadersFromCursor(c, headers);
547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Load address information of the MM.
548d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        loadAddress(msgId, headers);
549d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Load parts for the PDU body
550d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
551d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PduBody body = loadBody(msgId, msgType);
552d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return createPdu(msgType, headers, body);
553d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
554d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
555d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Load a PDU from storage by given Uri.
557d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
558d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param uri            The Uri of the PDU to be loaded.
559d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return A generic PDU object, it may be cast to dedicated PDU.
560d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws MmsException Failed to load some fields of a PDU.
561d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
562d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public GenericPdu load(final Uri uri) throws MmsException {
563d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        GenericPdu pdu = null;
564d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PduCacheEntry cacheEntry = null;
565d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int msgBox = 0;
566d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long threadId = -1;
567d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
568d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (PDU_CACHE_INSTANCE) {
569d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
570d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LOCAL_LOGV) {
571d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "load: " + uri + " blocked by isUpdating()");
572d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
573d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    try {
574d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        PDU_CACHE_INSTANCE.wait();
575d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } catch (final InterruptedException e) {
576d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Log.e(TAG, "load: ", e);
577d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
578d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
579d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
580d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Check if the pdu is already loaded
581d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cacheEntry = PDU_CACHE_INSTANCE.get(uri);
582d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (cacheEntry != null) {
583d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return cacheEntry.getPdu();
584d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
585d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
586d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Tell the cache to indicate to other callers that this item
587d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // is currently being updated.
588d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.setUpdating(uri, true);
589d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
590d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
591d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
592d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PDU_PROJECTION, null, null, null);
593d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduHeaders headers = new PduHeaders();
594d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long msgId = ContentUris.parseId(uri);
595d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
596d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            try {
597d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
598d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return null;  // MMS not found
599d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
600d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
601d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
602d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                //threadId = c.getLong(PDU_COLUMN_THREAD_ID);
603d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                loadHeadersFromCursor(c, headers);
604d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } finally {
605d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (c != null) {
606d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    c.close();
607d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
608d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
609d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
610d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Check whether 'msgId' has been assigned a valid value.
611d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (msgId == -1L) {
612d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                throw new MmsException("Error! ID of the message: -1.");
613d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
614d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
615d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Load address information of the MM.
616d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            loadAddress(msgId, headers);
617d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
618d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
619d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduBody body = loadBody(msgId, msgType);
620d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            pdu = createPdu(msgType, headers, body);
621d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
622d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (PDU_CACHE_INSTANCE) {
623d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (pdu != null) {
624d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Assert.isNull(PDU_CACHE_INSTANCE.get(uri), "Pdu exists for " + uri);
625d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Update the cache entry with the real info
626d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
627d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PDU_CACHE_INSTANCE.put(uri, cacheEntry);
628d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
629d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.setUpdating(uri, false);
630d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead
631d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
632d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
633d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return pdu;
634d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
635d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
636d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void loadHeadersFromCursor(final Cursor c, final PduHeaders headers)
637d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws InvalidHeaderValueException {
638d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = ENCODED_STRING_COLUMN_INDEX_MAP.size(); --i >= 0; ) {
639d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setEncodedStringValueToHeaders(
640d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    c, ENCODED_STRING_COLUMN_INDEX_MAP.valueAt(i), headers,
641d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ENCODED_STRING_COLUMN_INDEX_MAP.keyAt(i));
642d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
643d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = TEXT_STRING_COLUMN_INDEX_MAP.size(); --i >= 0; ) {
644d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setTextStringToHeaders(
645d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    c, TEXT_STRING_COLUMN_INDEX_MAP.valueAt(i), headers,
646d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    TEXT_STRING_COLUMN_INDEX_MAP.keyAt(i));
647d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
648d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = OCTET_COLUMN_INDEX_MAP.size(); --i >= 0; ) {
649d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setOctetToHeaders(
650d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    c, OCTET_COLUMN_INDEX_MAP.valueAt(i), headers,
651d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    OCTET_COLUMN_INDEX_MAP.keyAt(i));
652d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
653d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = LONG_COLUMN_INDEX_MAP.size(); --i >= 0; ) {
654d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setLongToHeaders(
655d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    c, LONG_COLUMN_INDEX_MAP.valueAt(i), headers,
656d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LONG_COLUMN_INDEX_MAP.keyAt(i));
657d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
658d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
659d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
660d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private GenericPdu createPdu(final int msgType, final PduHeaders headers, final PduBody body)
661d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws MmsException {
662d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        switch (msgType) {
663d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
664d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new NotificationInd(headers);
665d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
666d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new DeliveryInd(headers);
667d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
668d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new ReadOrigInd(headers);
669d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
670d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new RetrieveConf(headers, body);
671d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
672d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new SendReq(headers, body);
673d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
674d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new AcknowledgeInd(headers);
675d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
676d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new NotifyRespInd(headers);
677d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
678d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return new ReadRecInd(headers);
679d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
680d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_FORWARD_REQ:
681d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_FORWARD_CONF:
682d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ:
683d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF:
684d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ:
685d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF:
686d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ:
687d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF:
688d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ:
689d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF:
690d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_MBOX_DESCR:
691d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_DELETE_REQ:
692d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_DELETE_CONF:
693d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_CANCEL_REQ:
694d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case PduHeaders.MESSAGE_TYPE_CANCEL_CONF:
695d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                throw new MmsException(
696d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        "Unsupported PDU type: " + Integer.toHexString(msgType));
697d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
698d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            default:
699d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                throw new MmsException(
700d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        "Unrecognized PDU type: " + Integer.toHexString(msgType));
701d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
702d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
703d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
704d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private PduBody loadBody(final long msgId, final int msgType) throws MmsException {
705d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PduBody body = new PduBody();
706d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
707d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // For PDU which type is M_retrieve.conf or Send.req, we should
708d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // load multiparts and put them into the body of the PDU.
709d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
710d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
711d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PduPart[] parts = loadParts(msgId);
712d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (parts != null) {
713d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int partsNum = parts.length;
714d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (int i = 0; i < partsNum; i++) {
715d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    body.addPart(parts[i]);
716d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
717d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
718d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
719d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
720d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return body;
721d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
722d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
723d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void persistAddress(
724d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long msgId, final int type, final EncodedStringValue[] array) {
725d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues(3);
726d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
727d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final EncodedStringValue addr : array) {
728d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.clear(); // Clear all values first.
729d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Addr.ADDRESS, toIsoString(addr.getTextString()));
730d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Addr.CHARSET, addr.getCharacterSet());
731d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Addr.TYPE, type);
732d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
733d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Uri uri = Uri.parse("content://mms/" + msgId + "/addr");
734d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            SqliteWrapper.insert(mContext, mContentResolver, uri, values);
735d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
736d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
737d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
738d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String getPartContentType(final PduPart part) {
739d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return part.getContentType() == null ? null : toIsoString(part.getContentType());
740d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
741d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
742d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void getValues(final PduPart part, final ContentValues values) {
743d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte[] bytes = part.getFilename();
744d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (bytes != null) {
745d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.FILENAME, new String(bytes));
746d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
747d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
748d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bytes = part.getName();
749d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (bytes != null) {
750d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.NAME, new String(bytes));
751d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
752d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
753d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bytes = part.getContentDisposition();
754d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (bytes != null) {
755d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CONTENT_DISPOSITION, toIsoString(bytes));
756d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
757d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
758d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bytes = part.getContentId();
759d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (bytes != null) {
760d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CONTENT_ID, toIsoString(bytes));
761d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
762d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
763d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bytes = part.getContentLocation();
764d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (bytes != null) {
765d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CONTENT_LOCATION, toIsoString(bytes));
766d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
767d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
768d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
769d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Uri persistPart(final PduPart part, final long msgId,
770d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Map<Uri, InputStream> preOpenedFiles) throws MmsException {
771d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = Uri.parse("content://mms/" + msgId + "/part");
772d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues(8);
773d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
774d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int charset = part.getCharset();
775d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (charset != 0) {
776d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CHARSET, charset);
777d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
778d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
779d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String contentType = getPartContentType(part);
780d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final byte[] data = part.getData();
781d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
782d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LOCAL_LOGV) {
783d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.v(TAG, "PduPersister.persistPart part: " + uri + " contentType: " +
784d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    contentType);
785d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
786d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
787d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (contentType != null) {
788d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // There is no "image/jpg" in Android (and it's an invalid mimetype).
789d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Change it to "image/jpeg"
790d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (ContentType.IMAGE_JPG.equals(contentType)) {
791d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentType = ContentType.IMAGE_JPEG;
792d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
793d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
794d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // On somes phones, a vcard comes in as text/plain instead of text/v-card.
795d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Fix it if necessary.
796d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (ContentType.TEXT_PLAIN.equals(contentType) && data != null) {
797d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // There might be a more efficient way to just check the beginning of the string
798d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // without encoding the whole thing, but we're concerned that with various
799d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // characters sets, just comparing the byte data to BEGIN_VCARD would not be
800d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // reliable.
801d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String encodedDataString = new EncodedStringValue(charset, data).getString();
802d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (encodedDataString != null && encodedDataString.startsWith(BEGIN_VCARD)) {
803d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    contentType = ContentType.TEXT_VCARD;
804d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    part.setContentType(contentType.getBytes());
805d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
806d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.d(TAG, "PduPersister.persistPart part: " + uri + " contentType: " +
807d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                contentType + " changing to vcard");
808d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
809d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
810d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
811d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
812d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CONTENT_TYPE, contentType);
813d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // To ensure the SMIL part is always the first part.
814d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (ContentType.APP_SMIL.equals(contentType)) {
815d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(Part.SEQ, -1);
816d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
817d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
818d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException("MIME type of the part must be set.");
819d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
820d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
821d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        getValues(part, values);
822d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
823d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Uri res = null;
824d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
825d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
826d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
827d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (IllegalStateException e) {
828d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Currently the MMS provider throws an IllegalStateException when it's out of space
829d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.e(TAG, "SqliteWrapper.insert threw: ", e);
830d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
831d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
832d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (res == null) {
833d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException("Failed to persist part, return null.");
834d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
835d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
836d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        persistData(part, res, contentType, preOpenedFiles);
837d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // After successfully store the data, we should update
838d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // the dataUri of the part.
839d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        part.setDataUri(res);
840d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
841d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return res;
842d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
843d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
844d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
845d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Save data of the part into storage. The source data may be given
846d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * by a byte[] or a Uri. If it's a byte[], directly save it
847d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * into storage, otherwise load source data from the dataUri and then
848d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * save it. If the data is an image, we may scale down it according
849d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * to user preference.
850d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
851d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param part           The PDU part which contains data to be saved.
852d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param uri            The URI of the part.
853d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param contentType    The MIME type of the part.
854d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
855d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws MmsException Cannot find source data or error occurred
856d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *                      while saving the data.
857d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
858d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void persistData(final PduPart part, final Uri uri,
859d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String contentType, final Map<Uri, InputStream> preOpenedFiles)
860d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws MmsException {
861d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        OutputStream os = null;
862d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        InputStream is = null;
863d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DrmConvertSession drmConvertSession = null;
864d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Uri dataUri = null;
865d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String path = null;
866d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
867d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
868d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final byte[] data = part.getData();
869d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int charset = part.getCharset();
870d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (ContentType.TEXT_PLAIN.equals(contentType)
871d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    || ContentType.APP_SMIL.equals(contentType)
872d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    || ContentType.TEXT_HTML.equals(contentType)) {
873d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Some phone could send MMS with a text part having empty data
874d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Let's just skip those parts.
875d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // EncodedStringValue() throws NPE if data is empty
876d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (data != null) {
877d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final ContentValues cv = new ContentValues();
878d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    cv.put(Mms.Part.TEXT, new EncodedStringValue(charset, data).getString());
879d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (mContentResolver.update(uri, cv, null, null) != 1) {
880d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        throw new MmsException("unable to update " + uri.toString());
881d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
882d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
883d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
884d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
885d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (isDrm) {
886d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (uri != null) {
887d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        try {
888d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            path = convertUriToPath(mContext, uri);
889d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (LOCAL_LOGV) {
890d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                LogUtil.v(TAG, "drm uri: " + uri + " path: " + path);
891d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
892d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final File f = new File(path);
893d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final long len = f.length();
894d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (LOCAL_LOGV) {
895d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                LogUtil.v(TAG, "drm path: " + path + " len: " + len);
896d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
897d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (len > 0) {
898d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                // we're not going to re-persist and re-encrypt an already
899d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                // converted drm file
900d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                return;
901d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
902d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        } catch (final Exception e) {
903d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
904d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
905d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
906d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // We haven't converted the file yet, start the conversion
907d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    drmConvertSession = DrmConvertSession.open(mContext, contentType);
908d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (drmConvertSession == null) {
909d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        throw new MmsException("Mimetype " + contentType +
910d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                " can not be converted.");
911d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
912d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
913d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // uri can look like:
914d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // content://mms/part/98
915d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                os = mContentResolver.openOutputStream(uri);
916d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (os == null) {
917d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    throw new MmsException("Failed to create output stream on " + uri);
918d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
919d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (data == null) {
920d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    dataUri = part.getDataUri();
921d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if ((dataUri == null) || (dataUri == uri)) {
922d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Log.w(TAG, "Can't find data for this part.");
923d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        return;
924d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
925d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // dataUri can look like:
926d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // content://com.google.android.gallery3d.provider/picasa/item/5720646660183715
927d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (preOpenedFiles != null && preOpenedFiles.containsKey(dataUri)) {
928d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        is = preOpenedFiles.get(dataUri);
929d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
930d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (is == null) {
931d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        is = mContentResolver.openInputStream(dataUri);
932d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
933d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (is == null) {
934d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        throw new MmsException("Failed to create input stream on " + dataUri);
935d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
936d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LOCAL_LOGV) {
937d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "Saving data to: " + uri);
938d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
939d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
940d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final byte[] buffer = new byte[8192];
941d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    for (int len = 0; (len = is.read(buffer)) != -1; ) {
942d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (!isDrm) {
943d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            os.write(buffer, 0, len);
944d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        } else {
945d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final byte[] convertedData = drmConvertSession.convert(buffer, len);
946d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (convertedData != null) {
947d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                os.write(convertedData, 0, convertedData.length);
948d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            } else {
949d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                throw new MmsException("Error converting drm data.");
950d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
951d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
952d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
953d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
954d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LOCAL_LOGV) {
955d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "Saving data to: " + uri);
956d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
957d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (!isDrm) {
958d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        os.write(data);
959d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
960d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        dataUri = uri;
961d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final byte[] convertedData = drmConvertSession.convert(data, data.length);
962d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (convertedData != null) {
963d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            os.write(convertedData, 0, convertedData.length);
964d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        } else {
965d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            throw new MmsException("Error converting drm data.");
966d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
967d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
968d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
969d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
970d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final SQLiteException e) {
971d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Log.e(TAG, "Failed with SQLiteException.", e);
972d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException(e);
973d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final FileNotFoundException e) {
974d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Log.e(TAG, "Failed to open Input/Output stream.", e);
975d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException(e);
976d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final IOException e) {
977d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Log.e(TAG, "Failed to read/write data.", e);
978d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException(e);
979d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
980d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (os != null) {
981d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
982d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    os.close();
983d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final IOException e) {
984d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Log.e(TAG, "IOException while closing: " + os, e);
985d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } // Ignore
986d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
987d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (is != null) {
988d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
989d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    is.close();
990d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final IOException e) {
991d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Log.e(TAG, "IOException while closing: " + is, e);
992d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } // Ignore
993d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
994d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (drmConvertSession != null) {
995d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                drmConvertSession.close(path);
996d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
997d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Reset the permissions on the encrypted part file so everyone has only read
998d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // permission.
999d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final File f = new File(path);
1000d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ContentValues values = new ContentValues(0);
1001d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                SqliteWrapper.update(mContext, mContentResolver,
1002d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Uri.parse("content://mms/resetFilePerm/" + f.getName()),
1003d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        values, null, null);
1004d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1005d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1006d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1007d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1008d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1009d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * This method expects uri in the following format
1010d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *     content://media/<table_name>/<row_index> (or)
1011d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *     file://sdcard/test.mp4
1012d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *     http://test.com/test.mp4
1013d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1014d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Here <table_name> shall be "video" or "audio" or "images"
1015d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * <row_index> the index of the content in given table
1016d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1017d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String convertUriToPath(final Context context, final Uri uri) {
1018d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String path = null;
1019d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (null != uri) {
1020d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String scheme = uri.getScheme();
1021d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (null == scheme || scheme.equals("") ||
1022d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    scheme.equals(ContentResolver.SCHEME_FILE)) {
1023d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                path = uri.getPath();
1024d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1025d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else if (scheme.equals("http")) {
1026d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                path = uri.toString();
1027d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1028d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
1029d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String[] projection = new String[] {MediaStore.MediaColumns.DATA};
1030d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Cursor cursor = null;
1031d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
1032d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    cursor = context.getContentResolver().query(uri, projection, null,
1033d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            null, null);
1034d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
1035d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        throw new IllegalArgumentException("Given Uri could not be found" +
1036d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                " in media store");
1037d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1038d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int pathIndex =
1039d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
1040d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    path = cursor.getString(pathIndex);
1041d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final SQLiteException e) {
1042d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    throw new IllegalArgumentException("Given Uri is not formatted in a way " +
1043d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            "so that it can be found in media store.");
1044d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } finally {
1045d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (null != cursor) {
1046d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        cursor.close();
1047d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1048d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1049d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
1050d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                throw new IllegalArgumentException("Given Uri scheme is not supported");
1051d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1052d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1053d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return path;
1054d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1055d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1056d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateAddress(
1057d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long msgId, final int type, final EncodedStringValue[] array) {
1058d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Delete old address information and then insert new ones.
1059d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.delete(mContext, mContentResolver,
1060d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Uri.parse("content://mms/" + msgId + "/addr"),
1061d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Addr.TYPE + "=" + type, null);
1062d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1063d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        persistAddress(msgId, type, array);
1064d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1065d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1066d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1067d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update headers of a SendReq.
1068d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1069d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param uri The PDU which need to be updated.
1070d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param pdu New headers.
1071d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws MmsException Bad URI or updating failed.
1072d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1073d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void updateHeaders(final Uri uri, final SendReq sendReq) {
1074d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (PDU_CACHE_INSTANCE) {
1075d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If the cache item is getting updated, wait until it's done updating before
1076d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // purging it.
1077d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1078d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (LOCAL_LOGV) {
1079d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "updateHeaders: " + uri + " blocked by isUpdating()");
1080d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1081d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
1082d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PDU_CACHE_INSTANCE.wait();
1083d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final InterruptedException e) {
1084d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Log.e(TAG, "updateHeaders: ", e);
1085d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1086d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1087d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1088d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PDU_CACHE_INSTANCE.purge(uri);
1089d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1090d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues(10);
1091d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final byte[] contentType = sendReq.getContentType();
1092d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (contentType != null) {
1093d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.CONTENT_TYPE, toIsoString(contentType));
1094d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1095d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1096d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long date = sendReq.getDate();
1097d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (date != -1) {
1098d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.DATE, date);
1099d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int deliveryReport = sendReq.getDeliveryReport();
1102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (deliveryReport != 0) {
1103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.DELIVERY_REPORT, deliveryReport);
1104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long expiry = sendReq.getExpiry();
1107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (expiry != -1) {
1108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.EXPIRY, expiry);
1109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final byte[] msgClass = sendReq.getMessageClass();
1112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (msgClass != null) {
1113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.MESSAGE_CLASS, toIsoString(msgClass));
1114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int priority = sendReq.getPriority();
1117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (priority != 0) {
1118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.PRIORITY, priority);
1119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int readReport = sendReq.getReadReport();
1122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (readReport != 0) {
1123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.READ_REPORT, readReport);
1124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final byte[] transId = sendReq.getTransactionId();
1127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (transId != null) {
1128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.TRANSACTION_ID, toIsoString(transId));
1129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final EncodedStringValue subject = sendReq.getSubject();
1132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (subject != null) {
1133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.SUBJECT, toIsoString(subject.getTextString()));
1134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet());
1135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
1136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.SUBJECT, "");
1137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long messageSize = sendReq.getMessageSize();
1140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (messageSize > 0) {
1141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.MESSAGE_SIZE, messageSize);
1142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PduHeaders headers = sendReq.getPduHeaders();
1145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final HashSet<String> recipients = new HashSet<String>();
1146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final int addrType : ADDRESS_FIELDS) {
1147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            EncodedStringValue[] array = null;
1148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (addrType == PduHeaders.FROM) {
1149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final EncodedStringValue v = headers.getEncodedStringValue(addrType);
1150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (v != null) {
1151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    array = new EncodedStringValue[1];
1152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    array[0] = v;
1153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
1155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                array = headers.getEncodedStringValues(addrType);
1156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (array != null) {
1159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final long msgId = ContentUris.parseId(uri);
1160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                updateAddress(msgId, addrType, array);
1161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (addrType == PduHeaders.TO) {
1162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    for (final EncodedStringValue v : array) {
1163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (v != null) {
1164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            recipients.add(v.getString());
1165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
1166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!recipients.isEmpty()) {
1171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long threadId = MmsSmsUtils.Threads.getOrCreateThreadId(mContext, recipients);
1172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.THREAD_ID, threadId);
1173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updatePart(final Uri uri, final PduPart part,
1180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Map<Uri, InputStream> preOpenedFiles)
1181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws MmsException {
1182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues(7);
1183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int charset = part.getCharset();
1185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (charset != 0) {
1186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CHARSET, charset);
1187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String contentType = null;
1190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (part.getContentType() != null) {
1191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            contentType = toIsoString(part.getContentType());
1192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Part.CONTENT_TYPE, contentType);
1193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
1194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException("MIME type of the part must be set.");
1195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        getValues(part, values);
1198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Only update the data when:
1202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // 1. New binary data supplied or
1203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // 2. The Uri of the part is different from the current one.
1204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if ((part.getData() != null)
1205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || (uri != part.getDataUri())) {
1206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            persistData(part, uri, contentType, preOpenedFiles);
1207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Update all parts of a PDU.
1212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param uri            The PDU which need to be updated.
1214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param body           New message body of the PDU.
1215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
1216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws MmsException Bad URI or updating failed.
1217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void updateParts(final Uri uri, final PduBody body,
1219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Map<Uri, InputStream> preOpenedFiles)
1220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws MmsException {
1221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
1222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            PduCacheEntry cacheEntry;
1223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (PDU_CACHE_INSTANCE) {
1224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LOCAL_LOGV) {
1226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "updateParts: " + uri + " blocked by isUpdating()");
1227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    try {
1229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        PDU_CACHE_INSTANCE.wait();
1230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } catch (final InterruptedException e) {
1231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Log.e(TAG, "updateParts: ", e);
1232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
1234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (cacheEntry != null) {
1235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
1236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Tell the cache to indicate to other callers that this item
1239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // is currently being updated.
1240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.setUpdating(uri, true);
1241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
1244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ArrayMap<Uri, PduPart> toBeUpdated = new ArrayMap<Uri, PduPart>();
1245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int partsNum = body.getPartsNum();
1247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final StringBuilder filter = new StringBuilder().append('(');
1248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (int i = 0; i < partsNum; i++) {
1249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final PduPart part = body.getPart(i);
1250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final Uri partUri = part.getDataUri();
1251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
1252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    toBeCreated.add(part);
1253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
1254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    toBeUpdated.put(partUri, part);
1255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Don't use 'i > 0' to determine whether we should append
1257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // 'AND' since 'i = 0' may be skipped in another branch.
1258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (filter.length() > 1) {
1259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        filter.append(" AND ");
1260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    filter.append(Part._ID);
1263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    filter.append("!=");
1264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
1265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            filter.append(')');
1268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long msgId = ContentUris.parseId(uri);
1270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Remove the parts which doesn't exist anymore.
1272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            SqliteWrapper.delete(mContext, mContentResolver,
1273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
1274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    filter.length() > 2 ? filter.toString() : null, null);
1275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Create new parts which didn't exist before.
1277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final PduPart part : toBeCreated) {
1278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                persistPart(part, msgId, preOpenedFiles);
1279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Update the modified parts.
1282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
1283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                updatePart(e.getKey(), e.getValue(), preOpenedFiles);
1284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
1286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            synchronized (PDU_CACHE_INSTANCE) {
1287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.setUpdating(uri, false);
1288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PDU_CACHE_INSTANCE.notifyAll();
1289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Persist a PDU object to specific location in the storage.
1295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param pdu             The PDU object to be stored.
1297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param uri             Where to store the given PDU object.
1298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param subId           Subscription id associated with this message.
1299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param subPhoneNumber TODO
1300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param preOpenedFiles  if not null, a map of preopened InputStreams for the parts.
1301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return A Uri which can be used to access the stored PDU.
1302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Uri persist(final GenericPdu pdu, final Uri uri, final int subId,
1304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String subPhoneNumber, final Map<Uri, InputStream> preOpenedFiles)
1305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throws MmsException {
1306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (uri == null) {
1307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException("Uri may not be null.");
1308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        long msgId = -1;
1310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
1311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            msgId = ContentUris.parseId(uri);
1312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final NumberFormatException e) {
1313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // the uri ends with "inbox" or something else like that
1314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean existingUri = msgId != -1;
1316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
1318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException(
1319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    "Bad destination, must be one of "
1320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/inbox, content://mms/sent, "
1321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/drafts, content://mms/outbox, "
1322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/temp."
1323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            );
1324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        synchronized (PDU_CACHE_INSTANCE) {
1326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If the cache item is getting updated, wait until it's done updating before
1327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // purging it.
1328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (LOCAL_LOGV) {
1330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "persist: " + uri + " blocked by isUpdating()");
1331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                try {
1333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    PDU_CACHE_INSTANCE.wait();
1334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } catch (final InterruptedException e) {
1335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Log.e(TAG, "persist1: ", e);
1336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PDU_CACHE_INSTANCE.purge(uri);
1340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final PduHeaders header = pdu.getPduHeaders();
1342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        PduBody body = null;
1343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ContentValues values = new ContentValues();
1344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Mark new messages as seen in the telephony database so that we don't have to
1346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // do a global "set all messages as seen" since that occasionally seems to be
1347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // problematic (i.e. very slow).  See bug 18189471.
1348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(Mms.SEEN, 1);
1349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        //Set<Entry<Integer, String>> set;
1351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = ENCODED_STRING_COLUMN_NAME_MAP.size(); --i >= 0; ) {
1353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int field = ENCODED_STRING_COLUMN_NAME_MAP.keyAt(i);
1354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final EncodedStringValue encodedString = header.getEncodedStringValue(field);
1355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (encodedString != null) {
1356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field);
1357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(ENCODED_STRING_COLUMN_NAME_MAP.valueAt(i),
1358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        toIsoString(encodedString.getTextString()));
1359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(charsetColumn, encodedString.getCharacterSet());
1360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = TEXT_STRING_COLUMN_NAME_MAP.size(); --i >= 0; ) {
1364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final byte[] text = header.getTextString(TEXT_STRING_COLUMN_NAME_MAP.keyAt(i));
1365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (text != null) {
1366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(TEXT_STRING_COLUMN_NAME_MAP.valueAt(i), toIsoString(text));
1367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = OCTET_COLUMN_NAME_MAP.size(); --i >= 0; ) {
1371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int b = header.getOctet(OCTET_COLUMN_NAME_MAP.keyAt(i));
1372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (b != 0) {
1373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(OCTET_COLUMN_NAME_MAP.valueAt(i), b);
1374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = LONG_COLUMN_NAME_MAP.size(); --i >= 0; ) {
1378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final long l = header.getLongInteger(LONG_COLUMN_NAME_MAP.keyAt(i));
1379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (l != -1L) {
1380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values.put(LONG_COLUMN_NAME_MAP.valueAt(i), l);
1381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final SparseArray<EncodedStringValue[]> addressMap =
1385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                new SparseArray<EncodedStringValue[]>(ADDRESS_FIELDS.length);
1386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Save address information.
1387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final int addrType : ADDRESS_FIELDS) {
1388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            EncodedStringValue[] array = null;
1389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (addrType == PduHeaders.FROM) {
1390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final EncodedStringValue v = header.getEncodedStringValue(addrType);
1391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (v != null) {
1392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    array = new EncodedStringValue[1];
1393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    array[0] = v;
1394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
1396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                array = header.getEncodedStringValues(addrType);
1397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            addressMap.put(addrType, array);
1399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final HashSet<String> recipients = new HashSet<String>();
1402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int msgType = pdu.getMessageType();
1403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Here we only allocate thread ID for M-Notification.ind,
1404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // M-Retrieve.conf and M-Send.req.
1405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Some of other PDU types may be allocated a thread ID outside
1406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // this scope.
1407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
1408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
1409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
1410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            switch (msgType) {
1411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
1412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
1413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    loadRecipients(PduHeaders.FROM, recipients, addressMap);
1414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // For received messages (whether group MMS is enabled or not) we want to
1416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // associate this message with the thread composed of all the recipients
1417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // EXCLUDING our own number. This includes the person who sent the
1418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // message (the FROM field above) in addition to the other people the message
1419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // was addressed TO (or CC fields to address group messaging compatibility
1420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // issues with devices that place numbers in this field). Typically our own
1421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // number is in the TO/CC field so we have to remove it in loadRecipients.
1422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    checkAndLoadToCcRecipients(recipients, addressMap, subPhoneNumber);
1423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
1424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case PduHeaders.MESSAGE_TYPE_SEND_REQ:
1425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    loadRecipients(PduHeaders.TO, recipients, addressMap);
1426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
1427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            long threadId = -1L;
1429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!recipients.isEmpty()) {
1430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Given all the recipients associated with this message, find (or create) the
1431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // correct thread.
1432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                threadId = MmsSmsUtils.Threads.getOrCreateThreadId(mContext, recipients);
1433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
1434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.w(TAG, "PduPersister.persist No recipients; persisting PDU to thread: "
1435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + threadId);
1436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.THREAD_ID, threadId);
1438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Save parts first to avoid inconsistent message is loaded
1441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // while saving the parts.
1442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
1443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Figure out if this PDU is a text-only message
1445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean textOnly = true;
1446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Get body if the PDU is a RetrieveConf or SendReq.
1448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (pdu instanceof MultimediaMessagePdu) {
1449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            body = ((MultimediaMessagePdu) pdu).getBody();
1450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Start saving parts if necessary.
1451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (body != null) {
1452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int partsNum = body.getPartsNum();
1453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (LOCAL_LOGV) {
1454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.v(TAG, "PduPersister.persist partsNum: " + partsNum);
1455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (partsNum > 2) {
1457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // For a text-only message there will be two parts: 1-the SMIL, 2-the text.
1458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Down a few lines below we're checking to make sure we've only got SMIL or
1459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // text. We also have to check then we don't have more than two parts.
1460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Otherwise, a slideshow with two text slides would be marked as textOnly.
1461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    textOnly = false;
1462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                for (int i = 0; i < partsNum; i++) {
1464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final PduPart part = body.getPart(i);
1465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    persistPart(part, dummyId, preOpenedFiles);
1466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // If we've got anything besides text/plain or SMIL part, then we've got
1468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // an mms message with some other type of attachment.
1469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final String contentType = getPartContentType(part);
1470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (LOCAL_LOGV) {
1471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "PduPersister.persist part: " + i + " contentType: " +
1472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                contentType);
1473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (contentType != null && !ContentType.APP_SMIL.equals(contentType)
1475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            && !ContentType.TEXT_PLAIN.equals(contentType)) {
1476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        textOnly = false;
1477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
1478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Record whether this mms message is a simple plain text or not. This is a hint for the
1482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // UI.
1483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastJB_MR1()) {
1484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0);
1485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (OsUtil.isAtLeastL_MR1()) {
1488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(Mms.SUBSCRIPTION_ID, subId);
1489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
1490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.equals(ParticipantData.DEFAULT_SELF_SUB_ID, subId);
1491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Uri res = null;
1494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (existingUri) {
1495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            res = uri;
1496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
1497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
1498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
1499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (res == null) {
1500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                throw new MmsException("persist() failed: return null.");
1501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Get the real ID of the PDU and update all parts which were
1503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // saved with the dummy ID.
1504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            msgId = ContentUris.parseId(res);
1505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values = new ContentValues(1);
1508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(Part.MSG_ID, msgId);
1509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.update(mContext, mContentResolver,
1510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Uri.parse("content://mms/" + dummyId + "/part"),
1511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                values, null, null);
1512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We should return the longest URI of the persisted PDU, for
1513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // example, if input URI is "content://mms/inbox" and the _ID of
1514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // persisted PDU is '8', we should return "content://mms/inbox/8"
1515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // instead of "content://mms/8".
1516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // TODO: Should the MmsProvider be responsible for this???
1517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!existingUri) {
1518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            res = Uri.parse(uri + "/" + msgId);
1519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Save address information.
1522d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final int addrType : ADDRESS_FIELDS) {
1523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final EncodedStringValue[] array = addressMap.get(addrType);
1524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (array != null) {
1525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                persistAddress(msgId, addrType, array);
1526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1529d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return res;
1530d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * For a given address type, extract the recipients from the headers.
1534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param addressType     can be PduHeaders.FROM or PduHeaders.TO
1536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param recipients      a HashSet that is loaded with the recipients from the FROM or TO
1537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *                        headers
1538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param addressMap      a HashMap of the addresses from the ADDRESS_FIELDS header
1539d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void loadRecipients(final int addressType, final HashSet<String> recipients,
1541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SparseArray<EncodedStringValue[]> addressMap) {
1542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final EncodedStringValue[] array = addressMap.get(addressType);
1543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (array == null) {
1544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
1545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final EncodedStringValue v : array) {
1547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (v != null) {
1548d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final String number = v.getString();
1549d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!recipients.contains(number)) {
1550d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Only add numbers which aren't already included.
1551d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    recipients.add(number);
1552d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1553d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1554d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1555d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1557d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1558d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * For a given address type, extract the recipients from the headers.
1559d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1560d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param recipients      a HashSet that is loaded with the recipients from the FROM or TO
1561d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *                        headers
1562d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param addressMap      a HashMap of the addresses from the ADDRESS_FIELDS header
1563d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param selfNumber      self phone number
1564d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1565d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void checkAndLoadToCcRecipients(final HashSet<String> recipients,
1566d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final SparseArray<EncodedStringValue[]> addressMap, final String selfNumber) {
1567d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final EncodedStringValue[] arrayTo = addressMap.get(PduHeaders.TO);
1568d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final EncodedStringValue[] arrayCc = addressMap.get(PduHeaders.CC);
1569d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayList<String> numbers = new ArrayList<String>();
1570d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (arrayTo != null) {
1571d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final EncodedStringValue v : arrayTo) {
1572d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (v != null) {
1573d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    numbers.add(v.getString());
1574d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1575d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1576d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1577d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (arrayCc != null) {
1578d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (final EncodedStringValue v : arrayCc) {
1579d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (v != null) {
1580d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    numbers.add(v.getString());
1581d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1582d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1583d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1584d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final String number : numbers) {
1585d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Only add numbers which aren't my own number.
1586d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (TextUtils.isEmpty(selfNumber) || !PhoneNumberUtils.compare(number, selfNumber)) {
1587d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!recipients.contains(number)) {
1588d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Only add numbers which aren't already included.
1589d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    recipients.add(number);
1590d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
1591d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1592d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1593d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1594d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1595d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1596d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Move a PDU object from one location to another.
1597d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
1598d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param from Specify the PDU object to be moved.
1599d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param to   The destination location, should be one of the following:
1600d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *             "content://mms/inbox", "content://mms/sent",
1601d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *             "content://mms/drafts", "content://mms/outbox",
1602d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *             "content://mms/trash".
1603d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return New Uri of the moved PDU.
1604d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @throws MmsException Error occurred while moving the message.
1605d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1606d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Uri move(final Uri from, final Uri to) throws MmsException {
1607d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Check whether the 'msgId' has been assigned a valid value.
1608d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long msgId = ContentUris.parseId(from);
1609d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (msgId == -1L) {
1610d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException("Error! ID of the message: -1.");
1611d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1612d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1613d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Get corresponding int value of destination box.
1614d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Integer msgBox = MESSAGE_BOX_MAP.get(to);
1615d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (msgBox == null) {
1616d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            throw new MmsException(
1617d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    "Bad destination, must be one of "
1618d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/inbox, content://mms/sent, "
1619d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/drafts, content://mms/outbox, "
1620d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + "content://mms/temp."
1621d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            );
1622d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1623d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1624d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ContentValues values = new ContentValues(1);
1625d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        values.put(Mms.MESSAGE_BOX, msgBox);
1626d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.update(mContext, mContentResolver, from, values, null, null);
1627d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return ContentUris.withAppendedId(to, msgId);
1628d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1629d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1630d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1631d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Wrap a byte[] into a String.
1632d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1633d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static String toIsoString(final byte[] bytes) {
1634d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
1635d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
1636d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final UnsupportedEncodingException e) {
1637d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Impossible to reach here!
1638d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1639d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return "";
1640d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1641d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1642d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1643d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1644d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Unpack a given String into a byte[].
1645d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1646d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static byte[] getBytes(final String data) {
1647d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
1648d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
1649d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } catch (final UnsupportedEncodingException e) {
1650d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Impossible to reach here!
1651d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1652d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new byte[0];
1653d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1654d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1655d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1656d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1657d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Remove all objects in the temporary path.
1658d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1659d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void release() {
1660d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri uri = Uri.parse(TEMPORARY_DRM_OBJECT_URI);
1661d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SqliteWrapper.delete(mContext, mContentResolver, uri, null, null);
1662d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1663d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1664d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1665d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Find all messages to be sent or downloaded before certain time.
1666d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1667d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public Cursor getPendingMessages(final long dueTime) {
1668d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon();
1669d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        uriBuilder.appendQueryParameter("protocol", "mms");
1670d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1671d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String selection = PendingMessages.ERROR_TYPE + " < ?"
1672d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                + " AND " + PendingMessages.DUE_TIME + " <= ?";
1673d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1674d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String[] selectionArgs = new String[] {
1675d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                String.valueOf(MmsSms.ERR_TYPE_GENERIC_PERMANENT),
1676d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                String.valueOf(dueTime)
1677d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        };
1678d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1679d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return SqliteWrapper.query(mContext, mContentResolver,
1680d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                uriBuilder.build(), null, selection, selectionArgs,
1681d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                PendingMessages.DUE_TIME);
1682d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1683d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
1684