diff --git a/app/src/main/java/top/yeij/hearth/app/AppRepository.kt b/app/src/main/java/top/yeij/hearth/app/AppRepository.kt new file mode 100644 index 0000000..ed72f6b --- /dev/null +++ b/app/src/main/java/top/yeij/hearth/app/AppRepository.kt @@ -0,0 +1,41 @@ +package top.yeij.hearth.app + +import android.content.Context +import android.content.Intent +import android.util.Log + +data class AppInfo(val packageName: String, val label: String, val iconBase64: String?) + +interface AppSource { + fun queryLaunchableApps(): List + fun launch(packageName: String): Boolean +} + +class AndroidAppSource(private val context: Context) : AppSource { + override fun queryLaunchableApps(): List { + val pm = context.packageManager + 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 补 */) + } + } + + override fun launch(packageName: String): Boolean { + val i = context.packageManager.getLaunchIntentForPackage(packageName) ?: return false + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(i) + return true + } +} + +class AppRepository(private val source: AppSource) { + private val gson = com.google.gson.Gson() + + fun listApps(): String { + Log.d("HearthBridge", "listApps: ${source.queryLaunchableApps().size} apps") + return gson.toJson(source.queryLaunchableApps()) + } + + fun launchApp(packageName: String): Boolean = source.launch(packageName) +} diff --git a/app/src/test/java/top/yeij/hearth/app/AppRepositoryTest.kt b/app/src/test/java/top/yeij/hearth/app/AppRepositoryTest.kt new file mode 100644 index 0000000..c559898 --- /dev/null +++ b/app/src/test/java/top/yeij/hearth/app/AppRepositoryTest.kt @@ -0,0 +1,21 @@ +package top.yeij.hearth.app + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class AppRepositoryTest { + @Test + fun listApps_returnsLauncherAppsJson() { + val repo = AppRepository(FakeAppSource(listOf(FakeApp("com.x.music", "音乐")))) + val json = repo.listApps() + assertTrue(json.contains("\"packageName\":\"com.x.music\"")) + assertTrue(json.contains("\"label\":\"音乐\"")) + } + + @Test + fun launchApp_unknownPackage_returnsFalse() { + val repo = AppRepository(FakeAppSource(emptyList())) + assertEquals(false, repo.launchApp("com.nope")) + } +} diff --git a/app/src/test/java/top/yeij/hearth/app/TestFakes.kt b/app/src/test/java/top/yeij/hearth/app/TestFakes.kt new file mode 100644 index 0000000..4205dd3 --- /dev/null +++ b/app/src/test/java/top/yeij/hearth/app/TestFakes.kt @@ -0,0 +1,13 @@ +package top.yeij.hearth.app + +// 测试用假源:返回固定应用列表,避免依赖 Android Context/PackageManager +// Test fake source: returns a fixed app list, avoiding dependency on Android Context/PackageManager +class FakeAppSource(private val apps: List) : AppSource { + override fun queryLaunchableApps(): List = apps + + override fun launch(packageName: String): Boolean = apps.any { it.packageName == packageName } +} + +// 测试用 AppInfo 构造辅助函数 +// Test helper to construct an AppInfo +fun FakeApp(packageName: String, label: String): AppInfo = AppInfo(packageName, label, null)