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