1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.messaging.datamodel.media; 17 18 import android.util.LruCache; 19 20 import com.android.messaging.util.LogUtil; 21 22 /** 23 * A modified LruCache that is able to hold RefCountedMediaResource instances. It releases 24 * ref on the entries as they are evicted from the cache, and it uses the media resource 25 * size in kilobytes, instead of the entry count, as the size of the cache. 26 * 27 * This class is used by the MediaResourceManager class to maintain a number of caches for 28 * holding different types of {@link RefCountedMediaResource} 29 */ 30 public class MediaCache<T extends RefCountedMediaResource> extends LruCache<String, T> { 31 private static final String TAG = LogUtil.BUGLE_IMAGE_TAG; 32 33 // Default memory cache size in kilobytes 34 protected static final int DEFAULT_MEDIA_RESOURCE_CACHE_SIZE_IN_KILOBYTES = 1024 * 5; // 5MB 35 36 // Unique identifier for the cache. 37 private final int mId; 38 // Descriptive name given to the cache for debugging purposes. 39 private final String mName; 40 41 // Convenience constructor that uses the default cache size. 42 public MediaCache(final int id, final String name) { 43 this(DEFAULT_MEDIA_RESOURCE_CACHE_SIZE_IN_KILOBYTES, id, name); 44 } 45 46 public MediaCache(final int maxSize, final int id, final String name) { 47 super(maxSize); 48 mId = id; 49 mName = name; 50 } 51 52 public void destroy() { 53 evictAll(); 54 } 55 56 public String getName() { 57 return mName; 58 } 59 60 public int getId() { 61 return mId; 62 } 63 64 /** 65 * Gets a media resource from this cache. Must use this method to get resource instead of get() 66 * to ensure addRef() on the resource. 67 */ 68 public synchronized T fetchResourceFromCache(final String key) { 69 final T ret = get(key); 70 if (ret != null) { 71 if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { 72 LogUtil.v(TAG, "cache hit in mediaCache @ " + getName() + 73 ", total cache hit = " + hitCount() + 74 ", total cache miss = " + missCount()); 75 } 76 ret.addRef(); 77 } else if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { 78 LogUtil.v(TAG, "cache miss in mediaCache @ " + getName() + 79 ", total cache hit = " + hitCount() + 80 ", total cache miss = " + missCount()); 81 } 82 return ret; 83 } 84 85 /** 86 * Add a media resource to this cache. Must use this method to add resource instead of put() 87 * to ensure addRef() on the resource. 88 */ 89 public synchronized T addResourceToCache(final String key, final T mediaResource) { 90 mediaResource.addRef(); 91 return put(key, mediaResource); 92 } 93 94 /** 95 * Notify the removed entry that is no longer being cached 96 */ 97 @Override 98 protected synchronized void entryRemoved(final boolean evicted, final String key, 99 final T oldValue, final T newValue) { 100 oldValue.release(); 101 } 102 103 /** 104 * Measure item size in kilobytes rather than units which is more practical 105 * for a media resource cache 106 */ 107 @Override 108 protected int sizeOf(final String key, final T value) { 109 final int mediaSizeInKilobytes = value.getMediaSize() / 1024; 110 // Never zero-count any resource, count as at least 1KB. 111 return mediaSizeInKilobytes == 0 ? 1 : mediaSizeInKilobytes; 112 } 113 }