/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.messaging.datamodel.media; import android.util.LruCache; import com.android.messaging.util.LogUtil; /** * A modified LruCache that is able to hold RefCountedMediaResource instances. It releases * ref on the entries as they are evicted from the cache, and it uses the media resource * size in kilobytes, instead of the entry count, as the size of the cache. * * This class is used by the MediaResourceManager class to maintain a number of caches for * holding different types of {@link RefCountedMediaResource} */ public class MediaCache extends LruCache { private static final String TAG = LogUtil.BUGLE_IMAGE_TAG; // Default memory cache size in kilobytes protected static final int DEFAULT_MEDIA_RESOURCE_CACHE_SIZE_IN_KILOBYTES = 1024 * 5; // 5MB // Unique identifier for the cache. private final int mId; // Descriptive name given to the cache for debugging purposes. private final String mName; // Convenience constructor that uses the default cache size. public MediaCache(final int id, final String name) { this(DEFAULT_MEDIA_RESOURCE_CACHE_SIZE_IN_KILOBYTES, id, name); } public MediaCache(final int maxSize, final int id, final String name) { super(maxSize); mId = id; mName = name; } public void destroy() { evictAll(); } public String getName() { return mName; } public int getId() { return mId; } /** * Gets a media resource from this cache. Must use this method to get resource instead of get() * to ensure addRef() on the resource. */ public synchronized T fetchResourceFromCache(final String key) { final T ret = get(key); if (ret != null) { if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { LogUtil.v(TAG, "cache hit in mediaCache @ " + getName() + ", total cache hit = " + hitCount() + ", total cache miss = " + missCount()); } ret.addRef(); } else if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) { LogUtil.v(TAG, "cache miss in mediaCache @ " + getName() + ", total cache hit = " + hitCount() + ", total cache miss = " + missCount()); } return ret; } /** * Add a media resource to this cache. Must use this method to add resource instead of put() * to ensure addRef() on the resource. */ public synchronized T addResourceToCache(final String key, final T mediaResource) { mediaResource.addRef(); return put(key, mediaResource); } /** * Notify the removed entry that is no longer being cached */ @Override protected synchronized void entryRemoved(final boolean evicted, final String key, final T oldValue, final T newValue) { oldValue.release(); } /** * Measure item size in kilobytes rather than units which is more practical * for a media resource cache */ @Override protected int sizeOf(final String key, final T value) { final int mediaSizeInKilobytes = value.getMediaSize() / 1024; // Never zero-count any resource, count as at least 1KB. return mediaSizeInKilobytes == 0 ? 1 : mediaSizeInKilobytes; } }