/* * Copyright (C) 2009 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.quicksearchbox; import com.android.quicksearchbox.util.CachedLater; import com.android.quicksearchbox.util.Consumer; import com.android.quicksearchbox.util.Now; import com.android.quicksearchbox.util.NowOrLater; import com.android.quicksearchbox.util.NowOrLaterWrapper; import android.graphics.drawable.Drawable; import android.net.Uri; import android.text.TextUtils; import android.util.Log; import java.util.WeakHashMap; /** * Icon loader that caches the results of another icon loader. * */ public class CachingIconLoader implements IconLoader { private static final boolean DBG = false; private static final String TAG = "QSB.CachingIconLoader"; private final IconLoader mWrapped; private final WeakHashMap<String, Entry> mIconCache; /** * Creates a new caching icon loader. * * @param wrapped IconLoader whose results will be cached. */ public CachingIconLoader(IconLoader wrapped) { mWrapped = wrapped; mIconCache = new WeakHashMap<String, Entry>(); } public NowOrLater<Drawable> getIcon(String drawableId) { if (DBG) Log.d(TAG, "getIcon(" + drawableId + ")"); if (TextUtils.isEmpty(drawableId) || "0".equals(drawableId)) { return new Now<Drawable>(null); } Entry newEntry = null; NowOrLater<Drawable.ConstantState> drawableState; synchronized (this) { drawableState = queryCache(drawableId); if (drawableState == null) { newEntry = new Entry(); storeInIconCache(drawableId, newEntry); } } if (drawableState != null) { return new NowOrLaterWrapper<Drawable.ConstantState, Drawable>(drawableState){ @Override public Drawable get(Drawable.ConstantState value) { return value == null ? null : value.newDrawable(); }}; } NowOrLater<Drawable> drawable = mWrapped.getIcon(drawableId); newEntry.set(drawable); storeInIconCache(drawableId, newEntry); return drawable; } public Uri getIconUri(String drawableId) { return mWrapped.getIconUri(drawableId); } private synchronized NowOrLater<Drawable.ConstantState> queryCache(String drawableId) { NowOrLater<Drawable.ConstantState> cached = mIconCache.get(drawableId); if (DBG) { if (cached != null) Log.d(TAG, "Found icon in cache: " + drawableId); } return cached; } private synchronized void storeInIconCache(String resourceUri, Entry drawable) { if (drawable != null) { mIconCache.put(resourceUri, drawable); } } private static class Entry extends CachedLater<Drawable.ConstantState> implements Consumer<Drawable>{ private NowOrLater<Drawable> mDrawable; private boolean mGotDrawable; private boolean mCreateRequested; public Entry() { } public synchronized void set(NowOrLater<Drawable> drawable) { if (mGotDrawable) throw new IllegalStateException("set() may only be called once."); mGotDrawable = true; mDrawable = drawable; if (mCreateRequested) { getLater(); } } @Override protected synchronized void create() { if (!mCreateRequested) { mCreateRequested = true; if (mGotDrawable) { getLater(); } } } private void getLater() { NowOrLater<Drawable> drawable = mDrawable; mDrawable = null; drawable.getLater(this); } public boolean consume(Drawable value) { store(value == null ? null : value.getConstantState()); return true; } } }