diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/AppModule.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/AppModule.kt index 48c2699..8a9e6d3 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/AppModule.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/AppModule.kt @@ -40,7 +40,7 @@ class AppModule { @Singleton @Provides - fun provideShortcutManager(@ApplicationContext context: Context): ShortcutManager { - return DynamicShortcutManager(context) + fun provideShortcutManager(@ApplicationContext context: Context, @IoDispatcher ioDispatcher: CoroutineDispatcher): ShortcutManager { + return DynamicShortcutManager(context, ioDispatcher) } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/DynamicShortcutManager.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/DynamicShortcutManager.kt index aa91025..b2ec76e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/DynamicShortcutManager.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/DynamicShortcutManager.kt @@ -6,14 +6,21 @@ import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat import com.zaneschepke.wireguardautotunnel.R +import com.zaneschepke.wireguardautotunnel.module.IoDispatcher +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext -class DynamicShortcutManager(private val context: Context) : ShortcutManager { - override fun addShortcuts() { - ShortcutManagerCompat.setDynamicShortcuts(context, createShortcuts()) +class DynamicShortcutManager(private val context: Context, @IoDispatcher private val ioDispatcher: CoroutineDispatcher) : ShortcutManager { + override suspend fun addShortcuts() { + withContext(ioDispatcher) { + ShortcutManagerCompat.setDynamicShortcuts(context, createShortcuts()) + } } - override fun removeShortcuts() { - ShortcutManagerCompat.removeDynamicShortcuts(context, createShortcuts().map { it.id }) + override suspend fun removeShortcuts() { + withContext(ioDispatcher) { + ShortcutManagerCompat.removeDynamicShortcuts(context, createShortcuts().map { it.id }) + } } private fun createShortcuts(): List { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutManager.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutManager.kt index fc3884c..d811dec 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutManager.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutManager.kt @@ -1,6 +1,6 @@ package com.zaneschepke.wireguardautotunnel.service.shortcut interface ShortcutManager { - fun addShortcuts() - fun removeShortcuts() + suspend fun addShortcuts() + suspend fun removeShortcuts() } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/AppViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/AppViewModel.kt index a44d9c2..dd0307f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/AppViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/AppViewModel.kt @@ -1,5 +1,6 @@ package com.zaneschepke.wireguardautotunnel.ui +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wireguard.android.backend.WgQuickBackend @@ -19,9 +20,11 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.config.model.InterfaceProxy import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.config.model.PeerProxy +import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.splittunnel.SplitTunnelApp import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.LocaleUtil import com.zaneschepke.wireguardautotunnel.util.StringValue +import com.zaneschepke.wireguardautotunnel.util.extensions.getAllInternetCapablePackages import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableSharedFlow @@ -64,6 +67,9 @@ constructor( private val _configurationChange = MutableStateFlow(false) val configurationChange = _configurationChange.asStateFlow() + private val _splitTunnelApps = MutableStateFlow>(emptyList()) + val splitTunnelApps = _splitTunnelApps.asStateFlow() + val uiState = combine( appDataRepository.settings.getSettingsFlow(), @@ -267,6 +273,19 @@ constructor( } } + suspend fun getEmitSplitTunnelApps(context: Context) { + withContext(ioDispatcher) { + val apps = context.getAllInternetCapablePackages().filter { it.applicationInfo != null }.map { pack -> + SplitTunnelApp( + context.packageManager.getApplicationIcon(pack.applicationInfo!!), + context.packageManager.getApplicationLabel(pack.applicationInfo!!).toString(), + pack.packageName, + ) + } + _splitTunnelApps.emit(apps) + } + } + suspend fun requestRoot(): Result { return withContext(ioDispatcher) { kotlin.runCatching { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt index 45fca6a..22f6c86 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt @@ -115,6 +115,10 @@ class MainActivity : AppCompatActivity() { } } + LaunchedEffect(Unit) { + viewModel.getEmitSplitTunnelApps(this@MainActivity) + } + LaunchedEffect(appUiState.autoTunnelActive) { requestAutoTunnelTileServiceUpdate() } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunneloptions/splittunnel/SplitTunnelScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunneloptions/splittunnel/SplitTunnelScreen.kt index 4cba395..de59b20 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunneloptions/splittunnel/SplitTunnelScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunneloptions/splittunnel/SplitTunnelScreen.kt @@ -56,7 +56,6 @@ import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar import com.zaneschepke.wireguardautotunnel.ui.common.textbox.CustomTextField import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.config.model.InterfaceProxy import com.zaneschepke.wireguardautotunnel.ui.theme.iconSize -import com.zaneschepke.wireguardautotunnel.util.extensions.getAllInternetCapablePackages import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth import java.text.Collator @@ -79,6 +78,8 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM val config by remember { derivedStateOf { appUiState.tunnels.first { it.id == tunnelId } } } + val splitTunnelApps by viewModel.splitTunnelApps.collectAsStateWithLifecycle() + var proxyInterface by remember { mutableStateOf(InterfaceProxy()) } var selectedSplitOption by remember { mutableStateOf(SplitOptions.ALL) } @@ -96,27 +97,17 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM selectedPackages.addAll(pair.second) } - val packages = remember { - context.getAllInternetCapablePackages().filter { it.applicationInfo != null }.map { pack -> - SplitTunnelApp( - context.packageManager.getApplicationIcon(pack.applicationInfo!!), - context.packageManager.getApplicationLabel(pack.applicationInfo!!).toString(), - pack.packageName, - ) - } - } - var query: String by remember { mutableStateOf("") } val sortedPackages by remember { derivedStateOf { - packages.sortedWith(compareBy(collator) { it.name }).filter { it.name.contains(query) }.toMutableStateList() + splitTunnelApps.sortedWith(compareBy(collator) { it.name }).filter { it.name.contains(query) }.toMutableStateList() } } LaunchedEffect(Unit) { // clean up any split tunnel packages for apps that were uninstalled - viewModel.cleanUpUninstalledApps(config, packages.map { it.`package` }) + viewModel.cleanUpUninstalledApps(config, splitTunnelApps.map { it.`package` }) } Scaffold(