From cc526816353a2919fc95bf459fba8570da2ff70a Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 9 Aug 2024 18:14:09 -0400 Subject: [PATCH] Moves service manager to the Application class --- .../com/vitorpamplona/amethyst/Amethyst.kt | 16 +++++++++++ .../vitorpamplona/amethyst/ui/MainActivity.kt | 28 +++++-------------- .../amethyst/ui/navigation/AppTopBar.kt | 12 ++++---- .../amethyst/ui/screen/AccountScreen.kt | 2 -- .../ui/screen/loggedIn/AccountViewModel.kt | 6 ++-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt index 538daea60..aadbe2f0b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt @@ -38,6 +38,7 @@ import com.vitorpamplona.amethyst.service.playback.VideoCache import com.vitorpamplona.quartz.events.OtsEvent import com.vitorpamplona.quartz.ots.OpenTimestamps import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.SupervisorJob @@ -50,6 +51,9 @@ import kotlin.time.measureTimedValue class Amethyst : Application() { val applicationIOScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + // Service Manager is only active when the activity is active. + val serviceManager = ServiceManager() + override fun onTerminate() { super.onTerminate() applicationIOScope.cancel() @@ -125,6 +129,18 @@ class Amethyst : Application() { fun encryptedStorage(npub: String? = null): EncryptedSharedPreferences = EncryptedStorage.preferences(instance, npub) + /** + * Release memory when the UI becomes hidden or when system resources become low. + * + * @param level the memory-related event that was raised. + */ + @OptIn(DelicateCoroutinesApi::class) + override fun onTrimMemory(level: Int) { + super.onTrimMemory(level) + println("Trim Memory $level") + GlobalScope.launch(Dispatchers.Default) { serviceManager.trimMemory() } + } + companion object { lateinit var instance: Amethyst private set diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 6cf0b8613..4fda7918f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -35,8 +35,8 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.compose.runtime.mutableStateOf +import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.LocalPreferences -import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService import com.vitorpamplona.amethyst.service.notifications.PushNotificationUtils @@ -67,8 +67,6 @@ class MainActivity : AppCompatActivity() { val isOnMobileDataState = mutableStateOf(false) private val isOnWifiDataState = mutableStateOf(false) - // Service Manager is only active when the activity is active. - val serviceManager = ServiceManager() private var shouldPauseService = true @RequiresApi(Build.VERSION_CODES.R) @@ -80,7 +78,7 @@ class MainActivity : AppCompatActivity() { setContent { val sharedPreferencesViewModel = prepareSharedViewModel(act = this) - AppScreen(sharedPreferencesViewModel = sharedPreferencesViewModel, serviceManager = serviceManager) + AppScreen(sharedPreferencesViewModel = sharedPreferencesViewModel, serviceManager = Amethyst.instance.serviceManager) } } @@ -105,7 +103,7 @@ class MainActivity : AppCompatActivity() { // Keep connection alive if it's calling the signer app Log.d("shouldPauseService", "shouldPauseService onResume: $shouldPauseService") if (shouldPauseService) { - GlobalScope.launch(Dispatchers.IO) { serviceManager.justStart() } + GlobalScope.launch(Dispatchers.IO) { Amethyst.instance.serviceManager.justStart() } } GlobalScope.launch(Dispatchers.IO) { @@ -129,7 +127,7 @@ class MainActivity : AppCompatActivity() { GlobalScope.launch(Dispatchers.IO) { LanguageTranslatorService.clear() } - serviceManager.cleanObservers() + Amethyst.instance.serviceManager.cleanObservers() // if (BuildConfig.DEBUG) { GlobalScope.launch(Dispatchers.IO) { debugState(this@MainActivity) } @@ -137,7 +135,7 @@ class MainActivity : AppCompatActivity() { Log.d("shouldPauseService", "shouldPauseService onPause: $shouldPauseService") if (shouldPauseService) { - GlobalScope.launch(Dispatchers.IO) { serviceManager.pauseForGood() } + GlobalScope.launch(Dispatchers.IO) { Amethyst.instance.serviceManager.pauseForGood() } } (getSystemService(ConnectivityManager::class.java) as ConnectivityManager) @@ -175,18 +173,6 @@ class MainActivity : AppCompatActivity() { super.onDestroy() } - /** - * Release memory when the UI becomes hidden or when system resources become low. - * - * @param level the memory-related event that was raised. - */ - @OptIn(DelicateCoroutinesApi::class) - override fun onTrimMemory(level: Int) { - super.onTrimMemory(level) - println("Trim Memory $level") - GlobalScope.launch(Dispatchers.Default) { serviceManager.trimMemory() } - } - fun updateNetworkCapabilities(networkCapabilities: NetworkCapabilities): Boolean { val unmetered = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) @@ -228,7 +214,7 @@ class MainActivity : AppCompatActivity() { Log.d("ServiceManager NetworkCallback", "onAvailable: $shouldPauseService") if (shouldPauseService && lastNetwork != null && lastNetwork != network) { - GlobalScope.launch(Dispatchers.IO) { serviceManager.forceRestart() } + GlobalScope.launch(Dispatchers.IO) { Amethyst.instance.serviceManager.forceRestart() } } lastNetwork = network @@ -247,7 +233,7 @@ class MainActivity : AppCompatActivity() { "onCapabilitiesChanged: ${network.networkHandle} hasMobileData ${isOnMobileDataState.value} hasWifi ${isOnWifiDataState.value}", ) if (updateNetworkCapabilities(networkCapabilities) && shouldPauseService) { - serviceManager.forceRestart() + Amethyst.instance.serviceManager.forceRestart() } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt index 73d16c4af..b5db38233 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppTopBar.kt @@ -1028,16 +1028,18 @@ fun debugState(context: Context) { NostrUserProfileDataSource.printCounter() NostrVideoDataSource.printCounter() - val totalMemoryKb = Runtime.getRuntime().totalMemory() / (1024 * 1024) - val freeMemoryKb = Runtime.getRuntime().freeMemory() / (1024 * 1024) + val totalMemoryMb = Runtime.getRuntime().totalMemory() / (1024 * 1024) + val freeMemoryMb = Runtime.getRuntime().freeMemory() / (1024 * 1024) + val maxMemoryMb = Runtime.getRuntime().maxMemory() / (1024 * 1024) - val jvmHeapAllocatedKb = totalMemoryKb - freeMemoryKb + val jvmHeapAllocatedMb = totalMemoryMb - freeMemoryMb - Log.d("STATE DUMP", "Total Heap Allocated: " + jvmHeapAllocatedKb + " MB") + Log.d("STATE DUMP", "Total Heap Allocated: " + jvmHeapAllocatedMb + "/" + maxMemoryMb + " MB") val nativeHeap = Debug.getNativeHeapAllocatedSize() / (1024 * 1024) + val maxNative = Debug.getNativeHeapSize() / (1024 * 1024) - Log.d("STATE DUMP", "Total Native Heap Allocated: " + nativeHeap + " MB") + Log.d("STATE DUMP", "Total Native Heap Allocated: " + nativeHeap + "/" + maxNative + " MB") val activityManager: ActivityManager? = context.getSystemService() if (activityManager != null) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index 7750b476d..fd71836cb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -133,8 +133,6 @@ fun LoggedInPage( ) val activity = getActivity() as MainActivity - // Find a better way to associate these two. - accountViewModel.serviceManager = activity.serviceManager if (accountViewModel.account.signer is NostrSignerExternal) { val lifeCycleOwner = LocalLifecycleOwner.current diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 5bf6ee7c9..3873701d0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -36,8 +36,8 @@ import androidx.lifecycle.map import androidx.lifecycle.viewModelScope import coil.imageLoader import coil.request.ImageRequest +import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.commons.compose.GenericBaseCache import com.vitorpamplona.amethyst.commons.compose.GenericBaseCacheAsync import com.vitorpamplona.amethyst.model.Account @@ -171,8 +171,6 @@ class AccountViewModel( val toasts = MutableSharedFlow(0, 3, onBufferOverflow = BufferOverflow.DROP_OLDEST) - var serviceManager: ServiceManager? = null - val showSensitiveContentChanges = account.live.map { it.account.showSensitiveContent }.distinctUntilChanged() @@ -1191,7 +1189,7 @@ class AccountViewModel( account.proxyPort = portNumber.value.toInt() account.proxy = HttpClientManager.initProxy(checked, "127.0.0.1", account.proxyPort) account.saveable.invalidateData() - serviceManager?.forceRestart() + Amethyst.instance.serviceManager.forceRestart() } }