1 /* 2 * Copyright (C) 2013 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 17 package com.android.gallery3d.filtershow.cache; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.util.Log; 22 import com.android.gallery3d.filtershow.pipeline.Buffer; 23 import com.android.gallery3d.filtershow.pipeline.CacheProcessing; 24 25 import java.lang.ref.WeakReference; 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 29 public class BitmapCache { 30 private static final String LOGTAG = "BitmapCache"; 31 private HashMap<Long, ArrayList<WeakReference<Bitmap>>> 32 mBitmapCache = new HashMap<Long, ArrayList<WeakReference<Bitmap>>>(); 33 private final int mMaxItemsPerKey = 4; 34 35 private static final boolean DEBUG = false; 36 private CacheProcessing mCacheProcessing; 37 38 public final static int PREVIEW_CACHE = 1; 39 public final static int NEW_LOOK = 2; 40 public final static int ICON = 3; 41 public final static int FILTERS = 4; 42 public final static int GEOMETRY = 5; 43 public final static int HIGHRES = 6; 44 public final static int UTIL_GEOMETRY = 7; 45 public final static int RENDERING_REQUEST = 8; 46 public final static int REGION = 9; 47 public final static int TINY_PLANET = 10; 48 public final static int PREVIEW_CACHE_NO_FILTERS = 11; 49 public final static int PREVIEW_CACHE_NO_ROOT = 12; 50 public static final int PREVIEW_CACHE_NO_APPLY = 13; 51 public final static int TRACKING_COUNT = 14; 52 private int[] mTracking = new int[TRACKING_COUNT]; 53 54 class BitmapTracking { 55 Bitmap bitmap; 56 int type; 57 } 58 59 private ArrayList<BitmapTracking> mBitmapTracking = new ArrayList<BitmapTracking>(); 60 61 private void track(Bitmap bitmap, int type) { 62 for (int i = 0; i < mBitmapTracking.size(); i++) { 63 BitmapTracking tracking = mBitmapTracking.get(i); 64 if (tracking.bitmap == bitmap) { 65 Log.e(LOGTAG, "giving a bitmap already given!!!"); 66 } 67 } 68 BitmapTracking tracking = new BitmapTracking(); 69 tracking.bitmap = bitmap; 70 tracking.type = type; 71 mBitmapTracking.add(tracking); 72 mTracking[tracking.type] ++; 73 } 74 75 private void untrack(Bitmap bitmap) { 76 for (int i = 0; i < mBitmapTracking.size(); i++) { 77 BitmapTracking tracking = mBitmapTracking.get(i); 78 if (tracking.bitmap == bitmap) { 79 mTracking[tracking.type] --; 80 mBitmapTracking.remove(i); 81 return; 82 } 83 } 84 } 85 86 public String getTrackingName(int i) { 87 switch (i) { 88 case PREVIEW_CACHE: return "PREVIEW_CACHE"; 89 case PREVIEW_CACHE_NO_FILTERS: return "PREVIEW_CACHE_NO_FILTERS"; 90 case PREVIEW_CACHE_NO_ROOT: return "PREVIEW_CACHE_NO_ROOT"; 91 case PREVIEW_CACHE_NO_APPLY: return "PREVIEW_CACHE_NO_APPLY"; 92 case NEW_LOOK: return "NEW_LOOK"; 93 case ICON: return "ICON"; 94 case FILTERS: return "FILTERS"; 95 case GEOMETRY: return "GEOMETRY"; 96 case HIGHRES: return "HIGHRES"; 97 case UTIL_GEOMETRY: return "UTIL_GEOMETRY"; 98 case RENDERING_REQUEST: return "RENDERING_REQUEST"; 99 case REGION: return "REGION"; 100 case TINY_PLANET: return "TINY_PLANET"; 101 } 102 return "UNKNOWN"; 103 } 104 105 public void showBitmapCounts() { 106 if (!DEBUG) { 107 return; 108 } 109 Log.v(LOGTAG, "\n--- showBitmap --- "); 110 for (int i = 0; i < TRACKING_COUNT; i++) { 111 if (mTracking[i] != 0) { 112 Log.v(LOGTAG, getTrackingName(i) + " => " + mTracking[i]); 113 } 114 } 115 } 116 117 public void setCacheProcessing(CacheProcessing cache) { 118 mCacheProcessing = cache; 119 } 120 121 public void cache(Buffer buffer) { 122 if (buffer == null) { 123 return; 124 } 125 Bitmap bitmap = buffer.getBitmap(); 126 cache(bitmap); 127 } 128 129 public synchronized boolean cache(Bitmap bitmap) { 130 if (bitmap == null) { 131 return true; 132 } 133 if (mCacheProcessing != null && mCacheProcessing.contains(bitmap)) { 134 Log.e(LOGTAG, "Trying to cache a bitmap still used in the pipeline"); 135 return false; 136 } 137 if (DEBUG) { 138 untrack(bitmap); 139 } 140 if (!bitmap.isMutable()) { 141 Log.e(LOGTAG, "Trying to cache a non mutable bitmap"); 142 return true; 143 } 144 Long key = calcKey(bitmap.getWidth(), bitmap.getHeight()); 145 ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key); 146 if (list == null) { 147 list = new ArrayList<WeakReference<Bitmap>>(); 148 mBitmapCache.put(key, list); 149 } 150 int i = 0; 151 while (i < list.size()) { 152 if (list.get(i).get() == null) { 153 list.remove(i); 154 } else { 155 i++; 156 } 157 } 158 for (i = 0; i < list.size(); i++) { 159 if (list.get(i).get() == null) { 160 list.remove(i); 161 } 162 } 163 if (list.size() < mMaxItemsPerKey) { 164 for (i = 0; i < list.size(); i++) { 165 WeakReference<Bitmap> ref = list.get(i); 166 if (ref.get() == bitmap) { 167 return true; // bitmap already in the cache 168 } 169 } 170 list.add(new WeakReference<Bitmap>(bitmap)); 171 } 172 return true; 173 } 174 175 public synchronized Bitmap getBitmap(int w, int h, int type) { 176 Long key = calcKey(w, h); 177 WeakReference<Bitmap> ref = null; 178 ArrayList<WeakReference<Bitmap>> list = mBitmapCache.get(key); 179 if (list != null && list.size() > 0) { 180 ref = list.remove(0); 181 if (list.size() == 0) { 182 mBitmapCache.remove(key); 183 } 184 } 185 Bitmap bitmap = null; 186 if (ref != null) { 187 bitmap = ref.get(); 188 } 189 if (bitmap == null 190 || bitmap.getWidth() != w 191 || bitmap.getHeight() != h) { 192 bitmap = Bitmap.createBitmap( 193 w, h, Bitmap.Config.ARGB_8888); 194 showBitmapCounts(); 195 } 196 197 if (DEBUG) { 198 track(bitmap, type); 199 if (mCacheProcessing != null && mCacheProcessing.contains(bitmap)) { 200 Log.e(LOGTAG, "Trying to give a bitmap used in the pipeline"); 201 } 202 } 203 return bitmap; 204 } 205 206 public synchronized Bitmap getBitmapCopy(Bitmap source, int type) { 207 Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight(), type); 208 Canvas canvas = new Canvas(bitmap); 209 canvas.drawBitmap(source, 0, 0, null); 210 return bitmap; 211 } 212 213 private Long calcKey(long w, long h) { 214 return (w << 32) | h; 215 } 216 } 217