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.Log;
     25 
     26 import java.util.HashMap;
     27 import java.util.HashSet;
     28 
     29 public 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 }
    262