1/*
2 * Copyright (C) 2010 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
17package com.android.gallery3d.data;
18
19import android.content.Context;
20
21import com.android.gallery3d.common.BlobCache;
22import com.android.gallery3d.common.BlobCache.LookupRequest;
23import com.android.gallery3d.common.Utils;
24import com.android.gallery3d.data.BytesBufferPool.BytesBuffer;
25import com.android.gallery3d.util.CacheManager;
26import com.android.gallery3d.util.GalleryUtils;
27
28import java.io.IOException;
29import java.nio.ByteBuffer;
30
31public class ImageCacheService {
32    @SuppressWarnings("unused")
33    private static final String TAG = "ImageCacheService";
34
35    private static final String IMAGE_CACHE_FILE = "imgcache";
36    private static final int IMAGE_CACHE_MAX_ENTRIES = 5000;
37    private static final int IMAGE_CACHE_MAX_BYTES = 200 * 1024 * 1024;
38    private static final int IMAGE_CACHE_VERSION = 7;
39
40    private BlobCache mCache;
41
42    public ImageCacheService(Context context) {
43        mCache = CacheManager.getCache(context, IMAGE_CACHE_FILE,
44                IMAGE_CACHE_MAX_ENTRIES, IMAGE_CACHE_MAX_BYTES,
45                IMAGE_CACHE_VERSION);
46    }
47
48    /**
49     * Gets the cached image data for the given <code>path</code>,
50     *  <code>timeModified</code> and <code>type</code>.
51     *
52     * The image data will be stored in <code>buffer.data</code>, started from
53     * <code>buffer.offset</code> for <code>buffer.length</code> bytes. If the
54     * buffer.data is not big enough, a new byte array will be allocated and returned.
55     *
56     * @return true if the image data is found; false if not found.
57     */
58    public boolean getImageData(Path path, long timeModified, int type, BytesBuffer buffer) {
59        byte[] key = makeKey(path, timeModified, type);
60        long cacheKey = Utils.crc64Long(key);
61        try {
62            LookupRequest request = new LookupRequest();
63            request.key = cacheKey;
64            request.buffer = buffer.data;
65            synchronized (mCache) {
66                if (!mCache.lookup(request)) return false;
67            }
68            if (isSameKey(key, request.buffer)) {
69                buffer.data = request.buffer;
70                buffer.offset = key.length;
71                buffer.length = request.length - buffer.offset;
72                return true;
73            }
74        } catch (IOException ex) {
75            // ignore.
76        }
77        return false;
78    }
79
80    public void putImageData(Path path, long timeModified, int type, byte[] value) {
81        byte[] key = makeKey(path, timeModified, type);
82        long cacheKey = Utils.crc64Long(key);
83        ByteBuffer buffer = ByteBuffer.allocate(key.length + value.length);
84        buffer.put(key);
85        buffer.put(value);
86        synchronized (mCache) {
87            try {
88                mCache.insert(cacheKey, buffer.array());
89            } catch (IOException ex) {
90                // ignore.
91            }
92        }
93    }
94
95    public void clearImageData(Path path, long timeModified, int type) {
96        byte[] key = makeKey(path, timeModified, type);
97        long cacheKey = Utils.crc64Long(key);
98        synchronized (mCache) {
99            try {
100                mCache.clearEntry(cacheKey);
101            } catch (IOException ex) {
102                // ignore.
103            }
104        }
105    }
106
107    private static byte[] makeKey(Path path, long timeModified, int type) {
108        return GalleryUtils.getBytes(path.toString() + "+" + timeModified + "+" + type);
109    }
110
111    private static boolean isSameKey(byte[] key, byte[] buffer) {
112        int n = key.length;
113        if (buffer.length < n) {
114            return false;
115        }
116        for (int i = 0; i < n; ++i) {
117            if (key[i] != buffer[i]) {
118                return false;
119            }
120        }
121        return true;
122    }
123}
124