blob: de83124bad7b93338fca89c01900a8f5a3219c0a [file] [log] [blame]
Wink Savilled02a0642012-06-14 12:11:20 -07001/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.google.android.mms.util;
19
20import android.content.ContentUris;
21import android.content.UriMatcher;
22import android.net.Uri;
23import android.provider.Telephony.Mms;
24import android.util.Log;
25
26import java.util.HashMap;
27import java.util.HashSet;
28
29public final class PduCache extends AbstractCache<Uri, PduCacheEntry> {
30 private static final String TAG = "PduCache";
31 private static final boolean DEBUG = false;
32 private static final boolean LOCAL_LOGV = false;
33
34 private static final int MMS_ALL = 0;
35 private static final int MMS_ALL_ID = 1;
36 private static final int MMS_INBOX = 2;
37 private static final int MMS_INBOX_ID = 3;
38 private static final int MMS_SENT = 4;
39 private static final int MMS_SENT_ID = 5;
40 private static final int MMS_DRAFTS = 6;
41 private static final int MMS_DRAFTS_ID = 7;
42 private static final int MMS_OUTBOX = 8;
43 private static final int MMS_OUTBOX_ID = 9;
44 private static final int MMS_CONVERSATION = 10;
45 private static final int MMS_CONVERSATION_ID = 11;
46
47 private static final UriMatcher URI_MATCHER;
48 private static final HashMap<Integer, Integer> MATCH_TO_MSGBOX_ID_MAP;
49
50 private static PduCache sInstance;
51
52 static {
53 URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
54 URI_MATCHER.addURI("mms", null, MMS_ALL);
55 URI_MATCHER.addURI("mms", "#", MMS_ALL_ID);
56 URI_MATCHER.addURI("mms", "inbox", MMS_INBOX);
57 URI_MATCHER.addURI("mms", "inbox/#", MMS_INBOX_ID);
58 URI_MATCHER.addURI("mms", "sent", MMS_SENT);
59 URI_MATCHER.addURI("mms", "sent/#", MMS_SENT_ID);
60 URI_MATCHER.addURI("mms", "drafts", MMS_DRAFTS);
61 URI_MATCHER.addURI("mms", "drafts/#", MMS_DRAFTS_ID);
62 URI_MATCHER.addURI("mms", "outbox", MMS_OUTBOX);
63 URI_MATCHER.addURI("mms", "outbox/#", MMS_OUTBOX_ID);
64 URI_MATCHER.addURI("mms-sms", "conversations", MMS_CONVERSATION);
65 URI_MATCHER.addURI("mms-sms", "conversations/#", MMS_CONVERSATION_ID);
66
67 MATCH_TO_MSGBOX_ID_MAP = new HashMap<Integer, Integer>();
68 MATCH_TO_MSGBOX_ID_MAP.put(MMS_INBOX, Mms.MESSAGE_BOX_INBOX);
69 MATCH_TO_MSGBOX_ID_MAP.put(MMS_SENT, Mms.MESSAGE_BOX_SENT);
70 MATCH_TO_MSGBOX_ID_MAP.put(MMS_DRAFTS, Mms.MESSAGE_BOX_DRAFTS);
71 MATCH_TO_MSGBOX_ID_MAP.put(MMS_OUTBOX, Mms.MESSAGE_BOX_OUTBOX);
72 }
73
74 private final HashMap<Integer, HashSet<Uri>> mMessageBoxes;
75 private final HashMap<Long, HashSet<Uri>> mThreads;
76 private final HashSet<Uri> mUpdating;
77
78 private PduCache() {
79 mMessageBoxes = new HashMap<Integer, HashSet<Uri>>();
80 mThreads = new HashMap<Long, HashSet<Uri>>();
81 mUpdating = new HashSet<Uri>();
82 }
83
84 synchronized public static final PduCache getInstance() {
85 if (sInstance == null) {
86 if (LOCAL_LOGV) {
87 Log.v(TAG, "Constructing new PduCache instance.");
88 }
89 sInstance = new PduCache();
90 }
91 return sInstance;
92 }
93
94 @Override
95 synchronized public boolean put(Uri uri, PduCacheEntry entry) {
96 int msgBoxId = entry.getMessageBox();
97 HashSet<Uri> msgBox = mMessageBoxes.get(msgBoxId);
98 if (msgBox == null) {
99 msgBox = new HashSet<Uri>();
100 mMessageBoxes.put(msgBoxId, msgBox);
101 }
102
103 long threadId = entry.getThreadId();
104 HashSet<Uri> thread = mThreads.get(threadId);
105 if (thread == null) {
106 thread = new HashSet<Uri>();
107 mThreads.put(threadId, thread);
108 }
109
110 Uri finalKey = normalizeKey(uri);
111 boolean result = super.put(finalKey, entry);
112 if (result) {
113 msgBox.add(finalKey);
114 thread.add(finalKey);
115 }
116 setUpdating(uri, false);
117 return result;
118 }
119
120 synchronized public void setUpdating(Uri uri, boolean updating) {
121 if (updating) {
122 mUpdating.add(uri);
123 } else {
124 mUpdating.remove(uri);
125 }
126 }
127
128 synchronized public boolean isUpdating(Uri uri) {
129 return mUpdating.contains(uri);
130 }
131
132 @Override
133 synchronized public PduCacheEntry purge(Uri uri) {
134 int match = URI_MATCHER.match(uri);
135 switch (match) {
136 case MMS_ALL_ID:
137 return purgeSingleEntry(uri);
138 case MMS_INBOX_ID:
139 case MMS_SENT_ID:
140 case MMS_DRAFTS_ID:
141 case MMS_OUTBOX_ID:
142 String msgId = uri.getLastPathSegment();
143 return purgeSingleEntry(Uri.withAppendedPath(Mms.CONTENT_URI, msgId));
144 // Implicit batch of purge, return null.
145 case MMS_ALL:
146 case MMS_CONVERSATION:
147 purgeAll();
148 return null;
149 case MMS_INBOX:
150 case MMS_SENT:
151 case MMS_DRAFTS:
152 case MMS_OUTBOX:
153 purgeByMessageBox(MATCH_TO_MSGBOX_ID_MAP.get(match));
154 return null;
155 case MMS_CONVERSATION_ID:
156 purgeByThreadId(ContentUris.parseId(uri));
157 return null;
158 default:
159 return null;
160 }
161 }
162
163 private PduCacheEntry purgeSingleEntry(Uri key) {
164 mUpdating.remove(key);
165 PduCacheEntry entry = super.purge(key);
166 if (entry != null) {
167 removeFromThreads(key, entry);
168 removeFromMessageBoxes(key, entry);
169 return entry;
170 }
171 return null;
172 }
173
174 @Override
175 synchronized public void purgeAll() {
176 super.purgeAll();
177
178 mMessageBoxes.clear();
179 mThreads.clear();
180 mUpdating.clear();
181 }
182
183 /**
184 * @param uri The Uri to be normalized.
185 * @return Uri The normalized key of cached entry.
186 */
187 private Uri normalizeKey(Uri uri) {
188 int match = URI_MATCHER.match(uri);
189 Uri normalizedKey = null;
190
191 switch (match) {
192 case MMS_ALL_ID:
193 normalizedKey = uri;
194 break;
195 case MMS_INBOX_ID:
196 case MMS_SENT_ID:
197 case MMS_DRAFTS_ID:
198 case MMS_OUTBOX_ID:
199 String msgId = uri.getLastPathSegment();
200 normalizedKey = Uri.withAppendedPath(Mms.CONTENT_URI, msgId);
201 break;
202 default:
203 return null;
204 }
205
206 if (LOCAL_LOGV) {
207 Log.v(TAG, uri + " -> " + normalizedKey);
208 }
209 return normalizedKey;
210 }
211
212 private void purgeByMessageBox(Integer msgBoxId) {
213 if (LOCAL_LOGV) {
214 Log.v(TAG, "Purge cache in message box: " + msgBoxId);
215 }
216
217 if (msgBoxId != null) {
218 HashSet<Uri> msgBox = mMessageBoxes.remove(msgBoxId);
219 if (msgBox != null) {
220 for (Uri key : msgBox) {
221 mUpdating.remove(key);
222 PduCacheEntry entry = super.purge(key);
223 if (entry != null) {
224 removeFromThreads(key, entry);
225 }
226 }
227 }
228 }
229 }
230
231 private void removeFromThreads(Uri key, PduCacheEntry entry) {
232 HashSet<Uri> thread = mThreads.get(entry.getThreadId());
233 if (thread != null) {
234 thread.remove(key);
235 }
236 }
237
238 private void purgeByThreadId(long threadId) {
239 if (LOCAL_LOGV) {
240 Log.v(TAG, "Purge cache in thread: " + threadId);
241 }
242
243 HashSet<Uri> thread = mThreads.remove(threadId);
244 if (thread != null) {
245 for (Uri key : thread) {
246 mUpdating.remove(key);
247 PduCacheEntry entry = super.purge(key);
248 if (entry != null) {
249 removeFromMessageBoxes(key, entry);
250 }
251 }
252 }
253 }
254
255 private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
256 HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox()));
257 if (msgBox != null) {
258 msgBox.remove(key);
259 }
260 }
261}