mirror of https://github.com/tasks/tasks
Add WidgetIconProvider
parent
27b21118eb
commit
d9ddd45f13
@ -0,0 +1,118 @@
|
||||
package org.tasks.widget
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.core.graphics.createBitmap
|
||||
import androidx.core.net.toUri
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import org.tasks.BuildConfig
|
||||
import org.tasks.icons.OutlinedGoogleMaterial
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class WidgetIconProvider : ContentProvider() {
|
||||
|
||||
override fun onCreate() = true
|
||||
|
||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||
if (mode != "r") {
|
||||
throw SecurityException("Only read access allowed")
|
||||
}
|
||||
|
||||
return try {
|
||||
val segments = uri.pathSegments
|
||||
if (segments.size != 2) return null
|
||||
|
||||
val iconName = segments[1]
|
||||
|
||||
if (!iconName.matches(Regex("^[a-zA-Z0-9_]+$"))) return null
|
||||
|
||||
val cacheFile = getCacheFile(iconName)
|
||||
|
||||
if (!cacheFile.exists()) {
|
||||
generateIcon(cacheFile, iconName)
|
||||
}
|
||||
|
||||
if (cacheFile.exists()) {
|
||||
ParcelFileDescriptor.open(cacheFile, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to open icon file for URI: $uri")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIcon(file: File, iconName: String) {
|
||||
try {
|
||||
val icon = OutlinedGoogleMaterial.getIcon("gmo_$iconName")
|
||||
val context = context ?: return
|
||||
|
||||
val drawable = IconicsDrawable(context, icon).apply {
|
||||
this.sizeDp = 24
|
||||
}
|
||||
|
||||
val bitmap = createBitmap(
|
||||
drawable.intrinsicWidth.coerceAtLeast(1),
|
||||
drawable.intrinsicHeight.coerceAtLeast(1)
|
||||
)
|
||||
|
||||
val canvas = Canvas(bitmap)
|
||||
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||
drawable.draw(canvas)
|
||||
|
||||
file.parentFile?.mkdirs()
|
||||
FileOutputStream(file).use { out ->
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
|
||||
}
|
||||
bitmap.recycle()
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to generate icon: $iconName")
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCacheFile(iconName: String): File {
|
||||
val context = context ?: throw IllegalStateException("Context is null")
|
||||
val cacheDir = File(context.cacheDir, "widget_icons")
|
||||
cacheDir.mkdirs()
|
||||
return File(cacheDir, "${iconName}.png")
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<out String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
sortOrder: String?,
|
||||
): Cursor? = null
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<out String>?,
|
||||
): Int = 0
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int = 0
|
||||
|
||||
override fun getType(uri: Uri): String = "image/png"
|
||||
|
||||
companion object {
|
||||
const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.widgeticons"
|
||||
|
||||
fun getIconUri(iconName: String): Uri {
|
||||
return "content://$AUTHORITY/icon/$iconName".toUri()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue