1/* 2 * Copyright (C) 2009 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.quicksearchbox; 18 19import com.android.quicksearchbox.util.CachedLater; 20import com.android.quicksearchbox.util.Consumer; 21import com.android.quicksearchbox.util.Now; 22import com.android.quicksearchbox.util.NowOrLater; 23import com.android.quicksearchbox.util.NowOrLaterWrapper; 24 25import android.graphics.drawable.Drawable; 26import android.net.Uri; 27import android.text.TextUtils; 28import android.util.Log; 29 30import java.util.WeakHashMap; 31 32/** 33 * Icon loader that caches the results of another icon loader. 34 * 35 */ 36public class CachingIconLoader implements IconLoader { 37 38 private static final boolean DBG = false; 39 private static final String TAG = "QSB.CachingIconLoader"; 40 41 private final IconLoader mWrapped; 42 43 private final WeakHashMap<String, Entry> mIconCache; 44 45 /** 46 * Creates a new caching icon loader. 47 * 48 * @param wrapped IconLoader whose results will be cached. 49 */ 50 public CachingIconLoader(IconLoader wrapped) { 51 mWrapped = wrapped; 52 mIconCache = new WeakHashMap<String, Entry>(); 53 } 54 55 public NowOrLater<Drawable> getIcon(String drawableId) { 56 if (DBG) Log.d(TAG, "getIcon(" + drawableId + ")"); 57 if (TextUtils.isEmpty(drawableId) || "0".equals(drawableId)) { 58 return new Now<Drawable>(null); 59 } 60 Entry newEntry = null; 61 NowOrLater<Drawable.ConstantState> drawableState; 62 synchronized (this) { 63 drawableState = queryCache(drawableId); 64 if (drawableState == null) { 65 newEntry = new Entry(); 66 storeInIconCache(drawableId, newEntry); 67 } 68 } 69 if (drawableState != null) { 70 return new NowOrLaterWrapper<Drawable.ConstantState, Drawable>(drawableState){ 71 @Override 72 public Drawable get(Drawable.ConstantState value) { 73 return value == null ? null : value.newDrawable(); 74 }}; 75 } 76 NowOrLater<Drawable> drawable = mWrapped.getIcon(drawableId); 77 newEntry.set(drawable); 78 storeInIconCache(drawableId, newEntry); 79 return drawable; 80 } 81 82 public Uri getIconUri(String drawableId) { 83 return mWrapped.getIconUri(drawableId); 84 } 85 86 private synchronized NowOrLater<Drawable.ConstantState> queryCache(String drawableId) { 87 NowOrLater<Drawable.ConstantState> cached = mIconCache.get(drawableId); 88 if (DBG) { 89 if (cached != null) Log.d(TAG, "Found icon in cache: " + drawableId); 90 } 91 return cached; 92 } 93 94 private synchronized void storeInIconCache(String resourceUri, Entry drawable) { 95 if (drawable != null) { 96 mIconCache.put(resourceUri, drawable); 97 } 98 } 99 100 private static class Entry extends CachedLater<Drawable.ConstantState> 101 implements Consumer<Drawable>{ 102 private NowOrLater<Drawable> mDrawable; 103 private boolean mGotDrawable; 104 private boolean mCreateRequested; 105 106 public Entry() { 107 } 108 109 public synchronized void set(NowOrLater<Drawable> drawable) { 110 if (mGotDrawable) throw new IllegalStateException("set() may only be called once."); 111 mGotDrawable = true; 112 mDrawable = drawable; 113 if (mCreateRequested) { 114 getLater(); 115 } 116 } 117 118 @Override 119 protected synchronized void create() { 120 if (!mCreateRequested) { 121 mCreateRequested = true; 122 if (mGotDrawable) { 123 getLater(); 124 } 125 } 126 } 127 128 private void getLater() { 129 NowOrLater<Drawable> drawable = mDrawable; 130 mDrawable = null; 131 drawable.getLater(this); 132 } 133 134 public boolean consume(Drawable value) { 135 store(value == null ? null : value.getConstantState()); 136 return true; 137 } 138 } 139 140} 141