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.android.messaging.mmslib.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.support.v4.util.SimpleArrayMap;
     25 import android.util.Log;
     26 import android.util.SparseArray;
     27 
     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 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 SparseArray<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 SparseArray<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 SparseArray<HashSet<Uri>> mMessageBoxes;
     75     private final SimpleArrayMap<Long, HashSet<Uri>> mThreads;
     76     private final HashSet<Uri> mUpdating;
     77 
     78     private PduCache() {
     79         mMessageBoxes = new SparseArray<HashSet<Uri>>();
     80         mThreads = new SimpleArrayMap<Long, HashSet<Uri>>();
     81         mUpdating = new HashSet<Uri>();
     82     }
     83 
     84     public static final synchronized 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     public synchronized 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     public synchronized void setUpdating(Uri uri, boolean updating) {
    121         if (updating) {
    122             mUpdating.add(uri);
    123         } else {
    124             mUpdating.remove(uri);
    125         }
    126     }
    127 
    128     public synchronized boolean isUpdating(Uri uri) {
    129         return mUpdating.contains(uri);
    130     }
    131 
    132     @Override
    133     public synchronized 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     public synchronized 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.get(msgBoxId);
    219             mMessageBoxes.remove(msgBoxId);
    220             if (msgBox != null) {
    221                 for (Uri key : msgBox) {
    222                     mUpdating.remove(key);
    223                     PduCacheEntry entry = super.purge(key);
    224                     if (entry != null) {
    225                         removeFromThreads(key, entry);
    226                     }
    227                 }
    228             }
    229         }
    230     }
    231 
    232     private void removeFromThreads(Uri key, PduCacheEntry entry) {
    233         HashSet<Uri> thread = mThreads.get(entry.getThreadId());
    234         if (thread != null) {
    235             thread.remove(key);
    236         }
    237     }
    238 
    239     private void purgeByThreadId(long threadId) {
    240         if (LOCAL_LOGV) {
    241             Log.v(TAG, "Purge cache in thread: " + threadId);
    242         }
    243 
    244         HashSet<Uri> thread = mThreads.remove(threadId);
    245         if (thread != null) {
    246             for (Uri key : thread) {
    247                 mUpdating.remove(key);
    248                 PduCacheEntry entry = super.purge(key);
    249                 if (entry != null) {
    250                     removeFromMessageBoxes(key, entry);
    251                 }
    252             }
    253         }
    254     }
    255 
    256     private void removeFromMessageBoxes(Uri key, PduCacheEntry entry) {
    257         HashSet<Uri> msgBox = mThreads.get(Long.valueOf(entry.getMessageBox()));
    258         if (msgBox != null) {
    259             msgBox.remove(key);
    260         }
    261     }
    262 }
    263