Stop using LocalBroadcastManager

This commit is contained in:
Mygod
2018-05-09 15:56:37 -07:00
parent 1695295eb3
commit e72dad8790
8 changed files with 83 additions and 62 deletions

View File

@@ -12,10 +12,10 @@ import android.os.Handler
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.widget.Toast import android.widget.Toast
import be.mygod.vpnhotspot.util.Event0
class App : Application() { class App : Application() {
companion object { companion object {
const val ACTION_CLEAN_ROUTINGS = "be.mygod.vpnhotspot.CLEAN_ROUTINGS"
const val KEY_OPERATING_CHANNEL = "service.repeater.oc" const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
private const val KEY_DNS = "service.dns" private const val KEY_DNS = "service.dns"
@@ -54,5 +54,7 @@ class App : Application() {
get() = pref.getString(KEY_DNS, "8.8.8.8") get() = pref.getString(KEY_DNS, "8.8.8.8")
set(value) = pref.edit().putString(KEY_DNS, value).apply() set(value) = pref.edit().putString(KEY_DNS, value).apply()
val cleanRoutings = Event0()
fun toast(@StringRes resId: Int) = handler.post { Toast.makeText(this, resId, Toast.LENGTH_SHORT).show() } fun toast(@StringRes resId: Int) = handler.post { Toast.makeText(this, resId, Toast.LENGTH_SHORT).show() }
} }

View File

@@ -1,9 +1,5 @@
package be.mygod.vpnhotspot package be.mygod.vpnhotspot
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.support.v4.content.LocalBroadcastManager
import android.widget.Toast import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.Routing import be.mygod.vpnhotspot.net.Routing
@@ -11,13 +7,12 @@ import be.mygod.vpnhotspot.net.VpnMonitor
import java.net.InetAddress import java.net.InetAddress
import java.net.SocketException import java.net.SocketException
class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetAddress? = null) : class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetAddress? = null) : VpnMonitor.Callback {
BroadcastReceiver(), VpnMonitor.Callback {
private var routing: Routing? = null private var routing: Routing? = null
private var dns = emptyList<InetAddress>() private var dns = emptyList<InetAddress>()
init { init {
LocalBroadcastManager.getInstance(app).registerReceiver(this, intentFilter(App.ACTION_CLEAN_ROUTINGS)) app.cleanRoutings[this] = this::clean
VpnMonitor.registerCallback(this) { initRouting() } VpnMonitor.registerCallback(this) { initRouting() }
} }
@@ -34,7 +29,8 @@ class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetA
if (!routing.stop()) app.toast(R.string.noisy_su_failure) if (!routing.stop()) app.toast(R.string.noisy_su_failure)
initRouting(null, routing.hostAddress, emptyList()) initRouting(null, routing.hostAddress, emptyList())
} }
override fun onReceive(context: Context?, intent: Intent?) {
private fun clean() {
val routing = routing ?: return val routing = routing ?: return
routing.started = false routing.started = false
initRouting(routing.upstream, routing.hostAddress, dns) initRouting(routing.upstream, routing.hostAddress, dns)
@@ -59,7 +55,7 @@ class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetA
fun stop() { fun stop() {
VpnMonitor.unregisterCallback(this) VpnMonitor.unregisterCallback(this)
LocalBroadcastManager.getInstance(app).unregisterReceiver(this) app.cleanRoutings -= this
if (routing?.stop() == false) app.toast(R.string.noisy_su_failure) if (routing?.stop() == false) app.toast(R.string.noisy_su_failure)
} }
} }

View File

@@ -11,7 +11,6 @@ import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatDialog import android.support.v7.app.AppCompatDialog
import android.support.v7.recyclerview.extensions.ListAdapter import android.support.v7.recyclerview.extensions.ListAdapter
@@ -28,8 +27,8 @@ import be.mygod.vpnhotspot.databinding.FragmentRepeaterBinding
import be.mygod.vpnhotspot.databinding.ListitemClientBinding import be.mygod.vpnhotspot.databinding.ListitemClientBinding
import be.mygod.vpnhotspot.net.IpNeighbour import be.mygod.vpnhotspot.net.IpNeighbour
import be.mygod.vpnhotspot.net.IpNeighbourMonitor import be.mygod.vpnhotspot.net.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration import be.mygod.vpnhotspot.net.wifi.P2pSupplicantConfiguration
import be.mygod.vpnhotspot.net.wifi.WifiP2pDialog import be.mygod.vpnhotspot.net.wifi.WifiP2pDialog
import java.net.NetworkInterface import java.net.NetworkInterface
@@ -61,7 +60,7 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
} }
} }
val ssid @Bindable get() = binder?.ssid ?: getText(R.string.service_inactive) val ssid @Bindable get() = binder?.service?.group?.networkName ?: getText(R.string.service_inactive)
val addresses @Bindable get(): String { val addresses @Bindable get(): String {
return try { return try {
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: "" NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
@@ -74,18 +73,14 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
fun onStatusChanged() { fun onStatusChanged() {
notifyPropertyChanged(BR.switchEnabled) notifyPropertyChanged(BR.switchEnabled)
notifyPropertyChanged(BR.serviceStarted) notifyPropertyChanged(BR.serviceStarted)
val binder = binder
onGroupChanged(if (binder?.active == true) binder.service.group else null)
} }
fun onGroupChanged(group: WifiP2pGroup?) { fun onGroupChanged(group: WifiP2pGroup? = binder?.service?.group) {
notifyPropertyChanged(BR.ssid) notifyPropertyChanged(BR.ssid)
p2pInterface = group?.`interface` p2pInterface = group?.`interface`
notifyPropertyChanged(BR.addresses) notifyPropertyChanged(BR.addresses)
adapter.p2p = group?.clientList ?: emptyList() adapter.p2p = group?.clientList ?: emptyList()
adapter.recreate() adapter.recreate()
} }
val statusListener = broadcastReceiver { _, _ -> onStatusChanged() }
} }
inner class Client(p2p: WifiP2pDevice? = null, neighbour: IpNeighbour? = null) { inner class Client(p2p: WifiP2pDevice? = null, neighbour: IpNeighbour? = null) {
@@ -202,18 +197,18 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
override fun onServiceConnected(name: ComponentName?, service: IBinder?) { override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binder = service as RepeaterService.RepeaterBinder val binder = service as RepeaterService.RepeaterBinder
binder.data = data
this.binder = binder this.binder = binder
data.onStatusChanged() binder.statusChanged[this] = data::onStatusChanged
LocalBroadcastManager.getInstance(requireContext()) binder.groupChanged[this] = data::onGroupChanged
.registerReceiver(data.statusListener, intentFilter(RepeaterService.ACTION_STATUS_CHANGED))
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
binder?.data = null val binder = binder ?: return
binder = null binder.statusChanged -= this
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(data.statusListener) binder.groupChanged -= this
this.binder = null
data.onStatusChanged() data.onStatusChanged()
data.onGroupChanged()
} }
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) { override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
@@ -239,13 +234,14 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
private fun editConfigurations() { private fun editConfigurations() {
val binder = binder val binder = binder
val ssid = binder?.ssid val group = binder?.service?.group
val ssid = group?.networkName
val context = requireContext() val context = requireContext()
if (ssid != null) { if (ssid != null) {
val wifi = WifiConfiguration() val wifi = WifiConfiguration()
val conf = P2pSupplicantConfiguration() val conf = P2pSupplicantConfiguration()
wifi.SSID = ssid wifi.SSID = ssid
wifi.preSharedKey = binder.password wifi.preSharedKey = group.passphrase
if (wifi.preSharedKey == null) wifi.preSharedKey = conf.readPsk() if (wifi.preSharedKey == null) wifi.preSharedKey = conf.readPsk()
if (wifi.preSharedKey != null) { if (wifi.preSharedKey != null) {
var dialog: WifiP2pDialog? = null var dialog: WifiP2pDialog? = null

View File

@@ -12,7 +12,6 @@ import android.net.wifi.p2p.WifiP2pManager
import android.os.Binder import android.os.Binder
import android.os.Looper import android.os.Looper
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.support.v4.content.LocalBroadcastManager
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
@@ -22,12 +21,13 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.netId
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
import be.mygod.vpnhotspot.util.StickyEvent0
import be.mygod.vpnhotspot.util.StickyEvent1
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.InetAddress import java.net.InetAddress
class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener { class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener {
companion object { companion object {
const val ACTION_STATUS_CHANGED = "be.mygod.vpnhotspot.RepeaterService.STATUS_CHANGED"
private const val TAG = "RepeaterService" private const val TAG = "RepeaterService"
} }
@@ -37,11 +37,9 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
inner class RepeaterBinder : Binder() { inner class RepeaterBinder : Binder() {
val service get() = this@RepeaterService val service get() = this@RepeaterService
var data: RepeaterFragment.Data? = null
val active get() = status == Status.ACTIVE val active get() = status == Status.ACTIVE
val statusChanged = StickyEvent0()
val ssid get() = group?.networkName val groupChanged = StickyEvent1 { group }
val password get() = group?.passphrase
private var groups: Collection<WifiP2pGroup> = emptyList() private var groups: Collection<WifiP2pGroup> = emptyList()
@@ -93,7 +91,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
var group: WifiP2pGroup? = null var group: WifiP2pGroup? = null
private set(value) { private set(value) {
field = value field = value
binder.data?.onGroupChanged(value) binder.groupChanged(value)
} }
private val binder = RepeaterBinder() private val binder = RepeaterBinder()
private var receiverRegistered = false private var receiverRegistered = false
@@ -114,7 +112,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
private set(value) { private set(value) {
if (field == value) return if (field == value) return
field = value field = value
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(ACTION_STATUS_CHANGED)) binder.statusChanged()
} }
private fun formatReason(@StringRes resId: Int, reason: Int) = getString(resId, when (reason) { private fun formatReason(@StringRes resId: Int, reason: Int) = getString(resId, when (reason) {
@@ -245,7 +243,6 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
Toast.makeText(this@RepeaterService, Toast.makeText(this@RepeaterService,
formatReason(R.string.repeater_remove_group_failure, reason), Toast.LENGTH_SHORT).show() formatReason(R.string.repeater_remove_group_failure, reason), Toast.LENGTH_SHORT).show()
status = Status.ACTIVE status = Status.ACTIVE
LocalBroadcastManager.getInstance(this@RepeaterService).sendBroadcast(Intent(ACTION_STATUS_CHANGED))
} }
} }
}) })

View File

@@ -5,16 +5,15 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.net.wifi.p2p.WifiP2pGroup
import android.os.IBinder import android.os.IBinder
import android.service.quicksettings.Tile import android.service.quicksettings.Tile
import android.service.quicksettings.TileService import android.service.quicksettings.TileService
import android.support.annotation.RequiresApi import android.support.annotation.RequiresApi
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager
@RequiresApi(24) @RequiresApi(24)
class RepeaterTileService : TileService(), ServiceConnection { class RepeaterTileService : TileService(), ServiceConnection {
private val statusListener = broadcastReceiver { _, _ -> updateTile() }
private val tileOff by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_off) } private val tileOff by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_off) }
private val tileOn by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_on) } private val tileOn by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_on) }
@@ -41,18 +40,20 @@ class RepeaterTileService : TileService(), ServiceConnection {
} }
override fun onServiceConnected(name: ComponentName?, service: IBinder) { override fun onServiceConnected(name: ComponentName?, service: IBinder) {
binder = service as RepeaterService.RepeaterBinder val binder = service as RepeaterService.RepeaterBinder
updateTile() this.binder = binder
LocalBroadcastManager.getInstance(this).registerReceiver(statusListener, binder.statusChanged[this] = { updateTile() }
intentFilter(RepeaterService.ACTION_STATUS_CHANGED)) binder.groupChanged[this] = this::updateTile
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
binder = null val binder = binder ?: return
LocalBroadcastManager.getInstance(this).unregisterReceiver(statusListener) this.binder = null
binder.statusChanged -= this
binder.groupChanged -= this
} }
private fun updateTile() { private fun updateTile(group: WifiP2pGroup? = binder?.service?.group) {
val qsTile = qsTile ?: return val qsTile = qsTile ?: return
when (binder?.service?.status) { when (binder?.service?.status) {
RepeaterService.Status.IDLE -> { RepeaterService.Status.IDLE -> {
@@ -68,7 +69,7 @@ class RepeaterTileService : TileService(), ServiceConnection {
RepeaterService.Status.ACTIVE -> { RepeaterService.Status.ACTIVE -> {
qsTile.state = Tile.STATE_ACTIVE qsTile.state = Tile.STATE_ACTIVE
qsTile.icon = tileOn qsTile.icon = tileOn
qsTile.label = binder?.ssid qsTile.label = group?.networkName
} }
null -> { null -> {
qsTile.state = Tile.STATE_UNAVAILABLE qsTile.state = Tile.STATE_UNAVAILABLE

View File

@@ -8,7 +8,6 @@ import android.os.Bundle
import android.support.customtabs.CustomTabsIntent import android.support.customtabs.CustomTabsIntent
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.content.FileProvider import android.support.v4.content.FileProvider
import android.support.v4.content.LocalBroadcastManager
import android.widget.Toast import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.Routing import be.mygod.vpnhotspot.net.Routing
@@ -30,9 +29,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompatDividers() {
findPreference("service.clean").setOnPreferenceClickListener { findPreference("service.clean").setOnPreferenceClickListener {
if (Routing.clean() == null) { if (Routing.clean() == null) {
Toast.makeText(requireContext(), R.string.root_unavailable, Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), R.string.root_unavailable, Toast.LENGTH_SHORT).show()
} else { } else app.cleanRoutings()
LocalBroadcastManager.getInstance(requireContext()).sendBroadcastSync(Intent(App.ACTION_CLEAN_ROUTINGS))
}
true true
} }
findPreference("misc.logcat").setOnPreferenceClickListener { findPreference("misc.logcat").setOnPreferenceClickListener {

View File

@@ -2,7 +2,6 @@ package be.mygod.vpnhotspot
import android.content.Intent import android.content.Intent
import android.os.Binder import android.os.Binder
import android.support.v4.content.LocalBroadcastManager
import android.widget.Toast import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.IpNeighbourMonitor import be.mygod.vpnhotspot.net.IpNeighbourMonitor
@@ -31,14 +30,9 @@ class TetheringService : IpNeighbourMonitoringService(), VpnMonitor.Callback {
private var receiverRegistered = false private var receiverRegistered = false
private val receiver = broadcastReceiver { _, intent -> private val receiver = broadcastReceiver { _, intent ->
synchronized(routings) { synchronized(routings) {
when (intent.action) { val failed = (routings.keys - TetheringManager.getTetheredIfaces(intent.extras))
TetheringManager.ACTION_TETHER_STATE_CHANGED -> { .any { routings.remove(it)?.stop() == false }
val failed = (routings.keys - TetheringManager.getTetheredIfaces(intent.extras)) if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
.any { routings.remove(it)?.stop() == false }
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
}
App.ACTION_CLEAN_ROUTINGS -> for (iface in routings.keys) routings[iface] = null
}
updateRoutingsLocked() updateRoutingsLocked()
} }
} }
@@ -63,8 +57,12 @@ class TetheringService : IpNeighbourMonitoringService(), VpnMonitor.Callback {
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show() if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
} else if (!receiverRegistered) { } else if (!receiverRegistered) {
registerReceiver(receiver, intentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED)) registerReceiver(receiver, intentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
LocalBroadcastManager.getInstance(this) app.cleanRoutings[this] = {
.registerReceiver(receiver, intentFilter(App.ACTION_CLEAN_ROUTINGS)) synchronized(routings) {
for (iface in routings.keys) routings[iface] = null
updateRoutingsLocked()
}
}
IpNeighbourMonitor.registerCallback(this) IpNeighbourMonitor.registerCallback(this)
VpnMonitor.registerCallback(this) VpnMonitor.registerCallback(this)
receiverRegistered = true receiverRegistered = true
@@ -121,7 +119,7 @@ class TetheringService : IpNeighbourMonitoringService(), VpnMonitor.Callback {
private fun unregisterReceiver() { private fun unregisterReceiver() {
if (receiverRegistered) { if (receiverRegistered) {
unregisterReceiver(receiver) unregisterReceiver(receiver)
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver) app.cleanRoutings -= this
IpNeighbourMonitor.unregisterCallback(this) IpNeighbourMonitor.unregisterCallback(this)
VpnMonitor.unregisterCallback(this) VpnMonitor.unregisterCallback(this)
upstream = null upstream = null

View File

@@ -0,0 +1,34 @@
package be.mygod.vpnhotspot.util
import java.util.concurrent.ConcurrentHashMap
/**
* These class are based off https://github.com/1blustone/kotlin-events.
*/
open class Event0 : ConcurrentHashMap<Any, () -> Unit>() {
operator fun invoke() {
for ((_, handler) in this) handler()
}
}
class StickyEvent0 : Event0() {
override fun put(key: Any, value: () -> Unit): (() -> Unit)? {
val result = super.put(key, value)
if (result == null) value()
return result
}
}
open class Event1<T> : ConcurrentHashMap<Any, (T) -> Unit>() {
operator fun invoke(arg: T) {
for ((_, handler) in this) handler(arg)
}
}
class StickyEvent1<T>(private val fire: () -> T) : Event1<T>() {
override fun put(key: Any, value: (T) -> Unit): ((T) -> Unit)? {
val result = super.put(key, value)
if (result == null) value(fire())
return result
}
}