Home | History | Annotate | Download | only in util
      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.content.ContentUris;
     21 import android.content.UriMatcher;
     22 import android.net.Uri;
     23 import android.provider.Telephony.Mms;
     24 import android.util.Config;
     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 = DEBUG ? Config.LOGD : Config.LOGV;
     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>();
     69         MATCH_TO_MSGBOX_ID_MAP.put(MMS_INBOX,  Mms.MESSAGE_BOX_INBOX);
     70         MATCH_TO_MSGBOX_ID_MAP.put(MMS_SENT,   Mms.MESSAGE_BOX_SENT);
     71         MATCH_TO_MSGBOX_ID_MAP.put(MMS_DRAFTS, Mms.MESSAGE_BOX_DRAFTS);
     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 
     78     private PduCache() {
     79         mMessageBoxes = new HashMap<Integer, HashSet<Uri>>();
     80         mThreads = new HashMap<Long, HashSet<Uri>>();
     81     }
     82 
     83     synchronized public static final PduCache getInstance() {
     84         if (sInstance == null) {
     85             if (LOCAL_LOGV) {
     86                 Log.v(TAG, "Constructing new PduCache instance.");
     87             }
     88             sInstance = new PduCache();
     89         }
     90         return sInstance;
     91     }
     92 
     93     @Override
     94     synchronized public boolean put(Uri uri, PduCacheEntry entry) {
     95         int msgBoxId = entry.getMessageBox();
     96         HashSet<Uri> msgBox = mMessageBoxes.get(msgBoxId);
     97         if (msgBox == null) {
     98             msgBox = new HashSet<Uri>();
     99             mMessageBoxes.put(msgBoxId, msgBox);
    100         }
    101 
    102         long threadId = entry.getThreadId();
    103         HashSet<Uri> thread = mThreads.get(threadId);
    104         if (thread == null) {
    105             thread = new HashSet<Uri>();
    106             mThreads.put(threadId, thread);
    107         }
    108 
    109         Uri finalKey = normalizeKey(uri);
    110         boolean result = super.put(finalKey, entry);
    111         if (result) {
    112             msgBox.add(finalKey);
    113             thread.add(finalKey);
    114         }
    115         return result;
    116     }
    117 
    118     @Override
    119     synchronized public PduCacheEntry purge(Uri uri) {
    120         int match = URI_MATCHER.match(uri);
    121         switch (match) {
    122             case MMS_ALL_ID:
    123                 return purgeSingleEntry(uri);
    124             case MMS_INBOX_ID:
    125             case MMS_SENT_ID:
    126             case MMS_DRAFTS_ID:
    127             case MMS_OUTBOX_ID:
    128                 String msgId = uri.getLastPathSegment();
    129                 return purgeSingleEntry(Uri.withAppendedPath(Mms.CONTENT_URI, msgId));
    130             // Implicit batch of purge, return null.
    131             case MMS_ALL:
    132             case MMS_CONVERSATION:
    133                 purgeAll();
    134                 return null;
    135             case MMS_INBOX:
    136             case MMS_SENT:
    137             case MMS_DRAFTS:
    138             case MMS_OUTBOX:
    139                 purgeByMessageBox(MATCH_TO_MSGBOX_ID_MAP.get(match));
    140                 return null;
    141             case MMS_CONVERSATION_ID:
    142                 purgeByThreadId(ContentUris.parseId(uri));
    143                 return null;
    144             default:
    145                 return null;
    146         }
    147     }
    148 
    149     private PduCacheEntry purgeSingleEntry(Uri key) {
    150         PduCacheEntry entry = super.purge(key);
    151         if (entry != null) {
    152             removeFromThreads(key, entry);
    153             removeFromMessageBoxes(key, entry);
    154             return entry;
    155         }
    156         return null;
    157     }
    158 
    159     @Override
    160     synchronized public void purgeAll() {
    161         super.purgeAll();
    162 
    163         mMessageBoxes.clear();
    164         mThreads.clear();
    165     }
    166 
    167     /**
    168      * @param uri The Uri to be normalized.
    169      * @return Uri The normalized key of cached entry.
    170      */
    171     private Uri normalizeKey(Uri uri) {
    172         int match = URI_MATCHER.match(uri);
    173         Uri normalizedKey = null;
    174 
    175         switch (match) {
    176             case MMS_ALL_ID:
    177                 normalizedKey = uri;
    178                 break;
    179             case MMS_INBOX_ID:
    180             case MMS_SENT_ID:
    181             case MMS_DRAFTS_ID:
    182             case MMS_OUTBOX_ID:
    183                 String msgId = uri.getLastPathSegment();
    184                 normalizedKey = Uri.withAppendedPath(Mms.CONTENT_URI, msgId);
    185                 break;
    186             default:
    187                 return null;
    188         }
    189 
    190         if (LOCAL_LOGV) {
    191             Log.v(TAG, uri + " -> " + normalizedKey);
    192         }
    193         return normalizedKey;
    194     }
    195 
    196     private void purgeByMessageBox(Integer msgBoxId) {
    197         if (LOCAL_LOGV) {
    198             Log.v(TAG, "Purge cache in message box: " + msgBoxId);
    199         }
    200 
    201         if (msgBoxId != null) {
    202             HashSet<Uri> msgBox = mMessageBoxes.remove(msgBoxId);
    203             if (msgBox != null) {
    204                 for (Uri key : msgBox) {
    205                     PduCacheEntry entry = super.purge(key);
    206                     if (entry != null) {
    207                         removeFromThreads(key, entry);
    208                     }
    209                 }
    210             }
    211         }
    212     }
    213 
    214     private void removeFromThreads(Uri key, PduCacheEntry entry) {
    215         HashSet<Uri> thread = mThreads.get(entry.getThreadId());
    216         if (thread != null) {
    217             thread.remove(key);
    218         }
    219     }
    220 
    221     private void purgeByThreadId(long threadId) {
    222         if (LOCAL_LOGV) {
    223             Log.v(TAG, "Purge cache in thread: " + threadId);
    224         }
    225 
    226         HashSet<Uri> thread = mThreads.remove(threadId);
    227         if (thread != null) {
    228             for (Uri key : thread) {
    229                 PduCacheEntry entry = super.purge(key);
    230                 if (entry != null) {
    231                     removeFromMessageBoxes(key, entry);
    232                 }
    233             }
    234         }
    235     }
    236 
    237     private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
    238         HashSet<Uri> msgBox = mThreads.get(entry.getMessageBox());
    239         if (msgBox != null) {
    240             msgBox.remove(key);
    241         }
    242     }
    243 }
    244