mirror of
https://github.com/2dust/v2rayNG.git
synced 2026-10-29 06:31:54 +00:00
refactor: achieve complete process isolation for CoreServiceManager
This commit is contained in:
1 parent
2c1efde450
commit
919dd71ea7
11 files changed
+165
-166
No files matched your search
@@ -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 -> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user