Files
vnidrop/shared/src/androidMain/kotlin/com/vnidrop/app/Platform.android.kt

83 lines
3.3 KiB
Kotlin

package com.vnidrop.app
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.BatteryManager
import android.os.Build
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.vnidrop.app.core.rememberFileSystemService
import com.vnidrop.app.notifications.rememberAndroidLocalNotificationService
import com.vnidrop.app.feature.receive.ExternalInvitationController
import java.net.NetworkInterface
@Composable
fun rememberAndroidAppDependencies(activity: ComponentActivity, externalInvitations: ExternalInvitationController): AppDependencies {
val context = activity.applicationContext
val fileSystemService = rememberFileSystemService()
val notificationService = rememberAndroidLocalNotificationService(activity)
return remember(context, fileSystemService, notificationService) {
AppDependencies(
environment = PlatformEnvironment(
name = "Android ${Build.VERSION.SDK_INT}",
appVersion = context.appVersion(),
defaultCoreDataDir = context.filesDir.resolve("vnidrop").absolutePath,
defaultUsername = Build.DEVICE.takeIf(String::isNotBlank) ?: "Receiver",
uiPlatform = UiPlatform.Android,
),
deviceInfoProvider = AndroidDeviceInfoProvider(context),
fileSystemService = fileSystemService,
localNotificationService = notificationService,
externalInvitations = externalInvitations,
)
}
}
private class AndroidDeviceInfoProvider(
private val context: Context,
) : DeviceInfoProvider {
override suspend fun load(): DeviceInfo = DeviceInfo(
deviceName = Build.DEVICE,
deviceModel = listOf(Build.MANUFACTURER, Build.MODEL)
.filter(String::isNotBlank)
.joinToString(" ")
.ifBlank { null },
operatingSystem = "Android ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})",
network = context.activeNetworkSummary(),
batteryLevel = context.batteryLevel(),
)
}
private fun Context.appVersion(): String = runCatching {
packageManager.getPackageInfo(packageName, 0).versionName
}.getOrNull()?.takeIf(String::isNotBlank) ?: "unknown"
private fun Context.activeNetworkSummary(): String? = runCatching {
val manager = getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
?: return@runCatching networkInterfaceName()
val activeNetwork = manager.activeNetwork ?: return@runCatching networkInterfaceName()
val capabilities = manager.getNetworkCapabilities(activeNetwork) ?: return@runCatching networkInterfaceName()
when {
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> "Wi-Fi"
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> "Mobile"
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> "Ethernet"
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> "VPN"
else -> networkInterfaceName()
}
}.getOrNull()
private fun Context.batteryLevel(): String? = runCatching {
val manager = getSystemService(BatteryManager::class.java)
val level = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
level.takeIf { it >= 0 }?.let { "$it%" }
}.getOrNull()
private fun networkInterfaceName(): String? =
NetworkInterface.getNetworkInterfaces()
.asSequence()
.filter { it.isUp && !it.isLoopback }
.map { it.displayName }
.firstOrNull()