13e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/* 23e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Copyright (C) 2009 The Android Open Source Project 33e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 43e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 53e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * you may not use this file except in compliance with the License. 63e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * You may obtain a copy of the License at 73e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 83e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 93e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 103e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 113e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 123e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * See the License for the specific language governing permissions and 143e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * limitations under the License. 153e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 163e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 173e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpackage com.android.quicksearchbox; 183e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 19e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.CachedLater; 20e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.Consumer; 21e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.Now; 22e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.NowOrLater; 23e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwoodimport com.android.quicksearchbox.util.NowOrLaterWrapper; 24e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 253e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.graphics.drawable.Drawable; 263e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.net.Uri; 273e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.text.TextUtils; 283e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport android.util.Log; 293e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 303e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertimport java.util.WeakHashMap; 313e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 323e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert/** 333e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Icon loader that caches the results of another icon loader. 343e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 353e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 363e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringertpublic class CachingIconLoader implements IconLoader { 373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final boolean DBG = false; 393e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private static final String TAG = "QSB.CachingIconLoader"; 403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 413e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert private final IconLoader mWrapped; 423e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 43e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private final WeakHashMap<String, Entry> mIconCache; 443e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 453e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert /** 463e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * Creates a new caching icon loader. 473e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * 483e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert * @param wrapped IconLoader whose results will be cached. 493e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert */ 503e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public CachingIconLoader(IconLoader wrapped) { 513e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert mWrapped = wrapped; 52e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIconCache = new WeakHashMap<String, Entry>(); 533e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 543e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 55e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public NowOrLater<Drawable> getIcon(String drawableId) { 563e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (DBG) Log.d(TAG, "getIcon(" + drawableId + ")"); 573e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (TextUtils.isEmpty(drawableId) || "0".equals(drawableId)) { 58e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return new Now<Drawable>(null); 593e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 60e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood Entry newEntry = null; 61e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable.ConstantState> drawableState; 62e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood synchronized (this) { 63e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawableState = queryCache(drawableId); 64e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (drawableState == null) { 65e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood newEntry = new Entry(); 66e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood storeInIconCache(drawableId, newEntry); 67e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 683e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 69e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (drawableState != null) { 70e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return new NowOrLaterWrapper<Drawable.ConstantState, Drawable>(drawableState){ 71e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 72e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public Drawable get(Drawable.ConstantState value) { 73e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return value == null ? null : value.newDrawable(); 74e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood }}; 75e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 76e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable> drawable = mWrapped.getIcon(drawableId); 77e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood newEntry.set(drawable); 78e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood storeInIconCache(drawableId, newEntry); 793e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return drawable; 803e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 813e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 823e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert public Uri getIconUri(String drawableId) { 833e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert return mWrapped.getIconUri(drawableId); 843e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 853e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 86e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private synchronized NowOrLater<Drawable.ConstantState> queryCache(String drawableId) { 87e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable.ConstantState> cached = mIconCache.get(drawableId); 88e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (DBG) { 89e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (cached != null) Log.d(TAG, "Found icon in cache: " + drawableId); 903e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 91e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return cached; 923e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 933e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert 94e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private synchronized void storeInIconCache(String resourceUri, Entry drawable) { 953e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert if (drawable != null) { 96e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mIconCache.put(resourceUri, drawable); 97e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 98e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 99e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 100e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private static class Entry extends CachedLater<Drawable.ConstantState> 101e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood implements Consumer<Drawable>{ 102e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private NowOrLater<Drawable> mDrawable; 103e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private boolean mGotDrawable; 104e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private boolean mCreateRequested; 105e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 106e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public Entry() { 107e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 108e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 109e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public synchronized void set(NowOrLater<Drawable> drawable) { 110e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (mGotDrawable) throw new IllegalStateException("set() may only be called once."); 111e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mGotDrawable = true; 112e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mDrawable = drawable; 113e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (mCreateRequested) { 114e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood getLater(); 115e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 116e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 117e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 118e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood @Override 119e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood protected synchronized void create() { 120e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (!mCreateRequested) { 121e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mCreateRequested = true; 122e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood if (mGotDrawable) { 123e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood getLater(); 124e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 125e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 126e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 127e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 128e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood private void getLater() { 129e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood NowOrLater<Drawable> drawable = mDrawable; 130e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood mDrawable = null; 131e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood drawable.getLater(this); 132e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood } 133e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 134e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood public boolean consume(Drawable value) { 135e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood store(value == null ? null : value.getConstantState()); 136e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood return true; 1373e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 1383e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert } 139e29d52aa72c96c3147fa91d83aeb8dafc6d1f578Mathew Inwood 1403e44ff1f2a204db3f479698cf0b3eab3d451dec2Bjorn Bringert} 141