feat: android app list page with search and icons
This commit is contained in:
@@ -6,6 +6,8 @@ import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowInsetsController
|
||||
import top.yeij.hearth.app.AndroidAppSource
|
||||
import top.yeij.hearth.app.AppRepository
|
||||
import top.yeij.hearth.webview.JsBridge
|
||||
import top.yeij.hearth.webview.WebViewManager
|
||||
|
||||
@@ -36,6 +38,7 @@ class MainActivity : Activity() {
|
||||
deviceHeightPx = dm.heightPixels,
|
||||
density = dm.density,
|
||||
darkMode = darkMode,
|
||||
appRepository = AppRepository(AndroidAppSource(this)),
|
||||
)
|
||||
WebViewManager(this).attach(bridge)
|
||||
Log.d(
|
||||
|
||||
@@ -2,7 +2,12 @@ package top.yeij.hearth.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
data class AppInfo(val packageName: String, val label: String, val iconBase64: String?)
|
||||
|
||||
@@ -17,7 +22,7 @@ class AndroidAppSource(private val context: Context) : AppSource {
|
||||
val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
return pm.queryIntentActivities(intent, 0).map { ri ->
|
||||
val pkg = ri.activityInfo.packageName
|
||||
AppInfo(pkg, ri.loadLabel(pm).toString(), null /* 图标 base64 在 Task 5 补 */)
|
||||
AppInfo(pkg, ri.loadLabel(pm).toString(), drawableToBase64(ri.loadIcon(pm)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +32,18 @@ class AndroidAppSource(private val context: Context) : AppSource {
|
||||
context.startActivity(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// 图标 Drawable → 96px PNG base64 字符串(含 data:image/png;base64, 前缀)
|
||||
// Convert app icon Drawable to a 96px PNG base64 string (with data:image/png;base64, prefix)
|
||||
private fun drawableToBase64(d: Drawable, size: Int = 96): String {
|
||||
val bmp = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bmp)
|
||||
d.setBounds(0, 0, size, size)
|
||||
d.draw(canvas)
|
||||
val out = ByteArrayOutputStream()
|
||||
bmp.compress(Bitmap.CompressFormat.PNG, 100, out)
|
||||
return "data:image/png;base64," + Base64.encodeToString(out.toByteArray(), Base64.NO_WRAP)
|
||||
}
|
||||
}
|
||||
|
||||
class AppRepository(private val source: AppSource) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package top.yeij.hearth.webview
|
||||
|
||||
import android.util.Log
|
||||
import top.yeij.hearth.app.AppRepository
|
||||
|
||||
class JsBridge(
|
||||
private val deviceWidthPx: Int,
|
||||
private val deviceHeightPx: Int,
|
||||
private val density: Float,
|
||||
private val darkMode: Boolean,
|
||||
private val appRepository: AppRepository? = null,
|
||||
) {
|
||||
private val gson = com.google.gson.Gson()
|
||||
|
||||
@@ -22,4 +24,14 @@ class JsBridge(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 返回已安装应用列表 JSON(无仓库时返回空数组)
|
||||
// Return installed app list JSON (empty array when no repository wired)
|
||||
@android.webkit.JavascriptInterface
|
||||
fun listApps(): String = appRepository?.listApps() ?: "[]"
|
||||
|
||||
// 启动指定包名应用,成功返回 true(无仓库时返回 false)
|
||||
// Launch an app by package name, true on success (false when no repository wired)
|
||||
@android.webkit.JavascriptInterface
|
||||
fun launchApp(packageName: String): Boolean = appRepository?.launchApp(packageName) ?: false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user