blob: afc039b0bbbf3b7f0f7611426c4859dce1f80ddd [file] [log] [blame]
/*
* 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>()
}
}