From e72dad879031cb51a61dc202c4d81726231f5cd7 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 9 May 2018 15:56:37 -0700 Subject: [PATCH] Stop using LocalBroadcastManager --- .../src/main/java/be/mygod/vpnhotspot/App.kt | 4 ++- .../vpnhotspot/LocalOnlyInterfaceManager.kt | 14 +++----- .../be/mygod/vpnhotspot/RepeaterFragment.kt | 30 +++++++--------- .../be/mygod/vpnhotspot/RepeaterService.kt | 15 ++++---- .../mygod/vpnhotspot/RepeaterTileService.kt | 21 ++++++------ .../vpnhotspot/SettingsPreferenceFragment.kt | 5 +-- .../be/mygod/vpnhotspot/TetheringService.kt | 22 ++++++------ .../java/be/mygod/vpnhotspot/util/Events.kt | 34 +++++++++++++++++++ 8 files changed, 83 insertions(+), 62 deletions(-) create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/util/Events.kt diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt index 34fde065..4b3cee5d 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt @@ -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() } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyInterfaceManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyInterfaceManager.kt index d3dee1a8..e106e9ea 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyInterfaceManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/LocalOnlyInterfaceManager.kt @@ -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() 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) } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt index 78a446d8..b790c474 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterFragment.kt @@ -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 diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index 1e9fb4cf..b6a08e67 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -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 = 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)) } } }) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterTileService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterTileService.kt index 0d9dc302..5e979a25 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterTileService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterTileService.kt @@ -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 diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt index 84455d45..1f6e9189 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt @@ -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 { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt index 8ea5413e..3db34e65 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/TetheringService.kt @@ -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 - } + 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() 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 diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/Events.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/Events.kt new file mode 100644 index 00000000..d6e39beb --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/Events.kt @@ -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 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 : ConcurrentHashMap Unit>() { + operator fun invoke(arg: T) { + for ((_, handler) in this) handler(arg) + } +} + +class StickyEvent1(private val fire: () -> T) : Event1() { + override fun put(key: Any, value: (T) -> Unit): ((T) -> Unit)? { + val result = super.put(key, value) + if (result == null) value(fire()) + return result + } +}