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