Commit fcdcbd14 authored by Mygod's avatar Mygod

Refactor ShadowsocksConnection

parent 2ca6737f
......@@ -20,7 +20,6 @@
package com.github.shadowsocks
import android.app.Fragment
import android.content.ComponentName
import android.content.Context
import android.content.Intent
......@@ -32,45 +31,30 @@ import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.Action
import java.util.*
class ShadowsocksConnection(private val instance: Interface) : ServiceConnection {
companion object {
private val connections = WeakHashMap<Interface, ShadowsocksConnection>()
}
interface Interface : IBinder.DeathRecipient {
class ShadowsocksConnection(private val callback: Callback, private var listenForDeath: Boolean = false) :
ServiceConnection, IBinder.DeathRecipient {
interface Callback {
val serviceCallback: IShadowsocksServiceCallback? get() = null
val connection: ShadowsocksConnection
get() = connections.getOrPut(this) { ShadowsocksConnection(this) }
val listenForDeath get() = false
fun onServiceConnected(service: IShadowsocksService) { }
fun onServiceConnected(service: IShadowsocksService)
/**
* Different from Android framework, this method will be called even when you call `detachService`.
*/
fun onServiceDisconnected() { }
override fun binderDied() {
connection.service = null
}
fun onBinderDied() { }
}
private var connectionActive = false
private var callbackRegistered = false
private var binder: IBinder? = null
private val context by lazy {
when (instance) {
is Fragment -> instance.activity
else -> instance as Context
}
}
var listeningForBandwidth = false
set(value) {
val service = service
if (listeningForBandwidth != value && service != null && instance.serviceCallback != null)
if (value) service.startListeningForBandwidth(instance.serviceCallback) else try {
service.stopListeningForBandwidth(instance.serviceCallback)
if (listeningForBandwidth != value && service != null && callback.serviceCallback != null)
if (value) service.startListeningForBandwidth(callback.serviceCallback) else try {
service.stopListeningForBandwidth(callback.serviceCallback)
} catch (_: DeadObjectException) { }
field = value
}
......@@ -78,50 +62,54 @@ class ShadowsocksConnection(private val instance: Interface) : ServiceConnection
override fun onServiceConnected(name: ComponentName?, binder: IBinder) {
this.binder = binder
if (instance.listenForDeath) binder.linkToDeath(instance, 0)
if (listenForDeath) binder.linkToDeath(this, 0)
val service = IShadowsocksService.Stub.asInterface(binder)!!
this.service = service
if (instance.serviceCallback != null && !callbackRegistered) try {
service.registerCallback(instance.serviceCallback)
if (callback.serviceCallback != null && !callbackRegistered) try {
service.registerCallback(callback.serviceCallback)
callbackRegistered = true
if (listeningForBandwidth) service.startListeningForBandwidth(instance.serviceCallback)
if (listeningForBandwidth) service.startListeningForBandwidth(callback.serviceCallback)
} catch (_: RemoteException) { }
instance.onServiceConnected(service)
callback.onServiceConnected(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
unregisterCallback()
instance.onServiceDisconnected()
callback.onServiceDisconnected()
service = null
binder = null
}
override fun binderDied() {
service = null
callback.onBinderDied()
}
private fun unregisterCallback() {
val service = service
if (service != null && instance.serviceCallback != null && callbackRegistered) try {
service.unregisterCallback(instance.serviceCallback)
if (service != null && callback.serviceCallback != null && callbackRegistered) try {
service.unregisterCallback(callback.serviceCallback)
} catch (_: RemoteException) { }
callbackRegistered = false
}
fun connect() {
fun connect(context: Context) {
if (connectionActive) return
connectionActive = true
val intent = Intent(context, BaseService.serviceClass.java).setAction(Action.SERVICE)
context.bindService(intent, this, Context.BIND_AUTO_CREATE)
}
fun disconnect() {
fun disconnect(context: Context) {
unregisterCallback()
instance.onServiceDisconnected()
callback.onServiceDisconnected()
if (connectionActive) try {
context.unbindService(this)
} catch (_: IllegalArgumentException) { } // ignore
connectionActive = false
if (instance.listenForDeath) binder?.unlinkToDeath(instance, 0)
if (listenForDeath) binder?.unlinkToDeath(this, 0)
binder = null
if (instance.serviceCallback != null)
service?.stopListeningForBandwidth(instance.serviceCallback)
if (callback.serviceCallback != null) service?.stopListeningForBandwidth(callback.serviceCallback)
service = null
}
}
......@@ -36,12 +36,13 @@ import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.core.R
import com.github.shadowsocks.utils.broadcastReceiver
class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface {
class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Callback {
companion object {
private const val TAG = "VpnRequestActivity"
private const val REQUEST_CONNECT = 1
}
private val connection = ShadowsocksConnection(this)
private var receiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
......@@ -51,9 +52,9 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
return
}
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
receiver = broadcastReceiver { _, _ -> connection.connect() }
receiver = broadcastReceiver { _, _ -> connection.connect(this) }
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
} else connection.connect()
} else connection.connect(this)
}
override fun onServiceConnected(service: IShadowsocksService) {
......@@ -72,7 +73,7 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
override fun onDestroy() {
super.onDestroy()
connection.disconnect()
connection.disconnect(this)
if (receiver != null) unregisterReceiver(receiver)
}
}
......@@ -59,7 +59,7 @@ import com.github.shadowsocks.widget.StatsBar
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPreferenceDataStoreChangeListener,
class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPreferenceDataStoreChangeListener,
NavigationView.OnNavigationItemSelectedListener {
companion object {
private const val TAG = "ShadowsocksMainActivity"
......@@ -130,19 +130,18 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
else -> Core.startService()
}
override val listenForDeath: Boolean get() = true
private val connection = ShadowsocksConnection(this, true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state
} catch (_: DeadObjectException) {
BaseService.IDLE
})
override fun onServiceDisconnected() = changeState(BaseService.IDLE)
override fun binderDied() {
super.binderDied()
override fun onBinderDied() {
Core.handler.post {
connection.disconnect()
connection.disconnect(this)
Executable.killAll()
connection.connect()
connection.connect(this)
}
}
......@@ -174,7 +173,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
fab.setOnClickListener { toggle() }
changeState(BaseService.IDLE) // reset everything to init state
Core.handler.post { connection.connect() }
Core.handler.post { connection.connect(this) }
DataStore.publicStore.registerChangeListener(this)
val intent = this.intent
......@@ -213,8 +212,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
when (key) {
Key.serviceMode -> Core.handler.post {
connection.disconnect()
connection.connect()
connection.disconnect(this)
connection.connect(this)
}
}
}
......@@ -285,7 +284,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
override fun onDestroy() {
super.onDestroy()
DataStore.publicStore.unregisterChangeListener(this)
connection.disconnect()
connection.disconnect(this)
BackupManager(this).dataChanged()
Core.handler.removeCallbacksAndMessages(null)
}
......
......@@ -32,7 +32,9 @@ import androidx.core.graphics.drawable.IconCompat
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService
class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
private val connection = ShadowsocksConnection(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (intent.action == Intent.ACTION_CREATE_SHORTCUT) {
......@@ -44,7 +46,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
.build()))
finish()
} else {
connection.connect()
connection.connect(this)
if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("toggle")
}
}
......@@ -58,7 +60,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
}
override fun onDestroy() {
connection.disconnect()
connection.disconnect(this)
super.onDestroy()
}
}
......@@ -35,13 +35,14 @@ import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.preference.DataStore
@RequiresApi(24)
class TileService : BaseTileService(), ShadowsocksConnection.Interface {
class TileService : BaseTileService(), ShadowsocksConnection.Callback {
private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle) }
private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) }
private val iconConnected by lazy { Icon.createWithResource(this, R.drawable.ic_service_active) }
private val keyguard by lazy { getSystemService<KeyguardManager>()!! }
private var tapPending = false
private val connection = ShadowsocksConnection(this)
override val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
val tile = qsTile ?: return
......@@ -78,10 +79,10 @@ class TileService : BaseTileService(), ShadowsocksConnection.Interface {
override fun onStartListening() {
super.onStartListening()
connection.connect()
connection.connect(this)
}
override fun onStopListening() {
connection.disconnect()
connection.disconnect(this)
super.onStopListening()
}
......
......@@ -55,7 +55,7 @@ import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import com.github.shadowsocks.utils.*
import org.json.JSONArray
class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnection.Interface,
class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnection.Callback,
OnPreferenceDataStoreChangeListener {
companion object {
private const val REQUEST_CONNECT = 1
......@@ -141,19 +141,18 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
}
}
override val listenForDeath: Boolean get() = true
private val connection = ShadowsocksConnection(this, true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state
} catch (_: DeadObjectException) {
BaseService.IDLE
})
override fun onServiceDisconnected() = changeState(BaseService.IDLE)
override fun binderDied() {
super.binderDied()
override fun onBinderDied() {
Core.handler.post {
connection.disconnect()
connection.disconnect(activity)
Executable.killAll()
connection.connect()
connection.connect(activity)
}
}
......@@ -203,7 +202,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
tester = ViewModelProviders.of(activity as FragmentActivity).get()
changeState(BaseService.IDLE) // reset everything to init state
connection.connect()
connection.connect(activity)
DataStore.publicStore.registerChangeListener(this)
}
......@@ -240,8 +239,8 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
when (key) {
Key.serviceMode -> Core.handler.post {
connection.disconnect()
connection.connect()
connection.disconnect(activity)
connection.connect(activity)
}
}
}
......@@ -334,7 +333,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
override fun onDestroy() {
super.onDestroy()
DataStore.publicStore.unregisterChangeListener(this)
connection.disconnect()
connection.disconnect(activity)
BackupManager(activity).dataChanged()
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment