Home | History | Annotate | Download | only in cache
      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