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.support.annotation.StringRes
import android.widget.Toast
import be.mygod.vpnhotspot.util.Event0
class App : Application() {
companion object {
const val ACTION_CLEAN_ROUTINGS = "be.mygod.vpnhotspot.CLEAN_ROUTINGS"
const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
private const val KEY_DNS = "service.dns"
@@ -54,5 +54,7 @@ class App : Application() {
get() = pref.getString(KEY_DNS, "8.8.8.8")
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() }
}

View File

@@ -1,9 +1,5 @@
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 be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.Routing
@@ -11,13 +7,12 @@ import be.mygod.vpnhotspot.net.VpnMonitor
import java.net.InetAddress
import java.net.SocketException
class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetAddress? = null) :
BroadcastReceiver(), VpnMonitor.Callback {
class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetAddress? = null) : VpnMonitor.Callback {
private var routing: Routing? = null
private var dns = emptyList<InetAddress>()
init {
LocalBroadcastManager.getInstance(app).registerReceiver(this, intentFilter(App.ACTION_CLEAN_ROUTINGS))
app.cleanRoutings[this] = this::clean
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)
initRouting(null, routing.hostAddress, emptyList())
}
override fun onReceive(context: Context?, intent: Intent?) {
private fun clean() {
val routing = routing ?: return
routing.started = false
initRouting(routing.upstream, routing.hostAddress, dns)
@@ -59,7 +55,7 @@ class LocalOnlyInterfaceManager(val downstream: String, private val owner: InetA
fun stop() {
VpnMonitor.unregisterCallback(this)
LocalBroadcastManager.getInstance(app).unregisterReceiver(this)
app.cleanRoutings -= this
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.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatDialog
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.net.IpNeighbour
import be.mygod.vpnhotspot.net.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.TetheringManager
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.WifiP2pDialog
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 {
return try {
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
@@ -74,18 +73,14 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
fun onStatusChanged() {
notifyPropertyChanged(BR.switchEnabled)
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)
p2pInterface = group?.`interface`
notifyPropertyChanged(BR.addresses)
adapter.p2p = group?.clientList ?: emptyList()
adapter.recreate()
}
val statusListener = broadcastReceiver { _, _ -> onStatusChanged() }
}
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?) {
val binder = service as RepeaterService.RepeaterBinder
binder.data = data
this.binder = binder
data.onStatusChanged()
LocalBroadcastManager.getInstance(requireContext())
.registerReceiver(data.statusListener, intentFilter(RepeaterService.ACTION_STATUS_CHANGED))
binder.statusChanged[this] = data::onStatusChanged
binder.groupChanged[this] = data::onGroupChanged
}
override fun onServiceDisconnected(name: ComponentName?) {
binder?.data = null
binder = null
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(data.statusListener)
val binder = binder ?: return
binder.statusChanged -= this
binder.groupChanged -= this
this.binder = null
data.onStatusChanged()
data.onGroupChanged()
}
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
@@ -239,13 +234,14 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
private fun editConfigurations() {
val binder = binder
val ssid = binder?.ssid
val group = binder?.service?.group
val ssid = group?.networkName
val context = requireContext()
if (ssid != null) {
val wifi = WifiConfiguration()
val conf = P2pSupplicantConfiguration()
wifi.SSID = ssid
wifi.preSharedKey = binder.password
wifi.preSharedKey = group.passphrase
if (wifi.preSharedKey == null) wifi.preSharedKey = conf.readPsk()
if (wifi.preSharedKey != null) {
var dialog: WifiP2pDialog? = null

View File

@@ -12,7 +12,6 @@ import android.net.wifi.p2p.WifiP2pManager
import android.os.Binder
import android.os.Looper
import android.support.annotation.StringRes
import android.support.v4.content.LocalBroadcastManager
import android.util.Log
import android.widget.Toast
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.setWifiP2pChannels
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.net.InetAddress
class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
const val ACTION_STATUS_CHANGED = "be.mygod.vpnhotspot.RepeaterService.STATUS_CHANGED"
private const val TAG = "RepeaterService"
}
@@ -37,11 +37,9 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
inner class RepeaterBinder : Binder() {
val service get() = this@RepeaterService
var data: RepeaterFragment.Data? = null
val active get() = status == Status.ACTIVE
val ssid get() = group?.networkName
val password get() = group?.passphrase
val statusChanged = StickyEvent0()
val groupChanged = StickyEvent1 { group }
private var groups: Collection<WifiP2pGroup> = emptyList()
@@ -93,7 +91,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
var group: WifiP2pGroup? = null
private set(value) {
field = value
binder.data?.onGroupChanged(value)
binder.groupChanged(value)
}
private val binder = RepeaterBinder()
private var receiverRegistered = false
@@ -114,7 +112,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
private set(value) {
if (field == value) return
field = value
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(ACTION_STATUS_CHANGED))
binder.statusChanged()
}
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,
formatReason(R.string.repeater_remove_group_failure, reason), Toast.LENGTH_SHORT).show()
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.ServiceConnection
import android.graphics.drawable.Icon
import android.net.wifi.p2p.WifiP2pGroup
import android.os.IBinder
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import android.support.annotation.RequiresApi
import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager
@RequiresApi(24)
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 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) {
binder = service as RepeaterService.RepeaterBinder
updateTile()
LocalBroadcastManager.getInstance(this).registerReceiver(statusListener,
intentFilter(RepeaterService.ACTION_STATUS_CHANGED))
val binder = service as RepeaterService.RepeaterBinder
this.binder = binder
binder.statusChanged[this] = { updateTile() }
binder.groupChanged[this] = this::updateTile
}
override fun onServiceDisconnected(name: ComponentName?) {
binder = null
LocalBroadcastManager.getInstance(this).unregisterReceiver(statusListener)
val binder = binder ?: return
this.binder = null
binder.statusChanged -= this
binder.groupChanged -= this
}
private fun updateTile() {
private fun updateTile(group: WifiP2pGroup? = binder?.service?.group) {
val qsTile = qsTile ?: return
when (binder?.service?.status) {
RepeaterService.Status.IDLE -> {
@@ -68,7 +69,7 @@ class RepeaterTileService : TileService(), ServiceConnection {
RepeaterService.Status.ACTIVE -> {
qsTile.state = Tile.STATE_ACTIVE
qsTile.icon = tileOn
qsTile.label = binder?.ssid
qsTile.label = group?.networkName
}
null -> {
qsTile.state = Tile.STATE_UNAVAILABLE

View File

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

View File

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