1526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen/*
2526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * Copyright (C) 2007-2008 Esmertec AG.
3526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * Copyright (C) 2007-2008 The Android Open Source Project
4526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen *
5526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * Licensed under the Apache License, Version 2.0 (the "License");
6526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * you may not use this file except in compliance with the License.
7526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * You may obtain a copy of the License at
8526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen *
9526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen *      http://www.apache.org/licenses/LICENSE-2.0
10526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen *
11526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * Unless required by applicable law or agreed to in writing, software
12526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * distributed under the License is distributed on an "AS IS" BASIS,
13526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * See the License for the specific language governing permissions and
15526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * limitations under the License.
16526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen */
17526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
18526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenpackage com.google.android.mms.pdu;
19526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
20526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.ContentType;
21526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.InvalidHeaderValueException;
22526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.MmsException;
23526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.util.DownloadDrmHelper;
24526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.util.DrmConvertSession;
25526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.util.PduCache;
26526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.util.PduCacheEntry;
27526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.util.SqliteWrapper;
28526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
29526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.content.ContentResolver;
30526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.content.ContentUris;
31526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.content.ContentValues;
32526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.content.Context;
33526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.database.Cursor;
34526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.database.DatabaseUtils;
35526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.database.sqlite.SQLiteException;
36526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.drm.DrmManagerClient;
37526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.net.Uri;
38526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.MediaStore;
39526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony;
40526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.Mms;
41526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.MmsSms;
42526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.Threads;
43526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.Mms.Addr;
44526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.Mms.Part;
45526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.provider.Telephony.MmsSms.PendingMessages;
468c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylorimport android.telephony.SubscriptionManager;
47526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.telephony.PhoneNumberUtils;
48526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.telephony.TelephonyManager;
49526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.text.TextUtils;
50526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport android.util.Log;
51526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
52526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.ByteArrayOutputStream;
53526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.File;
54526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.FileNotFoundException;
55526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.IOException;
56526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.InputStream;
57526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.OutputStream;
58526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.io.UnsupportedEncodingException;
59526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.ArrayList;
60526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.HashMap;
61526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.HashSet;
62526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.Map;
63526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.Set;
64526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport java.util.Map.Entry;
65526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
66526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenimport com.google.android.mms.pdu.EncodedStringValue;
67526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
68526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen/**
69526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen * This class is the high-level manager of PDU storage.
70526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen */
71526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wenpublic class PduPersister {
72526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final String TAG = "PduPersister";
73526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final boolean DEBUG = false;
74526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final boolean LOCAL_LOGV = false;
75526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
76526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final long DUMMY_THREAD_ID = Long.MAX_VALUE;
77526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
78526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
79526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * The uri of temporary drm objects.
80526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
81526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static final String TEMPORARY_DRM_OBJECT_URI =
82526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        "content://mms/" + Long.MAX_VALUE + "/part";
83526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
84526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Indicate that we transiently failed to process a MM.
85526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
86526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static final int PROC_STATUS_TRANSIENT_FAILURE   = 1;
87526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
88526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Indicate that we permanently failed to process a MM.
89526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
90526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static final int PROC_STATUS_PERMANENTLY_FAILURE = 2;
91526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
92526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Indicate that we have successfully processed a MM.
93526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
94526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static final int PROC_STATUS_COMPLETED           = 3;
95526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
96526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static PduPersister sPersister;
97526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final PduCache PDU_CACHE_INSTANCE;
98526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
99526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int[] ADDRESS_FIELDS = new int[] {
100526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders.BCC,
101526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders.CC,
102526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders.FROM,
103526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders.TO
104526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    };
105526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
106526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final String[] PDU_PROJECTION = new String[] {
107526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms._ID,
108526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MESSAGE_BOX,
109526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.THREAD_ID,
110526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.RETRIEVE_TEXT,
111526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.SUBJECT,
112526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.CONTENT_LOCATION,
113526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.CONTENT_TYPE,
114526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MESSAGE_CLASS,
115526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MESSAGE_ID,
116526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.RESPONSE_TEXT,
117526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.TRANSACTION_ID,
118526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.CONTENT_CLASS,
119526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.DELIVERY_REPORT,
120526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MESSAGE_TYPE,
121526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MMS_VERSION,
122526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.PRIORITY,
123526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.READ_REPORT,
124526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.READ_STATUS,
125526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.REPORT_ALLOWED,
126526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.RETRIEVE_STATUS,
127526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.STATUS,
128526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.DATE,
129526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.DELIVERY_TIME,
130526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.EXPIRY,
131526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.MESSAGE_SIZE,
132526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.SUBJECT_CHARSET,
133526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Mms.RETRIEVE_TEXT_CHARSET,
134526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    };
135526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
136526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_ID                    = 0;
137526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MESSAGE_BOX           = 1;
138526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_THREAD_ID             = 2;
139526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_RETRIEVE_TEXT         = 3;
140526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_SUBJECT               = 4;
141526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_CONTENT_LOCATION      = 5;
142526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_CONTENT_TYPE          = 6;
143526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MESSAGE_CLASS         = 7;
144526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MESSAGE_ID            = 8;
145526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_RESPONSE_TEXT         = 9;
146526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_TRANSACTION_ID        = 10;
147526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_CONTENT_CLASS         = 11;
148526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_DELIVERY_REPORT       = 12;
149526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MESSAGE_TYPE          = 13;
150526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MMS_VERSION           = 14;
151526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_PRIORITY              = 15;
152526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_READ_REPORT           = 16;
153526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_READ_STATUS           = 17;
154526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_REPORT_ALLOWED        = 18;
155526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_RETRIEVE_STATUS       = 19;
156526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_STATUS                = 20;
157526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_DATE                  = 21;
158526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_DELIVERY_TIME         = 22;
159526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_EXPIRY                = 23;
160526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_MESSAGE_SIZE          = 24;
161526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_SUBJECT_CHARSET       = 25;
162526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PDU_COLUMN_RETRIEVE_TEXT_CHARSET = 26;
163526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
164526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final String[] PART_PROJECTION = new String[] {
165526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part._ID,
166526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.CHARSET,
167526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.CONTENT_DISPOSITION,
168526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.CONTENT_ID,
169526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.CONTENT_LOCATION,
170526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.CONTENT_TYPE,
171526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.FILENAME,
172526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.NAME,
173526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Part.TEXT
174526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    };
175526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
176526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_ID                  = 0;
177526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_CHARSET             = 1;
178526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_CONTENT_DISPOSITION = 2;
179526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_CONTENT_ID          = 3;
180526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_CONTENT_LOCATION    = 4;
181526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_CONTENT_TYPE        = 5;
182526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_FILENAME            = 6;
183526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_NAME                = 7;
184526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final int PART_COLUMN_TEXT                = 8;
185526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
186526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Uri, Integer> MESSAGE_BOX_MAP;
187526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    // These map are used for convenience in persist() and load().
188526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, Integer> CHARSET_COLUMN_INDEX_MAP;
189526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, Integer> ENCODED_STRING_COLUMN_INDEX_MAP;
190526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, Integer> TEXT_STRING_COLUMN_INDEX_MAP;
191526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, Integer> OCTET_COLUMN_INDEX_MAP;
192526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, Integer> LONG_COLUMN_INDEX_MAP;
193526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, String> CHARSET_COLUMN_NAME_MAP;
194526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, String> ENCODED_STRING_COLUMN_NAME_MAP;
195526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, String> TEXT_STRING_COLUMN_NAME_MAP;
196526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, String> OCTET_COLUMN_NAME_MAP;
197526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static final HashMap<Integer, String> LONG_COLUMN_NAME_MAP;
198526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
199526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    static {
200526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        MESSAGE_BOX_MAP = new HashMap<Uri, Integer>();
201526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        MESSAGE_BOX_MAP.put(Mms.Inbox.CONTENT_URI,  Mms.MESSAGE_BOX_INBOX);
202526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        MESSAGE_BOX_MAP.put(Mms.Sent.CONTENT_URI,   Mms.MESSAGE_BOX_SENT);
203526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        MESSAGE_BOX_MAP.put(Mms.Draft.CONTENT_URI,  Mms.MESSAGE_BOX_DRAFTS);
204526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        MESSAGE_BOX_MAP.put(Mms.Outbox.CONTENT_URI, Mms.MESSAGE_BOX_OUTBOX);
205526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
206526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
207526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT_CHARSET);
208526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT_CHARSET);
209526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
210526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
211526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT_CHARSET);
212526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        CHARSET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT_CHARSET);
213526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
214526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Encoded string field code -> column index/name map.
215526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
216526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_TEXT, PDU_COLUMN_RETRIEVE_TEXT);
217526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_INDEX_MAP.put(PduHeaders.SUBJECT, PDU_COLUMN_SUBJECT);
218526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
219526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
220526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_TEXT, Mms.RETRIEVE_TEXT);
221526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ENCODED_STRING_COLUMN_NAME_MAP.put(PduHeaders.SUBJECT, Mms.SUBJECT);
222526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
223526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Text string field code -> column index/name map.
224526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
225526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_LOCATION, PDU_COLUMN_CONTENT_LOCATION);
226526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_TYPE, PDU_COLUMN_CONTENT_TYPE);
227526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_CLASS, PDU_COLUMN_MESSAGE_CLASS);
228526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_ID, PDU_COLUMN_MESSAGE_ID);
229526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.RESPONSE_TEXT, PDU_COLUMN_RESPONSE_TEXT);
230526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_INDEX_MAP.put(PduHeaders.TRANSACTION_ID, PDU_COLUMN_TRANSACTION_ID);
231526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
232526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP = new HashMap<Integer, String>();
233526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_LOCATION, Mms.CONTENT_LOCATION);
234526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_TYPE, Mms.CONTENT_TYPE);
235526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_CLASS, Mms.MESSAGE_CLASS);
236526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_ID, Mms.MESSAGE_ID);
237526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.RESPONSE_TEXT, Mms.RESPONSE_TEXT);
238526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        TEXT_STRING_COLUMN_NAME_MAP.put(PduHeaders.TRANSACTION_ID, Mms.TRANSACTION_ID);
239526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
240526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Octet field code -> column index/name map.
241526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
242526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.CONTENT_CLASS, PDU_COLUMN_CONTENT_CLASS);
243526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_REPORT, PDU_COLUMN_DELIVERY_REPORT);
244526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_TYPE, PDU_COLUMN_MESSAGE_TYPE);
245526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.MMS_VERSION, PDU_COLUMN_MMS_VERSION);
246526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.PRIORITY, PDU_COLUMN_PRIORITY);
247526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_REPORT, PDU_COLUMN_READ_REPORT);
248526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.READ_STATUS, PDU_COLUMN_READ_STATUS);
249526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.REPORT_ALLOWED, PDU_COLUMN_REPORT_ALLOWED);
250526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.RETRIEVE_STATUS, PDU_COLUMN_RETRIEVE_STATUS);
251526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_INDEX_MAP.put(PduHeaders.STATUS, PDU_COLUMN_STATUS);
252526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
253526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP = new HashMap<Integer, String>();
254526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.CONTENT_CLASS, Mms.CONTENT_CLASS);
255526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_REPORT, Mms.DELIVERY_REPORT);
256526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_TYPE, Mms.MESSAGE_TYPE);
257526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.MMS_VERSION, Mms.MMS_VERSION);
258526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.PRIORITY, Mms.PRIORITY);
259526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_REPORT, Mms.READ_REPORT);
260526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.READ_STATUS, Mms.READ_STATUS);
261526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.REPORT_ALLOWED, Mms.REPORT_ALLOWED);
262526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.RETRIEVE_STATUS, Mms.RETRIEVE_STATUS);
263526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OCTET_COLUMN_NAME_MAP.put(PduHeaders.STATUS, Mms.STATUS);
264526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
265526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Long field code -> column index/name map.
266526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_INDEX_MAP = new HashMap<Integer, Integer>();
267526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DATE, PDU_COLUMN_DATE);
268526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_INDEX_MAP.put(PduHeaders.DELIVERY_TIME, PDU_COLUMN_DELIVERY_TIME);
269526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_INDEX_MAP.put(PduHeaders.EXPIRY, PDU_COLUMN_EXPIRY);
270526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_INDEX_MAP.put(PduHeaders.MESSAGE_SIZE, PDU_COLUMN_MESSAGE_SIZE);
271526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
272526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_NAME_MAP = new HashMap<Integer, String>();
273526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_NAME_MAP.put(PduHeaders.DATE, Mms.DATE);
274526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_NAME_MAP.put(PduHeaders.DELIVERY_TIME, Mms.DELIVERY_TIME);
275526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_NAME_MAP.put(PduHeaders.EXPIRY, Mms.EXPIRY);
276526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        LONG_COLUMN_NAME_MAP.put(PduHeaders.MESSAGE_SIZE, Mms.MESSAGE_SIZE);
277526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
278526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PDU_CACHE_INSTANCE = PduCache.getInstance();
279526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     }
280526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
281526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private final Context mContext;
282526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private final ContentResolver mContentResolver;
283526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private final DrmManagerClient mDrmManagerClient;
284526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private final TelephonyManager mTelephonyManager;
285526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
286526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private PduPersister(Context context) {
287526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        mContext = context;
288526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        mContentResolver = context.getContentResolver();
289526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        mDrmManagerClient = new DrmManagerClient(context);
290526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        mTelephonyManager = (TelephonyManager)context
291526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                .getSystemService(Context.TELEPHONY_SERVICE);
292526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     }
293526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
294526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /** Get(or create if not exist) an instance of PduPersister */
295526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static PduPersister getPduPersister(Context context) {
296526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if ((sPersister == null)) {
297526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            sPersister = new PduPersister(context);
298526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } else if (!context.equals(sPersister.mContext)) {
299526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            sPersister.release();
300526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            sPersister = new PduPersister(context);
301526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
302526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
303526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return sPersister;
304526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
305526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
306526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void setEncodedStringValueToHeaders(
307526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Cursor c, int columnIndex,
308526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders headers, int mapColumn) {
309526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String s = c.getString(columnIndex);
310526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if ((s != null) && (s.length() > 0)) {
311526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int charsetColumnIndex = CHARSET_COLUMN_INDEX_MAP.get(mapColumn);
312526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int charset = c.getInt(charsetColumnIndex);
313526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            EncodedStringValue value = new EncodedStringValue(
314526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    charset, getBytes(s));
315526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            headers.setEncodedStringValue(value, mapColumn);
316526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
317526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
318526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
319526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void setTextStringToHeaders(
320526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Cursor c, int columnIndex,
321526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders headers, int mapColumn) {
322526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String s = c.getString(columnIndex);
323526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (s != null) {
324526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            headers.setTextString(getBytes(s), mapColumn);
325526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
326526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
327526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
328526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void setOctetToHeaders(
329526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Cursor c, int columnIndex,
330526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders headers, int mapColumn) throws InvalidHeaderValueException {
331526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!c.isNull(columnIndex)) {
332526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int b = c.getInt(columnIndex);
333526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            headers.setOctet(b, mapColumn);
334526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
335526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
336526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
337526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void setLongToHeaders(
338526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Cursor c, int columnIndex,
339526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders headers, int mapColumn) {
340526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!c.isNull(columnIndex)) {
341526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long l = c.getLong(columnIndex);
342526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            headers.setLongInteger(l, mapColumn);
343526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
344526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
345526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
346526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private Integer getIntegerFromPartColumn(Cursor c, int columnIndex) {
347526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!c.isNull(columnIndex)) {
348526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return c.getInt(columnIndex);
349526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
350526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return null;
351526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
352526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
353526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private byte[] getByteArrayFromPartColumn(Cursor c, int columnIndex) {
354526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!c.isNull(columnIndex)) {
355526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return getBytes(c.getString(columnIndex));
356526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
357526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return null;
358526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
359526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
360526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private PduPart[] loadParts(long msgId) throws MmsException {
361526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
362526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Uri.parse("content://mms/" + msgId + "/part"),
363526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PART_PROJECTION, null, null, null);
364526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
365526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PduPart[] parts = null;
366526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
367526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
368526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if ((c == null) || (c.getCount() == 0)) {
369526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (LOCAL_LOGV) {
370526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.v(TAG, "loadParts(" + msgId + "): no part to load.");
371526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
372526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                return null;
373526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
374526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
375526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int partCount = c.getCount();
376526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int partIdx = 0;
377526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            parts = new PduPart[partCount];
378526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            while (c.moveToNext()) {
379526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PduPart part = new PduPart();
380526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Integer charset = getIntegerFromPartColumn(
381526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_CHARSET);
382526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (charset != null) {
383526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setCharset(charset);
384526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
385526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
386526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] contentDisposition = getByteArrayFromPartColumn(
387526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_CONTENT_DISPOSITION);
388526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (contentDisposition != null) {
389526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setContentDisposition(contentDisposition);
390526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
391526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
392526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] contentId = getByteArrayFromPartColumn(
393526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_CONTENT_ID);
394526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (contentId != null) {
395526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setContentId(contentId);
396526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
397526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
398526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] contentLocation = getByteArrayFromPartColumn(
399526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_CONTENT_LOCATION);
400526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (contentLocation != null) {
401526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setContentLocation(contentLocation);
402526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
403526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
404526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] contentType = getByteArrayFromPartColumn(
405526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_CONTENT_TYPE);
406526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (contentType != null) {
407526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setContentType(contentType);
408526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } else {
409526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    throw new MmsException("Content-Type must be set.");
410526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
411526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
412526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] fileName = getByteArrayFromPartColumn(
413526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_FILENAME);
414526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (fileName != null) {
415526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setFilename(fileName);
416526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
417526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
418526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                byte[] name = getByteArrayFromPartColumn(
419526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        c, PART_COLUMN_NAME);
420526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (name != null) {
421526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setName(name);
422526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
423526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
424526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // Construct a Uri for this part.
425526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                long partId = c.getLong(PART_COLUMN_ID);
426526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Uri partURI = Uri.parse("content://mms/part/" + partId);
427526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                part.setDataUri(partURI);
428526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
429526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // For images/audio/video, we won't keep their data in Part
430526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // because their renderer accept Uri as source.
431526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                String type = toIsoString(contentType);
432526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (!ContentType.isImageType(type)
433526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        && !ContentType.isAudioType(type)
434526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        && !ContentType.isVideoType(type)) {
435526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
436526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    InputStream is = null;
437526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
438526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // Store simple string values directly in the database instead of an
439526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // external file.  This makes the text searchable and retrieval slightly
440526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // faster.
441526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type)
442526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            || ContentType.TEXT_HTML.equals(type)) {
443526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        String text = c.getString(PART_COLUMN_TEXT);
444526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        byte [] blob = new EncodedStringValue(text != null ? text : "")
445526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            .getTextString();
446526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        baos.write(blob, 0, blob.length);
447526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    } else {
448526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
449526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        try {
450526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            is = mContentResolver.openInputStream(partURI);
451526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
452526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            byte[] buffer = new byte[256];
453526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            int len = is.read(buffer);
454526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            while (len >= 0) {
455526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                baos.write(buffer, 0, len);
456526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                len = is.read(buffer);
457526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
458526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        } catch (IOException e) {
459526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            Log.e(TAG, "Failed to load part data", e);
460526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            c.close();
461526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            throw new MmsException(e);
462526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        } finally {
463526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            if (is != null) {
464526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                try {
465526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                    is.close();
466526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                } catch (IOException e) {
467526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                    Log.e(TAG, "Failed to close stream", e);
468526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                } // Ignore
469526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
470526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
471526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
472526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    part.setData(baos.toByteArray());
473526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
474526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                parts[partIdx++] = part;
475526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
476526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } finally {
477526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (c != null) {
478526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                c.close();
479526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
480526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
481526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
482526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return parts;
483526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
484526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
485526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void loadAddress(long msgId, PduHeaders headers) {
486526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Cursor c = SqliteWrapper.query(mContext, mContentResolver,
487526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Uri.parse("content://mms/" + msgId + "/addr"),
488526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                new String[] { Addr.ADDRESS, Addr.CHARSET, Addr.TYPE },
489526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                null, null, null);
490526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
491526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (c != null) {
492526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            try {
493526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                while (c.moveToNext()) {
494526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    String addr = c.getString(0);
495526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (!TextUtils.isEmpty(addr)) {
496526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        int addrType = c.getInt(2);
497526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        switch (addrType) {
498526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            case PduHeaders.FROM:
499526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                headers.setEncodedStringValue(
500526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
501526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                        addrType);
502526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                break;
503526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            case PduHeaders.TO:
504526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            case PduHeaders.CC:
505526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            case PduHeaders.BCC:
506526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                headers.appendEncodedStringValue(
507526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                        new EncodedStringValue(c.getInt(1), getBytes(addr)),
508526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                        addrType);
509526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                break;
510526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            default:
511526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                Log.e(TAG, "Unknown address type: " + addrType);
512526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                break;
513526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
514526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
515526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
516526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } finally {
517526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                c.close();
518526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
519526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
520526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
521526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
522526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
523526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Load a PDU from storage by given Uri.
524526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
525526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param uri The Uri of the PDU to be loaded.
526526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @return A generic PDU object, it may be cast to dedicated PDU.
527526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @throws MmsException Failed to load some fields of a PDU.
528526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
529526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public GenericPdu load(Uri uri) throws MmsException {
530526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        GenericPdu pdu = null;
531526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PduCacheEntry cacheEntry = null;
532526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int msgBox = 0;
533526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long threadId = -1;
534526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
535526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            synchronized(PDU_CACHE_INSTANCE) {
536526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
537526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (LOCAL_LOGV) {
538526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.v(TAG, "load: " + uri + " blocked by isUpdating()");
539526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
540526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    try {
541526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        PDU_CACHE_INSTANCE.wait();
542526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    } catch (InterruptedException e) {
543526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.e(TAG, "load: ", e);
544526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
545526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
546526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (cacheEntry != null) {
547526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        return cacheEntry.getPdu();
548526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
549526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
550526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // Tell the cache to indicate to other callers that this item
551526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // is currently being updated.
552526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.setUpdating(uri, true);
553526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
554526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
555526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
556526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    PDU_PROJECTION, null, null, null);
557526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduHeaders headers = new PduHeaders();
558526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Set<Entry<Integer, Integer>> set;
559526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long msgId = ContentUris.parseId(uri);
560526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
561526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            try {
562526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if ((c == null) || (c.getCount() != 1) || !c.moveToFirst()) {
563526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    throw new MmsException("Bad uri: " + uri);
564526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
565526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
566526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                msgBox = c.getInt(PDU_COLUMN_MESSAGE_BOX);
567526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                threadId = c.getLong(PDU_COLUMN_THREAD_ID);
568526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
569526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                set = ENCODED_STRING_COLUMN_INDEX_MAP.entrySet();
570526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                for (Entry<Integer, Integer> e : set) {
571526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    setEncodedStringValueToHeaders(
572526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            c, e.getValue(), headers, e.getKey());
573526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
574526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
575526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                set = TEXT_STRING_COLUMN_INDEX_MAP.entrySet();
576526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                for (Entry<Integer, Integer> e : set) {
577526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    setTextStringToHeaders(
578526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            c, e.getValue(), headers, e.getKey());
579526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
580526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
581526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                set = OCTET_COLUMN_INDEX_MAP.entrySet();
582526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                for (Entry<Integer, Integer> e : set) {
583526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    setOctetToHeaders(
584526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            c, e.getValue(), headers, e.getKey());
585526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
586526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
587526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                set = LONG_COLUMN_INDEX_MAP.entrySet();
588526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                for (Entry<Integer, Integer> e : set) {
589526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    setLongToHeaders(
590526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            c, e.getValue(), headers, e.getKey());
591526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
592526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } finally {
593526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (c != null) {
594526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    c.close();
595526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
596526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
597526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
598526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Check whether 'msgId' has been assigned a valid value.
599526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (msgId == -1L) {
600526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                throw new MmsException("Error! ID of the message: -1.");
601526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
602526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
603526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Load address information of the MM.
604526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            loadAddress(msgId, headers);
605526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
606526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int msgType = headers.getOctet(PduHeaders.MESSAGE_TYPE);
607526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduBody body = new PduBody();
608526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
609526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // For PDU which type is M_retrieve.conf or Send.req, we should
610526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // load multiparts and put them into the body of the PDU.
611526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if ((msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
612526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
613526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PduPart[] parts = loadParts(msgId);
614526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (parts != null) {
615526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    int partsNum = parts.length;
616526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    for (int i = 0; i < partsNum; i++) {
617526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        body.addPart(parts[i]);
618526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
619526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
620526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
621526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
622526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            switch (msgType) {
623526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
624526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new NotificationInd(headers);
625526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
626526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_DELIVERY_IND:
627526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new DeliveryInd(headers);
628526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
629526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_READ_ORIG_IND:
630526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new ReadOrigInd(headers);
631526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
632526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
633526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new RetrieveConf(headers, body);
634526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
635526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_SEND_REQ:
636526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new SendReq(headers, body);
637526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
638526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_ACKNOWLEDGE_IND:
639526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new AcknowledgeInd(headers);
640526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
641526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_NOTIFYRESP_IND:
642526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new NotifyRespInd(headers);
643526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
644526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_READ_REC_IND:
645526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                pdu = new ReadRecInd(headers);
646526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                break;
647526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_SEND_CONF:
648526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_FORWARD_REQ:
649526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_FORWARD_CONF:
650526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_REQ:
651526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_STORE_CONF:
652526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_REQ:
653526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_VIEW_CONF:
654526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_REQ:
655526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_UPLOAD_CONF:
656526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_REQ:
657526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_DELETE_CONF:
658526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_MBOX_DESCR:
659526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_DELETE_REQ:
660526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_DELETE_CONF:
661526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_CANCEL_REQ:
662526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            case PduHeaders.MESSAGE_TYPE_CANCEL_CONF:
663526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                throw new MmsException(
664526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        "Unsupported PDU type: " + Integer.toHexString(msgType));
665526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
666526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            default:
667526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                throw new MmsException(
668526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        "Unrecognized PDU type: " + Integer.toHexString(msgType));
669526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
670526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } finally {
671526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            synchronized(PDU_CACHE_INSTANCE) {
672526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (pdu != null) {
673526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    assert(PDU_CACHE_INSTANCE.get(uri) == null);
674526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // Update the cache entry with the real info
675526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
676526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    PDU_CACHE_INSTANCE.put(uri, cacheEntry);
677526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
678526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.setUpdating(uri, false);
679526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.notifyAll(); // tell anybody waiting on this entry to go ahead
680526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
681526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
682526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return pdu;
683526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
684526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
685526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void persistAddress(
686526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long msgId, int type, EncodedStringValue[] array) {
687526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues(3);
688526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
689526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (EncodedStringValue addr : array) {
690526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.clear(); // Clear all values first.
691526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Addr.ADDRESS, toIsoString(addr.getTextString()));
692526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Addr.CHARSET, addr.getCharacterSet());
693526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Addr.TYPE, type);
694526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
695526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Uri uri = Uri.parse("content://mms/" + msgId + "/addr");
696526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            SqliteWrapper.insert(mContext, mContentResolver, uri, values);
697526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
698526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
699526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
700526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private static String getPartContentType(PduPart part) {
701526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return part.getContentType() == null ? null : toIsoString(part.getContentType());
702526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
703526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
704526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public Uri persistPart(PduPart part, long msgId, HashMap<Uri, InputStream> preOpenedFiles)
705526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throws MmsException {
706526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri uri = Uri.parse("content://mms/" + msgId + "/part");
707526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues(8);
708526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
709526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int charset = part.getCharset();
710526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (charset != 0 ) {
711526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CHARSET, charset);
712526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
713526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
714526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String contentType = getPartContentType(part);
715526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (contentType != null) {
716526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // There is no "image/jpg" in Android (and it's an invalid mimetype).
717526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Change it to "image/jpeg"
718526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (ContentType.IMAGE_JPG.equals(contentType)) {
719526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                contentType = ContentType.IMAGE_JPEG;
720526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
721526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
722526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_TYPE, contentType);
723526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // To ensure the SMIL part is always the first part.
724526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (ContentType.APP_SMIL.equals(contentType)) {
725526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(Part.SEQ, -1);
726526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
727526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } else {
728526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException("MIME type of the part must be set.");
729526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
730526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
731526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getFilename() != null) {
732526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String fileName = new String(part.getFilename());
733526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.FILENAME, fileName);
734526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
735526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
736526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getName() != null) {
737526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String name = new String(part.getName());
738526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.NAME, name);
739526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
740526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
741526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Object value = null;
742526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentDisposition() != null) {
743526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentDisposition());
744526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_DISPOSITION, (String) value);
745526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
746526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
747526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentId() != null) {
748526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentId());
749526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_ID, (String) value);
750526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
751526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
752526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentLocation() != null) {
753526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentLocation());
754526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_LOCATION, (String) value);
755526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
756526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
757526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
758526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (res == null) {
759526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException("Failed to persist part, return null.");
760526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
761526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
762526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        persistData(part, res, contentType, preOpenedFiles);
763526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // After successfully store the data, we should update
764526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // the dataUri of the part.
765526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        part.setDataUri(res);
766526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
767526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return res;
768526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
769526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
770526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
771526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Save data of the part into storage. The source data may be given
772526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * by a byte[] or a Uri. If it's a byte[], directly save it
773526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * into storage, otherwise load source data from the dataUri and then
774526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * save it. If the data is an image, we may scale down it according
775526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * to user preference.
776526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
777526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param part The PDU part which contains data to be saved.
778526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param uri The URI of the part.
779526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param contentType The MIME type of the part.
780526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
781526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @throws MmsException Cannot find source data or error occurred
782526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *         while saving the data.
783526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
784526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void persistData(PduPart part, Uri uri,
785526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String contentType, HashMap<Uri, InputStream> preOpenedFiles)
786526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throws MmsException {
787526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        OutputStream os = null;
788526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        InputStream is = null;
789526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        DrmConvertSession drmConvertSession = null;
790526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri dataUri = null;
791526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String path = null;
792526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
793526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
794526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            byte[] data = part.getData();
795526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (ContentType.TEXT_PLAIN.equals(contentType)
796526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    || ContentType.APP_SMIL.equals(contentType)
797526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    || ContentType.TEXT_HTML.equals(contentType)) {
798526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                ContentValues cv = new ContentValues();
799526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (data == null) {
800526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    data = new String("").getBytes(CharacterSets.DEFAULT_CHARSET_NAME);
801526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
802526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                cv.put(Telephony.Mms.Part.TEXT, new EncodedStringValue(data).getString());
803526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (mContentResolver.update(uri, cv, null, null) != 1) {
804526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    throw new MmsException("unable to update " + uri.toString());
805526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
806526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else {
807526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
808526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (isDrm) {
809526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (uri != null) {
810526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        try {
811526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            path = convertUriToPath(mContext, uri);
812526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            if (LOCAL_LOGV) {
813526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                Log.v(TAG, "drm uri: " + uri + " path: " + path);
814526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
815526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            File f = new File(path);
816526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            long len = f.length();
817526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            if (LOCAL_LOGV) {
818526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                Log.v(TAG, "drm path: " + path + " len: " + len);
819526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
820526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            if (len > 0) {
821526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                // we're not going to re-persist and re-encrypt an already
822526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                // converted drm file
823526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                return;
824526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
825526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        } catch (Exception e) {
826526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
827526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
828526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
829526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // We haven't converted the file yet, start the conversion
830526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    drmConvertSession = DrmConvertSession.open(mContext, contentType);
831526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (drmConvertSession == null) {
832526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        throw new MmsException("Mimetype " + contentType +
833526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                " can not be converted.");
834526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
835526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
836526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // uri can look like:
837526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // content://mms/part/98
838526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                os = mContentResolver.openOutputStream(uri);
839526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (data == null) {
840526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    dataUri = part.getDataUri();
841526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if ((dataUri == null) || (dataUri == uri)) {
842526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.w(TAG, "Can't find data for this part.");
843526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        return;
844526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
845526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // dataUri can look like:
846526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // content://com.google.android.gallery3d.provider/picasa/item/5720646660183715586
847526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (preOpenedFiles != null && preOpenedFiles.containsKey(dataUri)) {
848526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        is = preOpenedFiles.get(dataUri);
849526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
850526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (is == null) {
851526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        is = mContentResolver.openInputStream(dataUri);
852526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
853526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
854526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (LOCAL_LOGV) {
855526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.v(TAG, "Saving data to: " + uri);
856526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
857526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
858526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    byte[] buffer = new byte[8192];
859526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    for (int len = 0; (len = is.read(buffer)) != -1; ) {
860526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        if (!isDrm) {
861526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            os.write(buffer, 0, len);
862526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        } else {
863526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            byte[] convertedData = drmConvertSession.convert(buffer, len);
864526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            if (convertedData != null) {
865526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                os.write(convertedData, 0, convertedData.length);
866526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            } else {
867526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                throw new MmsException("Error converting drm data.");
868526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            }
869526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
870526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
871526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } else {
872526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (LOCAL_LOGV) {
873526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.v(TAG, "Saving data to: " + uri);
874526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
875526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (!isDrm) {
876526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        os.write(data);
877526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    } else {
878526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        dataUri = uri;
879526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        byte[] convertedData = drmConvertSession.convert(data, data.length);
880526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        if (convertedData != null) {
881526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            os.write(convertedData, 0, convertedData.length);
882526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        } else {
883526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            throw new MmsException("Error converting drm data.");
884526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
885526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
886526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
887526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
888526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } catch (FileNotFoundException e) {
889526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Log.e(TAG, "Failed to open Input/Output stream.", e);
890526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException(e);
891526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } catch (IOException e) {
892526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Log.e(TAG, "Failed to read/write data.", e);
893526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException(e);
894526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } finally {
895526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (os != null) {
896526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                try {
897526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    os.close();
898526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } catch (IOException e) {
899526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.e(TAG, "IOException while closing: " + os, e);
900526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } // Ignore
901526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
902526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (is != null) {
903526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                try {
904526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    is.close();
905526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } catch (IOException e) {
906526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.e(TAG, "IOException while closing: " + is, e);
907526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } // Ignore
908526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
909526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (drmConvertSession != null) {
910526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                drmConvertSession.close(path);
911526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
912526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // Reset the permissions on the encrypted part file so everyone has only read
913526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // permission.
914526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                File f = new File(path);
915526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                ContentValues values = new ContentValues(0);
916526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                SqliteWrapper.update(mContext, mContentResolver,
917526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                     Uri.parse("content://mms/resetFilePerm/" + f.getName()),
918526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                     values, null, null);
919526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
920526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
921526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
922526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
923526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
924526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * This method expects uri in the following format
925526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *     content://media/<table_name>/<row_index> (or)
926526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *     file://sdcard/test.mp4
927526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *     http://test.com/test.mp4
928526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
929526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Here <table_name> shall be "video" or "audio" or "images"
930526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * <row_index> the index of the content in given table
931526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
932526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    static public String convertUriToPath(Context context, Uri uri) {
933526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String path = null;
934526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (null != uri) {
935526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String scheme = uri.getScheme();
936526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (null == scheme || scheme.equals("") ||
937526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    scheme.equals(ContentResolver.SCHEME_FILE)) {
938526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                path = uri.getPath();
939526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
940526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else if (scheme.equals("http")) {
941526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                path = uri.toString();
942526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
943526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
944526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                String[] projection = new String[] {MediaStore.MediaColumns.DATA};
945526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Cursor cursor = null;
946526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                try {
947526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    cursor = context.getContentResolver().query(uri, projection, null,
948526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            null, null);
949526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
950526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        throw new IllegalArgumentException("Given Uri could not be found" +
951526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                                " in media store");
952526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
953526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
954526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    path = cursor.getString(pathIndex);
955526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } catch (SQLiteException e) {
956526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    throw new IllegalArgumentException("Given Uri is not formatted in a way " +
957526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            "so that it can be found in media store.");
958526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } finally {
959526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (null != cursor) {
960526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        cursor.close();
961526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
962526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
963526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else {
964526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                throw new IllegalArgumentException("Given Uri scheme is not supported");
965526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
966526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
967526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return path;
968526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
969526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
970526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void updateAddress(
971526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long msgId, int type, EncodedStringValue[] array) {
972526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Delete old address information and then insert new ones.
973526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.delete(mContext, mContentResolver,
974526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Uri.parse("content://mms/" + msgId + "/addr"),
975526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Addr.TYPE + "=" + type, null);
976526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
977526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        persistAddress(msgId, type, array);
978526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
979526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
980526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
981526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Update headers of a SendReq.
982526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
983526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param uri The PDU which need to be updated.
984526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param pdu New headers.
985526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @throws MmsException Bad URI or updating failed.
986526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
987526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public void updateHeaders(Uri uri, SendReq sendReq) {
988526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        synchronized(PDU_CACHE_INSTANCE) {
989526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // If the cache item is getting updated, wait until it's done updating before
990526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // purging it.
991526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
992526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (LOCAL_LOGV) {
993526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.v(TAG, "updateHeaders: " + uri + " blocked by isUpdating()");
994526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
995526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                try {
996526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    PDU_CACHE_INSTANCE.wait();
997526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } catch (InterruptedException e) {
998526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.e(TAG, "updateHeaders: ", e);
999526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1000526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1001526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1002526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PDU_CACHE_INSTANCE.purge(uri);
1003526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1004526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues(10);
1005526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        byte[] contentType = sendReq.getContentType();
1006526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (contentType != null) {
1007526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.CONTENT_TYPE, toIsoString(contentType));
1008526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1009526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1010526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long date = sendReq.getDate();
1011526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (date != -1) {
1012526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.DATE, date);
1013526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1014526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1015526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int deliveryReport = sendReq.getDeliveryReport();
1016526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (deliveryReport != 0) {
1017526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.DELIVERY_REPORT, deliveryReport);
1018526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1019526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1020526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long expiry = sendReq.getExpiry();
1021526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (expiry != -1) {
1022526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.EXPIRY, expiry);
1023526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1024526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1025526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        byte[] msgClass = sendReq.getMessageClass();
1026526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (msgClass != null) {
1027526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.MESSAGE_CLASS, toIsoString(msgClass));
1028526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1029526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1030526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int priority = sendReq.getPriority();
1031526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (priority != 0) {
1032526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.PRIORITY, priority);
1033526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1034526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1035526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int readReport = sendReq.getReadReport();
1036526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (readReport != 0) {
1037526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.READ_REPORT, readReport);
1038526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1039526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1040526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        byte[] transId = sendReq.getTransactionId();
1041526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (transId != null) {
1042526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.TRANSACTION_ID, toIsoString(transId));
1043526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1044526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1045526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        EncodedStringValue subject = sendReq.getSubject();
1046526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (subject != null) {
1047526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.SUBJECT, toIsoString(subject.getTextString()));
1048526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet());
1049526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } else {
1050526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.SUBJECT, "");
1051526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1052526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1053526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long messageSize = sendReq.getMessageSize();
1054526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (messageSize > 0) {
1055526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.MESSAGE_SIZE, messageSize);
1056526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1057526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1058526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PduHeaders headers = sendReq.getPduHeaders();
1059526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        HashSet<String> recipients = new HashSet<String>();
1060526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (int addrType : ADDRESS_FIELDS) {
1061526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            EncodedStringValue[] array = null;
1062526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (addrType == PduHeaders.FROM) {
1063526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                EncodedStringValue v = headers.getEncodedStringValue(addrType);
1064526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (v != null) {
1065526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    array = new EncodedStringValue[1];
1066526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    array[0] = v;
1067526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1068526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else {
1069526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                array = headers.getEncodedStringValues(addrType);
1070526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1071526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1072526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (array != null) {
1073526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                long msgId = ContentUris.parseId(uri);
1074526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                updateAddress(msgId, addrType, array);
1075526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (addrType == PduHeaders.TO) {
1076526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    for (EncodedStringValue v : array) {
1077526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        if (v != null) {
1078526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            recipients.add(v.getString());
1079526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        }
1080526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1081526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1082526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1083526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1084526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!recipients.isEmpty()) {
1085526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long threadId = Threads.getOrCreateThreadId(mContext, recipients);
1086526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.THREAD_ID, threadId);
1087526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1088526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1089526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1090526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1091526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1092526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void updatePart(Uri uri, PduPart part, HashMap<Uri, InputStream> preOpenedFiles)
1093526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throws MmsException {
1094526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues(7);
1095526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1096526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int charset = part.getCharset();
1097526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (charset != 0 ) {
1098526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CHARSET, charset);
1099526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1100526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1101526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String contentType = null;
1102526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentType() != null) {
1103526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            contentType = toIsoString(part.getContentType());
1104526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_TYPE, contentType);
1105526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } else {
1106526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException("MIME type of the part must be set.");
1107526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1108526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1109526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getFilename() != null) {
1110526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String fileName = new String(part.getFilename());
1111526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.FILENAME, fileName);
1112526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1113526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1114526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getName() != null) {
1115526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            String name = new String(part.getName());
1116526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.NAME, name);
1117526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1118526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1119526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Object value = null;
1120526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentDisposition() != null) {
1121526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentDisposition());
1122526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_DISPOSITION, (String) value);
1123526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1124526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1125526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentId() != null) {
1126526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentId());
1127526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_ID, (String) value);
1128526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1129526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1130526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (part.getContentLocation() != null) {
1131526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            value = toIsoString(part.getContentLocation());
1132526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Part.CONTENT_LOCATION, (String) value);
1133526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1134526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1135526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);
1136526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1137526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Only update the data when:
1138526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // 1. New binary data supplied or
1139526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // 2. The Uri of the part is different from the current one.
1140526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if ((part.getData() != null)
1141526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                || (uri != part.getDataUri())) {
1142526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            persistData(part, uri, contentType, preOpenedFiles);
1143526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1144526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1145526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1146526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1147526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Update all parts of a PDU.
1148526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
1149526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param uri The PDU which need to be updated.
1150526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param body New message body of the PDU.
1151526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
1152526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @throws MmsException Bad URI or updating failed.
1153526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1154526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public void updateParts(Uri uri, PduBody body, HashMap<Uri, InputStream> preOpenedFiles)
1155526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throws MmsException {
1156526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
1157526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            PduCacheEntry cacheEntry;
1158526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            synchronized(PDU_CACHE_INSTANCE) {
1159526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1160526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (LOCAL_LOGV) {
1161526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.v(TAG, "updateParts: " + uri + " blocked by isUpdating()");
1162526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1163526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    try {
1164526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        PDU_CACHE_INSTANCE.wait();
1165526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    } catch (InterruptedException e) {
1166526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        Log.e(TAG, "updateParts: ", e);
1167526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1168526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
1169526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (cacheEntry != null) {
1170526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
1171526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1172526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1173526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // Tell the cache to indicate to other callers that this item
1174526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // is currently being updated.
1175526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.setUpdating(uri, true);
1176526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1177526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1178526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
1179526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();
1180526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1181526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int partsNum = body.getPartsNum();
1182526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            StringBuilder filter = new StringBuilder().append('(');
1183526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            for (int i = 0; i < partsNum; i++) {
1184526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PduPart part = body.getPart(i);
1185526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                Uri partUri = part.getDataUri();
1186526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
1187526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    toBeCreated.add(part);
1188526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } else {
1189526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    toBeUpdated.put(partUri, part);
1190526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1191526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // Don't use 'i > 0' to determine whether we should append
1192526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // 'AND' since 'i = 0' may be skipped in another branch.
1193526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (filter.length() > 1) {
1194526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        filter.append(" AND ");
1195526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1196526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1197526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    filter.append(Part._ID);
1198526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    filter.append("!=");
1199526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
1200526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1201526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1202526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            filter.append(')');
1203526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1204526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long msgId = ContentUris.parseId(uri);
1205526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1206526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Remove the parts which doesn't exist anymore.
1207526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            SqliteWrapper.delete(mContext, mContentResolver,
1208526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
1209526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    filter.length() > 2 ? filter.toString() : null, null);
1210526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1211526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Create new parts which didn't exist before.
1212526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            for (PduPart part : toBeCreated) {
1213526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                persistPart(part, msgId, preOpenedFiles);
1214526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1215526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1216526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Update the modified parts.
1217526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
1218526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                updatePart(e.getKey(), e.getValue(), preOpenedFiles);
1219526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1220526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } finally {
1221526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            synchronized(PDU_CACHE_INSTANCE) {
1222526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.setUpdating(uri, false);
1223526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PDU_CACHE_INSTANCE.notifyAll();
1224526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1225526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1226526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1227526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1228526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1229526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Persist a PDU object to specific location in the storage.
1230526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
1231526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param pdu The PDU object to be stored.
1232526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param uri Where to store the given PDU object.
1233526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param createThreadId if true, this function may create a thread id for the recipients
1234526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param groupMmsEnabled if true, all of the recipients addressed in the PDU will be used
1235526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *  to create the associated thread. When false, only the sender will be used in finding or
1236526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *  creating the appropriate thread or conversation.
1237526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param preOpenedFiles if not null, a map of preopened InputStreams for the parts.
1238526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @return A Uri which can be used to access the stored PDU.
1239526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1240526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1241526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public Uri persist(GenericPdu pdu, Uri uri, boolean createThreadId, boolean groupMmsEnabled,
1242526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            HashMap<Uri, InputStream> preOpenedFiles)
1243526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throws MmsException {
1244526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (uri == null) {
1245526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException("Uri may not be null.");
1246526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1247526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long msgId = -1;
1248526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
1249526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            msgId = ContentUris.parseId(uri);
1250526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } catch (NumberFormatException e) {
1251526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // the uri ends with "inbox" or something else like that
1252526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1253526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        boolean existingUri = msgId != -1;
1254526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1255526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
1256526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException(
1257526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    "Bad destination, must be one of "
1258526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/inbox, content://mms/sent, "
1259526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/drafts, content://mms/outbox, "
1260526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/temp.");
1261526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1262526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        synchronized(PDU_CACHE_INSTANCE) {
1263526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // If the cache item is getting updated, wait until it's done updating before
1264526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // purging it.
1265526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
1266526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (LOCAL_LOGV) {
1267526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.v(TAG, "persist: " + uri + " blocked by isUpdating()");
1268526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1269526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                try {
1270526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    PDU_CACHE_INSTANCE.wait();
1271526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                } catch (InterruptedException e) {
1272526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    Log.e(TAG, "persist1: ", e);
1273526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1274526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1275526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1276526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PDU_CACHE_INSTANCE.purge(uri);
1277526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1278526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PduHeaders header = pdu.getPduHeaders();
1279526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        PduBody body = null;
1280526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues();
1281526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Set<Entry<Integer, String>> set;
1282526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1283526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        set = ENCODED_STRING_COLUMN_NAME_MAP.entrySet();
1284526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (Entry<Integer, String> e : set) {
1285526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int field = e.getKey();
1286526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            EncodedStringValue encodedString = header.getEncodedStringValue(field);
1287526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (encodedString != null) {
1288526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                String charsetColumn = CHARSET_COLUMN_NAME_MAP.get(field);
1289526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(e.getValue(), toIsoString(encodedString.getTextString()));
1290526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(charsetColumn, encodedString.getCharacterSet());
1291526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1292526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1293526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1294526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        set = TEXT_STRING_COLUMN_NAME_MAP.entrySet();
1295526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (Entry<Integer, String> e : set){
1296526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            byte[] text = header.getTextString(e.getKey());
1297526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (text != null) {
1298526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(e.getValue(), toIsoString(text));
1299526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1300526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1301526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1302526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        set = OCTET_COLUMN_NAME_MAP.entrySet();
1303526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (Entry<Integer, String> e : set){
1304526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            int b = header.getOctet(e.getKey());
1305526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (b != 0) {
1306526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(e.getValue(), b);
1307526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1308526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1309526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1310526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        set = LONG_COLUMN_NAME_MAP.entrySet();
1311526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (Entry<Integer, String> e : set){
1312526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long l = header.getLongInteger(e.getKey());
1313526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (l != -1L) {
1314526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                values.put(e.getValue(), l);
1315526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1316526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1317526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1318526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        HashMap<Integer, EncodedStringValue[]> addressMap =
1319526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                new HashMap<Integer, EncodedStringValue[]>(ADDRESS_FIELDS.length);
1320526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Save address information.
1321526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (int addrType : ADDRESS_FIELDS) {
1322526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            EncodedStringValue[] array = null;
1323526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (addrType == PduHeaders.FROM) {
1324526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                EncodedStringValue v = header.getEncodedStringValue(addrType);
1325526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (v != null) {
1326526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    array = new EncodedStringValue[1];
1327526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    array[0] = v;
1328526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1329526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            } else {
1330526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                array = header.getEncodedStringValues(addrType);
1331526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1332526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            addressMap.put(addrType, array);
1333526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1334526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1335526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        HashSet<String> recipients = new HashSet<String>();
1336526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        int msgType = pdu.getMessageType();
1337526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Here we only allocate thread ID for M-Notification.ind,
1338526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // M-Retrieve.conf and M-Send.req.
1339526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Some of other PDU types may be allocated a thread ID outside
1340526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // this scope.
1341526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if ((msgType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND)
1342526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)
1343526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                || (msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)) {
1344526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            switch (msgType) {
1345526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
1346526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                case PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF:
1347526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    loadRecipients(PduHeaders.FROM, recipients, addressMap, false);
1348526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1349526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // For received messages when group MMS is enabled, we want to associate this
1350526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // message with the thread composed of all the recipients -- all but our own
1351526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // number, that is. This includes the person who sent the
1352526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // message or the FROM field (above) in addition to the other people the message
1353526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // was addressed to or the TO field. Our own number is in that TO field and
1354526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // we have to ignore it in loadRecipients.
1355526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (groupMmsEnabled) {
1356526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        loadRecipients(PduHeaders.TO, recipients, addressMap, true);
1357089a13f65c9bac16543ec2270152649bb3c77127kschulz
1358526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        // Also load any numbers in the CC field to address group messaging
1359526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        // compatibility issues with devices that place numbers in this field
1360526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        // for group messages.
1361526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        loadRecipients(PduHeaders.CC, recipients, addressMap, true);
1362526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1363526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    break;
1364526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                case PduHeaders.MESSAGE_TYPE_SEND_REQ:
1365526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    loadRecipients(PduHeaders.TO, recipients, addressMap, false);
1366526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    break;
1367526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1368526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            long threadId = 0;
1369526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (createThreadId && !recipients.isEmpty()) {
1370526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // Given all the recipients associated with this message, find (or create) the
1371526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                // correct thread.
1372526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                threadId = Threads.getOrCreateThreadId(mContext, recipients);
1373526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1374526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            values.put(Mms.THREAD_ID, threadId);
1375526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1376526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1377526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Save parts first to avoid inconsistent message is loaded
1378526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // while saving the parts.
1379526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
1380526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1381526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Figure out if this PDU is a text-only message
1382526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        boolean textOnly = true;
1383526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1384089a13f65c9bac16543ec2270152649bb3c77127kschulz        // Sum up the total message size
1385089a13f65c9bac16543ec2270152649bb3c77127kschulz        int messageSize = 0;
1386089a13f65c9bac16543ec2270152649bb3c77127kschulz
1387526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Get body if the PDU is a RetrieveConf or SendReq.
1388526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (pdu instanceof MultimediaMessagePdu) {
1389526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            body = ((MultimediaMessagePdu) pdu).getBody();
1390526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Start saving parts if necessary.
1391526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (body != null) {
1392526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                int partsNum = body.getPartsNum();
1393526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                if (partsNum > 2) {
1394526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // For a text-only message there will be two parts: 1-the SMIL, 2-the text.
1395526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // Down a few lines below we're checking to make sure we've only got SMIL or
1396526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // text. We also have to check then we don't have more than two parts.
1397526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // Otherwise, a slideshow with two text slides would be marked as textOnly.
1398526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    textOnly = false;
1399526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1400526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                for (int i = 0; i < partsNum; i++) {
1401526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    PduPart part = body.getPart(i);
1402089a13f65c9bac16543ec2270152649bb3c77127kschulz                    messageSize += part.getDataLength();
1403526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    persistPart(part, dummyId, preOpenedFiles);
1404526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1405526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // If we've got anything besides text/plain or SMIL part, then we've got
1406526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    // an mms message with some other type of attachment.
1407526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    String contentType = getPartContentType(part);
1408526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    if (contentType != null && !ContentType.APP_SMIL.equals(contentType)
1409526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                            && !ContentType.TEXT_PLAIN.equals(contentType)) {
1410526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                        textOnly = false;
1411526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    }
1412526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1413526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1414526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1415526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Record whether this mms message is a simple plain text or not. This is a hint for the
1416526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // UI.
1417526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        values.put(Mms.TEXT_ONLY, textOnly ? 1 : 0);
1418089a13f65c9bac16543ec2270152649bb3c77127kschulz        // The message-size might already have been inserted when parsing the
1419089a13f65c9bac16543ec2270152649bb3c77127kschulz        // PDU header. If not, then we insert the message size as well.
1420089a13f65c9bac16543ec2270152649bb3c77127kschulz        if (values.getAsInteger(Mms.MESSAGE_SIZE) == null) {
1421089a13f65c9bac16543ec2270152649bb3c77127kschulz            values.put(Mms.MESSAGE_SIZE, messageSize);
1422089a13f65c9bac16543ec2270152649bb3c77127kschulz        }
1423526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1424526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri res = null;
1425526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (existingUri) {
1426526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            res = uri;
1427526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
1428526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } else {
1429526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
1430526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (res == null) {
1431526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                throw new MmsException("persist() failed: return null.");
1432526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1433526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Get the real ID of the PDU and update all parts which were
1434526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // saved with the dummy ID.
1435526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            msgId = ContentUris.parseId(res);
1436526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1437526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1438526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        values = new ContentValues(1);
1439526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        values.put(Part.MSG_ID, msgId);
1440526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.update(mContext, mContentResolver,
1441526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                             Uri.parse("content://mms/" + dummyId + "/part"),
1442526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                             values, null, null);
1443526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // We should return the longest URI of the persisted PDU, for
1444526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // example, if input URI is "content://mms/inbox" and the _ID of
1445526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // persisted PDU is '8', we should return "content://mms/inbox/8"
1446526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // instead of "content://mms/8".
1447526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // FIXME: Should the MmsProvider be responsible for this???
1448526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (!existingUri) {
1449526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            res = Uri.parse(uri + "/" + msgId);
1450526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1451526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1452526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Save address information.
1453526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (int addrType : ADDRESS_FIELDS) {
1454526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            EncodedStringValue[] array = addressMap.get(addrType);
1455526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (array != null) {
1456526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                persistAddress(msgId, addrType, array);
1457526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1458526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1459526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1460526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return res;
1461526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1462526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1463526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1464526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * For a given address type, extract the recipients from the headers.
1465526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
1466526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param addressType can be PduHeaders.FROM, PduHeaders.TO or PduHeaders.CC
1467526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param recipients a HashSet that is loaded with the recipients from the FROM, TO or CC headers
1468526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param addressMap a HashMap of the addresses from the ADDRESS_FIELDS header
1469526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param excludeMyNumber if true, the number of this phone will be excluded from recipients
1470526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1471526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    private void loadRecipients(int addressType, HashSet<String> recipients,
1472526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            HashMap<Integer, EncodedStringValue[]> addressMap, boolean excludeMyNumber) {
1473526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        EncodedStringValue[] array = addressMap.get(addressType);
1474526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (array == null) {
1475526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return;
1476526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1477526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // If the TO recipients is only a single address, then we can skip loadRecipients when
1478526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // we're excluding our own number because we know that address is our own.
1479526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (excludeMyNumber && array.length == 1) {
1480526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return;
1481526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
14828c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor        final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext);
14838c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor        final Set<String> myPhoneNumbers = new HashSet<String>();
14848c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor        if (excludeMyNumber) {
14858c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor            // Build a list of my phone numbers from the various sims.
14868c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor            for (int subid : subscriptionManager.getActiveSubscriptionIdList()) {
14878c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                final String myNumber = mTelephonyManager.getLine1Number(subid);
14888c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                if (myNumber != null) {
14898c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                    myPhoneNumbers.add(myNumber);
14908c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                }
14918c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor            }
14928c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor        }
14938c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor
1494526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        for (EncodedStringValue v : array) {
1495526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            if (v != null) {
14968c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                final String number = v.getString();
14978c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                if (excludeMyNumber) {
14988c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                    for (final String myNumber : myPhoneNumbers) {
14998c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                        if (!PhoneNumberUtils.compare(number, myNumber)
15008c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                                && !recipients.contains(number)) {
15018c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                            // Only add numbers which aren't my own number.
15028c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                            recipients.add(number);
15038c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                            break;
15048c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                        }
15058c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                    }
15068c90b1263ad9ee3a29ec2af435779d095c5cacc7Tom Taylor                } else if (!recipients.contains(number)){
1507526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    recipients.add(number);
1508526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                }
1509526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            }
1510526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1511526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1512526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1513526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1514526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Move a PDU object from one location to another.
1515526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *
1516526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param from Specify the PDU object to be moved.
1517526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @param to The destination location, should be one of the following:
1518526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *        "content://mms/inbox", "content://mms/sent",
1519526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *        "content://mms/drafts", "content://mms/outbox",
1520526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     *        "content://mms/trash".
1521526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @return New Uri of the moved PDU.
1522526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * @throws MmsException Error occurred while moving the message.
1523526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1524526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public Uri move(Uri from, Uri to) throws MmsException {
1525526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Check whether the 'msgId' has been assigned a valid value.
1526526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        long msgId = ContentUris.parseId(from);
1527526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (msgId == -1L) {
1528526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException("Error! ID of the message: -1.");
1529526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1530526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1531526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        // Get corresponding int value of destination box.
1532526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Integer msgBox = MESSAGE_BOX_MAP.get(to);
1533526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        if (msgBox == null) {
1534526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            throw new MmsException(
1535526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    "Bad destination, must be one of "
1536526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/inbox, content://mms/sent, "
1537526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/drafts, content://mms/outbox, "
1538526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                    + "content://mms/temp.");
1539526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1540526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1541526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        ContentValues values = new ContentValues(1);
1542526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        values.put(Mms.MESSAGE_BOX, msgBox);
1543526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.update(mContext, mContentResolver, from, values, null, null);
1544526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return ContentUris.withAppendedId(to, msgId);
1545526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1546526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1547526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1548526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Wrap a byte[] into a String.
1549526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1550526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static String toIsoString(byte[] bytes) {
1551526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
1552526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
1553526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } catch (UnsupportedEncodingException e) {
1554526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Impossible to reach here!
1555526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1556526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return "";
1557526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1558526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1559526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1560526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1561526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Unpack a given String into a byte[].
1562526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1563526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public static byte[] getBytes(String data) {
1564526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        try {
1565526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
1566526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        } catch (UnsupportedEncodingException e) {
1567526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            // Impossible to reach here!
1568526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            Log.e(TAG, "ISO_8859_1 must be supported!", e);
1569526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen            return new byte[0];
1570526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        }
1571526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1572526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1573526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1574526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Remove all objects in the temporary path.
1575526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1576526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public void release() {
1577526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri uri = Uri.parse(TEMPORARY_DRM_OBJECT_URI);
1578526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        SqliteWrapper.delete(mContext, mContentResolver, uri, null, null);
1579526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1580526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1581526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    /**
1582526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     * Find all messages to be sent or downloaded before certain time.
1583526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen     */
1584526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    public Cursor getPendingMessages(long dueTime) {
1585526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        Uri.Builder uriBuilder = PendingMessages.CONTENT_URI.buildUpon();
1586526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        uriBuilder.appendQueryParameter("protocol", "mms");
1587526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1588526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String selection = PendingMessages.ERROR_TYPE + " < ?"
1589526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                + " AND " + PendingMessages.DUE_TIME + " <= ?";
1590526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1591526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        String[] selectionArgs = new String[] {
1592526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                String.valueOf(MmsSms.ERR_TYPE_GENERIC_PERMANENT),
1593526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                String.valueOf(dueTime)
1594526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        };
1595526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen
1596526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen        return SqliteWrapper.query(mContext, mContentResolver,
1597526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                uriBuilder.build(), null, selection, selectionArgs,
1598526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen                PendingMessages.DUE_TIME);
1599526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen    }
1600526ecd1799a2fc467cfce114eae3578b42ccb786Ye Wen}
1601