diff --git a/V2rayNG/app/src/main/AndroidManifest.xml b/V2rayNG/app/src/main/AndroidManifest.xml index 000f3d95..ae32e2cb 100644 --- a/V2rayNG/app/src/main/AndroidManifest.xml +++ b/V2rayNG/app/src/main/AndroidManifest.xml @@ -211,6 +211,16 @@ + + + + + + + ? = null set(value) { @@ -49,6 +50,7 @@ object V2RayServiceManager { context.toast(R.string.app_tile_first_use) return false } + isIntentionalStop = false startContextService(context) return true } @@ -74,6 +76,7 @@ object V2RayServiceManager { MmkvManager.setSelectServer(guid) } + isIntentionalStop = false startContextService(context) } finally { synchronized(operationLock) { @@ -87,8 +90,16 @@ object V2RayServiceManager { * @param context The context from which the service is stopped. */ fun stopVService(context: Context) { - Log.i(AppConfig.TAG, "StartCore-Manager: stopVService called, serviceControl=${serviceControl?.get()}") - MessageUtil.sendMsg2Service(context, AppConfig.MSG_STATE_STOP, "") + Log.i(AppConfig.TAG, "StartCore-Manager: stopVService called") + isIntentionalStop = true + val svc = serviceControl?.get() + if (svc != null) { + svc.stopService() + return + } + val intent = Intent(AppConfig.BROADCAST_ACTION_SERVICE_STOP) + intent.setPackage(AppConfig.ANG_PACKAGE) + context.sendBroadcast(intent) } /** @@ -356,6 +367,10 @@ object V2RayServiceManager { Log.w(AppConfig.TAG, "StartCore-Manager: Core shutdown callback, attempting restart") val service = serviceControl.getService() MessageUtil.sendMsg2UI(service, AppConfig.MSG_STATE_NOT_RUNNING, "") + if (isIntentionalStop) { + Log.i(AppConfig.TAG, "StartCore-Manager: Intentional stop, skipping restart") + return 0 + } CoroutineScope(Dispatchers.IO).launch { kotlinx.coroutines.delay(1000L) val ctx = service.applicationContext diff --git a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/receiver/ServiceControlReceiver.kt b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/receiver/ServiceControlReceiver.kt new file mode 100644 index 00000000..cfa5588e --- /dev/null +++ b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/receiver/ServiceControlReceiver.kt @@ -0,0 +1,19 @@ +package xyz.zarazaex.olc.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import xyz.zarazaex.olc.AppConfig +import xyz.zarazaex.olc.handler.V2RayServiceManager + +class ServiceControlReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + AppConfig.BROADCAST_ACTION_SERVICE_STOP -> { + V2RayServiceManager.isIntentionalStop = true + V2RayServiceManager.stopVService(context) + } + AppConfig.BROADCAST_ACTION_SERVICE_START -> V2RayServiceManager.startVServiceFromToggle(context) + } + } +} diff --git a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayProxyOnlyService.kt b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayProxyOnlyService.kt index 6dd718c8..3dee1d9d 100644 --- a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayProxyOnlyService.kt +++ b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayProxyOnlyService.kt @@ -32,7 +32,7 @@ class V2RayProxyOnlyService : Service(), ServiceControl { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i(AppConfig.TAG, "StartCore-Proxy: Service command received") V2RayServiceManager.startCoreLoop(null) - return START_STICKY + return START_NOT_STICKY } /** diff --git a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayVpnService.kt b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayVpnService.kt index 8906e755..ec05edad 100644 --- a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayVpnService.kt +++ b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/service/V2RayVpnService.kt @@ -99,18 +99,16 @@ class V2RayVpnService : VpnService(), ServiceControl { override fun onDestroy() { super.onDestroy() Log.i(AppConfig.TAG, "StartCore-VPN: Service destroyed") + stopAllService(false) wakeLock?.let { if (it.isHeld) it.release() } wakeLock = null - NotificationManager.cancelNotification() - MessageUtil.sendMsg2UI(this, AppConfig.MSG_STATE_STOP_SUCCESS, "") } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i(AppConfig.TAG, "StartCore-VPN: Service command received") setupVpnService() startService() - return START_STICKY - //return super.onStartCommand(intent, flags, startId) + return START_NOT_STICKY } override fun getService(): Service { diff --git a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/ui/MainActivity.kt b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/ui/MainActivity.kt index d2a0d0dc..56a097be 100644 --- a/V2rayNG/app/src/main/java/xyz/zarazaex/olc/ui/MainActivity.kt +++ b/V2rayNG/app/src/main/java/xyz/zarazaex/olc/ui/MainActivity.kt @@ -208,19 +208,13 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect } isFabOperationInProgress = true - val actuallyRunning = V2RayServiceManager.isRunning() - if (mainViewModel.isRunning.value != actuallyRunning) { - Log.w(AppConfig.TAG, "FAB: UI state mismatch, syncing: vm=${mainViewModel.isRunning.value}, actual=$actuallyRunning") - mainViewModel.isRunning.value = actuallyRunning - isFabOperationInProgress = false - return - } + val isRunning = mainViewModel.isRunning.value == true applyRunningState(isLoading = true, isRunning = false) lifecycleScope.launch { try { - if (actuallyRunning) { + if (isRunning) { Log.d(AppConfig.TAG, "FAB: stopping service") V2RayServiceManager.stopVService(this@MainActivity) } else { @@ -229,7 +223,7 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect } } catch (e: Exception) { Log.e(AppConfig.TAG, "FAB: error", e) - applyRunningState(isLoading = false, isRunning = V2RayServiceManager.isRunning()) + applyRunningState(isLoading = false, isRunning = mainViewModel.isRunning.value == true) } finally { isFabOperationInProgress = false } @@ -378,11 +372,6 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect override fun onResume() { super.onResume() - val actuallyRunning = V2RayServiceManager.isRunning() - if (mainViewModel.isRunning.value != actuallyRunning) { - Log.w(AppConfig.TAG, "onResume: syncing state vm=${mainViewModel.isRunning.value}, actual=$actuallyRunning") - mainViewModel.isRunning.value = actuallyRunning - } MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "") }