diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreServiceManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreServiceManager.kt index 00d84a727..d707186e1 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreServiceManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/core/CoreServiceManager.kt @@ -16,18 +16,11 @@ import com.v2ray.ang.contracts.ServiceControl import com.v2ray.ang.dto.OutboundTrafficStat import com.v2ray.ang.dto.entities.ProfileItem import com.v2ray.ang.enums.BrowserDialerMode -import com.v2ray.ang.extension.isComplexType import com.v2ray.ang.extension.isNotNullEmpty -import com.v2ray.ang.extension.toast -import com.v2ray.ang.extension.toastError import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.handler.NotificationManager import com.v2ray.ang.handler.SettingsManager import com.v2ray.ang.handler.SpeedtestManager -import com.v2ray.ang.root.RootManager -import com.v2ray.ang.service.CoreProxyOnlyService -import com.v2ray.ang.service.CoreRootService -import com.v2ray.ang.service.CoreVpnService import com.v2ray.ang.service.DialerNativeService import com.v2ray.ang.service.DialerWebviewService import com.v2ray.ang.service.IDialerService @@ -62,55 +55,6 @@ object CoreServiceManager { } } - /** - * Starts the V2Ray service from a toggle action. - * @param context The context from which the service is started. - * @return True if the service was started successfully, false otherwise. - */ - fun startVServiceFromToggle(context: Context): Boolean { - if (MmkvManager.getSelectServer().isNullOrEmpty()) { - context.toast(R.string.app_tile_first_use) - return false - } - try { - startContextService(context) - } catch (e: Exception) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: ${e.message}", e) - context.toast(e.message ?: e.javaClass.simpleName) - return false - } - return true - } - - /** - * Starts the V2Ray service. - * @param context The context from which the service is started. - * @param guid The GUID of the server configuration to use (optional). - */ - fun startVService(context: Context, guid: String? = null) { - LogUtil.i(AppConfig.TAG, "StartCore-Manager: startVService from ${context::class.java.simpleName}") - - if (guid != null) { - MmkvManager.setSelectServer(guid) - } - - try { - startContextService(context) - } catch (e: Exception) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: ${e.message}", e) - context.toast(e.message ?: e.javaClass.simpleName) - } - } - - /** - * Stops the V2Ray service. - * @param context The context from which the service is stopped. - */ - fun stopVService(context: Context) { - //context.toast(R.string.toast_services_stop) - MessageUtil.sendMsg2Service(context, AppConfig.MSG_STATE_STOP, "") - } - /** * Checks if the V2Ray service is running. * @return True if the service is running, false otherwise. @@ -123,98 +67,13 @@ object CoreServiceManager { */ fun getRunningServerName() = currentConfig?.remarks.orEmpty() - /** - * Starts the context service for V2Ray. - * Chooses between VPN service or Proxy-only service based on user settings. - * @param context The context from which the service is started. - * @throws IllegalStateException if the core is already running, no server is selected, - * server config cannot be decoded, or server configuration is invalid. - * @throws Exception if the foreground service fails to start. - */ - @Throws(Exception::class) - private fun startContextService(context: Context) { - if (coreController.isRunning) { - LogUtil.w(AppConfig.TAG, "StartCore-Manager: Core already running") - return - } - - val guid = MmkvManager.getSelectServer() - ?: run { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: No server selected") - error(context.getString(R.string.app_tile_first_use)) - } - - val config = MmkvManager.decodeServerConfig(guid) - ?: run { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: Failed to decode server config") - error(context.getString(R.string.toast_config_file_invalid)) - } - - if (!config.configType.isComplexType() - && !Utils.isValidUrl(config.server) - && !Utils.isPureIpAddress(config.server.orEmpty()) - ) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: Invalid server configuration") - error(context.getString(R.string.toast_config_file_invalid)) - } - - // refresh socks port when enabled dynamic socks port - SettingsManager.refreshRuntimeSocksPort() - -// val result = V2rayConfigUtil.getV2rayConfig(context, guid) -// if (!result.status) error(result.errorMessage.ifBlank { "Failed to get V2Ray config" }) - - if (config.insecure == true && config.pinnedCA256.isNullOrEmpty()) { - context.toastError(R.string.toast_allow_insecure_deprecated) - Utils.setClipboard(context,context.getString(R.string.toast_allow_insecure_deprecated)) - } - - if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PROXY_SHARING)) { - context.toast(R.string.toast_warning_pref_proxysharing_short) - } else { - context.toast(R.string.toast_services_start) - } - - val isRootMode = SettingsManager.isRootMode() - if (isRootMode && !RootManager.isRootAvailable()) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: root mode requires root but none available") - error(context.getString(R.string.toast_root_required)) - } - - val intent = if (isRootMode) { - LogUtil.i(AppConfig.TAG, "StartCore-Manager: Starting Root service") - Intent(context.applicationContext, CoreRootService::class.java) - } else if (SettingsManager.isVpnMode()) { - LogUtil.i(AppConfig.TAG, "StartCore-Manager: Starting VPN service") - Intent(context.applicationContext, CoreVpnService::class.java) - } else { - LogUtil.i(AppConfig.TAG, "StartCore-Manager: Starting Proxy service") - Intent(context.applicationContext, CoreProxyOnlyService::class.java) - } - - try { - ContextCompat.startForegroundService(context, intent) - } catch (e: SecurityException) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: Missing permission to start foreground service", e) - throw IllegalStateException(e.message ?: e.javaClass.simpleName, e) - } catch (e: RuntimeException) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && - e.javaClass.name == "android.app.ForegroundServiceStartNotAllowedException" - ) { - LogUtil.e(AppConfig.TAG, "StartCore-Manager: Foreground service start not allowed", e) - throw IllegalStateException(e.message ?: e.javaClass.simpleName, e) - } - throw e - } - } - /** * Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int): * `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`. * Starts the V2Ray core service. */ fun startCoreLoop(vpnInterface: ParcelFileDescriptor?): Boolean { - if (coreController.isRunning) { + if (isRunning()) { LogUtil.w(AppConfig.TAG, "StartCore-Manager: Core already running") return false } @@ -273,7 +132,7 @@ object CoreServiceManager { } coreController.startLoop(result.content, tunFd) - if (!coreController.isRunning) { + if (!isRunning()) { error("Core failed to start") } @@ -308,7 +167,7 @@ object CoreServiceManager { fun stopCoreLoop(): Boolean { val service = getService() ?: return false - if (coreController.isRunning) { + if (isRunning()) { CoroutineScope(Dispatchers.IO).launch { try { coreController.stopLoop() @@ -372,7 +231,7 @@ object CoreServiceManager { * Also fetches remote IP information if the delay test was successful. */ private fun measureV2rayDelay() { - if (coreController.isRunning == false) { + if (!isRunning()) { return } @@ -511,7 +370,7 @@ object CoreServiceManager { val serviceControl = serviceControl?.get() ?: return when (intent?.getIntExtra("key", 0)) { AppConfig.MSG_REGISTER_CLIENT -> { - if (coreController.isRunning) { + if (isRunning()) { MessageUtil.sendMsg2UI(serviceControl.getService(), AppConfig.MSG_STATE_RUNNING, "") } else { MessageUtil.sendMsg2UI(serviceControl.getService(), AppConfig.MSG_STATE_NOT_RUNNING, "") @@ -535,7 +394,7 @@ object CoreServiceManager { LogUtil.i(AppConfig.TAG, "StartCore-Manager: Restart service") serviceControl.stopService() Thread.sleep(500L) - startVService(serviceControl.getService()) + LauncherManager.startService(serviceControl.getService()) } AppConfig.MSG_MEASURE_DELAY -> { diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/core/LauncherManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/core/LauncherManager.kt new file mode 100644 index 000000000..7da47d5b6 --- /dev/null +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/core/LauncherManager.kt @@ -0,0 +1,129 @@ +package com.v2ray.ang.core + +import android.content.Context +import android.content.Intent +import android.os.Build +import androidx.core.content.ContextCompat +import com.v2ray.ang.AppConfig +import com.v2ray.ang.R +import com.v2ray.ang.extension.isComplexType +import com.v2ray.ang.extension.toast +import com.v2ray.ang.extension.toastError +import com.v2ray.ang.handler.MmkvManager +import com.v2ray.ang.handler.SettingsManager +import com.v2ray.ang.root.RootManager +import com.v2ray.ang.service.CoreProxyOnlyService +import com.v2ray.ang.service.CoreRootService +import com.v2ray.ang.service.CoreVpnService +import com.v2ray.ang.util.LogUtil +import com.v2ray.ang.util.MessageUtil +import com.v2ray.ang.util.Utils + +object LauncherManager { + + fun startServiceFromToggle(context: Context): Boolean { + if (MmkvManager.getSelectServer().isNullOrEmpty()) { + context.toast(R.string.app_tile_first_use) + return false + } + try { + startContextService(context) + } catch (e: Exception) { + LogUtil.e(AppConfig.TAG, "LauncherManager: ${e.message}", e) + context.toast(e.message ?: e.javaClass.simpleName) + return false + } + return true + } + + fun startService(context: Context, guid: String? = null) { + LogUtil.i(AppConfig.TAG, "LauncherManager: startService from ${context::class.java.simpleName}") + + if (guid != null) { + MmkvManager.setSelectServer(guid) + } + + try { + startContextService(context) + } catch (e: Exception) { + LogUtil.e(AppConfig.TAG, "LauncherManager: ${e.message}", e) + context.toast(e.message ?: e.javaClass.simpleName) + } + } + + fun stopService(context: Context) { + //context.toast(R.string.toast_services_stop) + MessageUtil.sendMsg2Service(context, AppConfig.MSG_STATE_STOP, "") + } + + @Throws(Exception::class) + private fun startContextService(context: Context) { + // Note: isRunning check is removed here to avoid loading Native libraries in the UI process. + // The check is performed in CoreServiceManager when the service starts in the daemon process. + + val guid = MmkvManager.getSelectServer() + ?: run { + LogUtil.e(AppConfig.TAG, "LauncherManager: No server selected") + error(context.getString(R.string.app_tile_first_use)) + } + + val config = MmkvManager.decodeServerConfig(guid) + ?: run { + LogUtil.e(AppConfig.TAG, "LauncherManager: Failed to decode server config") + error(context.getString(R.string.toast_config_file_invalid)) + } + + if (!config.configType.isComplexType() + && !Utils.isValidUrl(config.server) + && !Utils.isPureIpAddress(config.server.orEmpty()) + ) { + LogUtil.e(AppConfig.TAG, "LauncherManager: Invalid server configuration") + error(context.getString(R.string.toast_config_file_invalid)) + } + + SettingsManager.refreshRuntimeSocksPort() + + if (config.insecure == true && config.pinnedCA256.isNullOrEmpty()) { + context.toastError(R.string.toast_allow_insecure_deprecated) + Utils.setClipboard(context, context.getString(R.string.toast_allow_insecure_deprecated)) + } + + if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PROXY_SHARING)) { + context.toast(R.string.toast_warning_pref_proxysharing_short) + } else { + context.toast(R.string.toast_services_start) + } + + val isRootMode = SettingsManager.isRootMode() + if (isRootMode && !RootManager.isRootAvailable()) { + LogUtil.e(AppConfig.TAG, "LauncherManager: root mode requires root but none available") + error(context.getString(R.string.toast_root_required)) + } + + val intent = if (isRootMode) { + LogUtil.i(AppConfig.TAG, "LauncherManager: Starting Root service") + Intent(context.applicationContext, CoreRootService::class.java) + } else if (SettingsManager.isVpnMode()) { + LogUtil.i(AppConfig.TAG, "LauncherManager: Starting VPN service") + Intent(context.applicationContext, CoreVpnService::class.java) + } else { + LogUtil.i(AppConfig.TAG, "LauncherManager: Starting Proxy service") + Intent(context.applicationContext, CoreProxyOnlyService::class.java) + } + + try { + ContextCompat.startForegroundService(context, intent) + } catch (e: SecurityException) { + LogUtil.e(AppConfig.TAG, "LauncherManager: Missing permission to start foreground service", e) + throw IllegalStateException(e.message ?: e.javaClass.simpleName, e) + } catch (e: RuntimeException) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && + e.javaClass.name == "android.app.ForegroundServiceStartNotAllowedException" + ) { + LogUtil.e(AppConfig.TAG, "LauncherManager: Foreground service start not allowed", e) + throw IllegalStateException(e.message ?: e.javaClass.simpleName, e) + } + throw e + } + } +} diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/BootReceiver.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/BootReceiver.kt index fb3b9e7d5..b666a1f42 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/BootReceiver.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/BootReceiver.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.os.UserManager import com.v2ray.ang.AppConfig -import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.handler.SubscriptionUpdater import com.v2ray.ang.util.LogUtil @@ -54,7 +54,7 @@ class BootReceiver : BroadcastReceiver() { } LogUtil.i(AppConfig.TAG, "BootReceiver: Starting V2Ray service") - CoreServiceManager.startVService(context) + LauncherManager.startService(context) SubscriptionUpdater.sync(context) } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/TaskerReceiver.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/TaskerReceiver.kt index 4f48eb033..4384092f1 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/TaskerReceiver.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/TaskerReceiver.kt @@ -5,7 +5,7 @@ import android.content.Context import android.content.Intent import android.text.TextUtils import com.v2ray.ang.AppConfig -import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.util.LogUtil class TaskerReceiver : BroadcastReceiver() { @@ -28,12 +28,12 @@ class TaskerReceiver : BroadcastReceiver() { return } else if (switch) { if (guid == AppConfig.TASKER_DEFAULT_GUID) { - CoreServiceManager.startVServiceFromToggle(context) + LauncherManager.startServiceFromToggle(context) } else { - CoreServiceManager.startVService(context, guid) + LauncherManager.startService(context, guid) } } else { - CoreServiceManager.stopVService(context) + LauncherManager.stopService(context) } } catch (e: Exception) { LogUtil.e(AppConfig.TAG, "Error processing Tasker broadcast", e) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt index d63b6ac0f..ca6a58489 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt @@ -10,6 +10,7 @@ import android.widget.RemoteViews import com.v2ray.ang.AppConfig import com.v2ray.ang.R import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager class WidgetProvider : AppWidgetProvider() { /** @@ -68,9 +69,9 @@ class WidgetProvider : AppWidgetProvider() { super.onReceive(context, intent) if (AppConfig.BROADCAST_ACTION_WIDGET_CLICK == intent.action) { if (CoreServiceManager.isRunning()) { - CoreServiceManager.stopVService(context) + LauncherManager.stopService(context) } else { - CoreServiceManager.startVServiceFromToggle(context) + LauncherManager.startServiceFromToggle(context) } } else if (AppConfig.BROADCAST_ACTION_ACTIVITY == intent.action) { AppWidgetManager.getInstance(context)?.let { manager -> diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreProxyOnlyService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreProxyOnlyService.kt index e1ee40655..9f24fcd71 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreProxyOnlyService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/CoreProxyOnlyService.kt @@ -31,7 +31,13 @@ class CoreProxyOnlyService : Service(), ServiceControl { */ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { LogUtil.i(AppConfig.TAG, "StartCore-Proxy: Service command received") - CoreServiceManager.startCoreLoop(null) + + if (!CoreServiceManager.startCoreLoop(null)) { + LogUtil.e(AppConfig.TAG, "StartCore-Proxy: Failed to start core loop") + stopSelf() + return START_NOT_STICKY + } + return START_STICKY } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt index 75019ee5a..e56880f6f 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt @@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat import com.v2ray.ang.AppConfig import com.v2ray.ang.R import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.util.LogUtil import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.Utils @@ -75,11 +76,11 @@ class QSTileService : TileService() { super.onClick() when (qsTile.state) { Tile.STATE_INACTIVE -> { - CoreServiceManager.startVServiceFromToggle(this) + LauncherManager.startServiceFromToggle(this) } Tile.STATE_ACTIVE -> { - CoreServiceManager.stopVService(this) + LauncherManager.stopService(this) } } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainActivity.kt index 5907294e0..0a0bacf7d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/main/MainActivity.kt @@ -12,7 +12,7 @@ import androidx.lifecycle.lifecycleScope import com.v2ray.ang.AngApplication import com.v2ray.ang.AppConfig import com.v2ray.ang.R -import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.dto.entities.ProfileItem import com.v2ray.ang.enums.EConfigType import com.v2ray.ang.enums.PermissionType @@ -160,7 +160,7 @@ class MainActivity : HelperBaseComponentActivity() { private fun handleFabAction() { if (mainViewModel.uiState.value.isRunning) { - CoreServiceManager.stopVService(this) + LauncherManager.stopService(this) } else if (SettingsManager.isVpnMode()) { val intent = VpnService.prepare(this) if (intent == null) startV2Ray() else requestVpnPermission.launch(intent) @@ -185,11 +185,11 @@ class MainActivity : HelperBaseComponentActivity() { ) { checkAndRequestPermission(PermissionType.ACCESS_LOCAL_NETWORK) {} } - CoreServiceManager.startVService(this) + LauncherManager.startService(this) } private fun restartV2Ray() { - if (mainViewModel.uiState.value.isRunning) CoreServiceManager.stopVService(this) + if (mainViewModel.uiState.value.isRunning) LauncherManager.stopService(this) lifecycleScope.launch { kotlinx.coroutines.delay(500) startV2Ray() diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStartActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStartActivity.kt index 4597d4428..1ef053791 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStartActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStartActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.ui.base.BaseComponentActivity class ScStartActivity : BaseComponentActivity() { @@ -17,7 +18,7 @@ class ScStartActivity : BaseComponentActivity() { LaunchedEffect(Unit) { moveTaskToBack(true) if (!CoreServiceManager.isRunning()) { - CoreServiceManager.startVServiceFromToggle(this@ScStartActivity) + LauncherManager.startServiceFromToggle(this@ScStartActivity) } finish() } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStopActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStopActivity.kt index 996e7cf00..dd4fd0e15 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStopActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScStopActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.ui.base.BaseComponentActivity class ScStopActivity : BaseComponentActivity() { @@ -17,7 +18,7 @@ class ScStopActivity : BaseComponentActivity() { LaunchedEffect(Unit) { moveTaskToBack(true) if (CoreServiceManager.isRunning()) { - CoreServiceManager.stopVService(this@ScStopActivity) + LauncherManager.stopService(this@ScStopActivity) } finish() } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScSwitchActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScSwitchActivity.kt index 2eeea69d5..2d4a4c427 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScSwitchActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/shortcut/ScSwitchActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import com.v2ray.ang.core.CoreServiceManager +import com.v2ray.ang.core.LauncherManager import com.v2ray.ang.ui.base.BaseComponentActivity class ScSwitchActivity : BaseComponentActivity() { @@ -17,9 +18,9 @@ class ScSwitchActivity : BaseComponentActivity() { LaunchedEffect(Unit) { moveTaskToBack(true) if (CoreServiceManager.isRunning()) { - CoreServiceManager.stopVService(this@ScSwitchActivity) + LauncherManager.stopService(this@ScSwitchActivity) } else { - CoreServiceManager.startVServiceFromToggle(this@ScSwitchActivity) + LauncherManager.startServiceFromToggle(this@ScSwitchActivity) } finish() }