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