11package org.getlantern.lantern
22
33import android.Manifest
4+ import android.app.Service
45import android.content.Intent
56import android.content.pm.PackageManager
67import android.net.VpnService
@@ -20,6 +21,7 @@ import org.getlantern.lantern.constant.VPNStatus
2021import org.getlantern.lantern.handler.EventHandler
2122import org.getlantern.lantern.handler.MethodHandler
2223import org.getlantern.lantern.service.LanternVpnService
24+ import org.getlantern.lantern.service.NoVpnLanternService
2325import org.getlantern.lantern.service.QuickTileService
2426import org.getlantern.lantern.utils.AppLogger
2527import org.getlantern.lantern.utils.VpnStatusManager
@@ -29,7 +31,7 @@ import org.getlantern.lantern.utils.logDir
2931import org.getlantern.lantern.utils.setupDirs
3032
3133
32- class MainActivity : FlutterFragmentActivity () {
34+ open class MainActivity : FlutterFragmentActivity () {
3335 companion object {
3436 const val TAG = " A/MainActivity"
3537 lateinit var instance: MainActivity
@@ -51,6 +53,16 @@ class MainActivity : FlutterFragmentActivity() {
5153
5254 private val serviceStartHandler = Handler (Looper .getMainLooper())
5355
56+ // NOTE: the stealth app uses its own MainActivity under the foundation.bridge
57+ // source set; this main-source-set activity only ever runs in the regular
58+ // (non-stealth) build where STEALTH_ENABLED is always false, so it references
59+ // the regular Lantern service classes directly.
60+ private val vpnServiceClass: Class <out Service >
61+ get() = LanternVpnService ::class .java
62+
63+ private val noVpnServiceClass: Class <out Service >
64+ get() = NoVpnLanternService ::class .java
65+
5466
5567 override fun configureFlutterEngine (flutterEngine : FlutterEngine ) {
5668 super .configureFlutterEngine(flutterEngine)
@@ -94,18 +106,25 @@ class MainActivity : FlutterFragmentActivity() {
94106 if (pendingServiceStart && retryCountResume < maxRetriesResume) {
95107 retryCountResume++
96108 AppLogger .d(TAG , " Retrying pending service start" )
97- startLanternService ()
109+ retryServiceStart ()
98110 }
99111 }
100112
101113 private fun startLanternService () {
102114 AppLogger .d(TAG , " Starting LanternService" )
103- if (isServiceRunning(this , LanternVpnService ::class .java)) {
115+ if (BuildConfig .STEALTH_NO_VPN ) {
116+ AppLogger .d(TAG , " Stealth no-VPN build skips proxy autostart" )
117+ pendingServiceStart = false
118+ retryCount = 0
119+ retryCountResume = 0
120+ return
121+ }
122+ if (isServiceRunning(this , vpnServiceClass)) {
104123 AppLogger .d(TAG , " LanternService is already running" )
105124 return
106125 }
107126 try {
108- val radianceIntent = Intent (this , LanternVpnService :: class .java ).apply {
127+ val radianceIntent = Intent (this , vpnServiceClass ).apply {
109128 action = LanternVpnService .ACTION_START_RADIANCE
110129 }
111130 startService(radianceIntent)
@@ -125,6 +144,27 @@ class MainActivity : FlutterFragmentActivity() {
125144 }
126145 }
127146
147+ private fun startNoVpnProxyService () {
148+ if (isServiceRunning(this , noVpnServiceClass)) {
149+ AppLogger .d(TAG , " NoVpnLanternService is already running; sending start action" )
150+ }
151+ try {
152+ ContextCompat .startForegroundService(this , Intent (this , noVpnServiceClass).apply {
153+ action = NoVpnLanternService .ACTION_START_PROXY
154+ })
155+ AppLogger .d(TAG , " NoVpnLanternService started" )
156+ pendingServiceStart = false
157+ retryCount = 0
158+ retryCountResume = 0
159+ } catch (e: IllegalStateException ) {
160+ AppLogger .e(TAG , " Cannot start no-VPN proxy service in background: ${e.message} " )
161+ pendingServiceStart = true
162+ } catch (e: Exception ) {
163+ AppLogger .e(TAG , " Error starting no-VPN proxy service" , e)
164+ handleImmediateRetry()
165+ }
166+ }
167+
128168 private fun handleImmediateRetry () {
129169 AppLogger .d(TAG , " Handling immediate retry for LanternService start" )
130170 if (retryCount < maxRetries) {
@@ -133,7 +173,7 @@ class MainActivity : FlutterFragmentActivity() {
133173
134174 AppLogger .d(TAG , " Scheduling immediate retry #$retryCount in ${delay} ms" )
135175 serviceStartHandler.postDelayed({
136- startLanternService ()
176+ retryServiceStart ()
137177 }, delay)
138178 } else {
139179 /*
@@ -148,8 +188,20 @@ class MainActivity : FlutterFragmentActivity() {
148188 }
149189 }
150190
191+ private fun retryServiceStart () {
192+ if (BuildConfig .STEALTH_NO_VPN ) {
193+ startNoVpnProxyService()
194+ } else {
195+ startLanternService()
196+ }
197+ }
198+
151199
152200 fun startVPN () {
201+ if (BuildConfig .STEALTH_NO_VPN ) {
202+ startNoVpnProxyService()
203+ return
204+ }
153205 if (! isVPNServiceReady()) {
154206 AppLogger .d(TAG , " VPN service not ready" )
155207 return
@@ -167,7 +219,7 @@ class MainActivity : FlutterFragmentActivity() {
167219 }
168220
169221 try {
170- val vpnIntent = Intent (this , LanternVpnService :: class .java ).apply {
222+ val vpnIntent = Intent (this , vpnServiceClass ).apply {
171223 action = LanternVpnService .ACTION_START_VPN
172224 }
173225 ContextCompat .startForegroundService(this , vpnIntent)
@@ -180,6 +232,13 @@ class MainActivity : FlutterFragmentActivity() {
180232 }
181233
182234 fun connectToServer (tag : String ) {
235+ if (BuildConfig .STEALTH_NO_VPN ) {
236+ ContextCompat .startForegroundService(this , Intent (this , noVpnServiceClass).apply {
237+ action = NoVpnLanternService .ACTION_CONNECT_TO_SERVER
238+ putExtra(" tag" , tag)
239+ })
240+ return
241+ }
183242 if (! isVPNServiceReady()) {
184243 AppLogger .d(TAG , " VPN service not ready" )
185244 return
@@ -196,7 +255,7 @@ class MainActivity : FlutterFragmentActivity() {
196255 }
197256
198257 try {
199- val vpnIntent = Intent (this , LanternVpnService :: class .java ).apply {
258+ val vpnIntent = Intent (this , vpnServiceClass ).apply {
200259 action = LanternVpnService .ACTION_CONNECT_TO_SERVER
201260 putExtra(" tag" , tag)
202261 }
@@ -211,7 +270,20 @@ class MainActivity : FlutterFragmentActivity() {
211270
212271
213272 fun stopVPN () {
214- if (isServiceRunning(this , LanternVpnService ::class .java)) {
273+ if (BuildConfig .STEALTH_NO_VPN ) {
274+ if (isServiceRunning(this , noVpnServiceClass)) {
275+ startService(Intent (this , noVpnServiceClass).apply {
276+ action = NoVpnLanternService .ACTION_STOP_PROXY
277+ })
278+ } else {
279+ CoroutineScope (Dispatchers .Main ).launch {
280+ runCatching { Mobile .stopVPN() }
281+ VpnStatusManager .postVPNStatus(VPNStatus .Disconnected )
282+ }
283+ }
284+ return
285+ }
286+ if (isServiceRunning(this , vpnServiceClass)) {
215287 LanternApp .application.sendBroadcast(
216288 Intent (LanternVpnService .ACTION_STOP_VPN )
217289 .setPackage(LanternApp .application.packageName)
0 commit comments