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