diff --git a/build.gradle b/build.gradle
index 527e29ff..0f13fc70 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,6 +5,7 @@ apply plugin: 'com.github.ben-manes.versions'
buildscript {
ext {
kotlinVersion = '1.3.11'
+ lifecycleVersion = '2.0.0'
roomVersion = '2.0.0'
}
repositories {
diff --git a/mobile/build.gradle b/mobile/build.gradle
index c5e8081d..a55981aa 100644
--- a/mobile/build.gradle
+++ b/mobile/build.gradle
@@ -58,11 +58,14 @@ android {
}
dependencies {
+ kapt "androidx.lifecycle:lifecycle-compiler:$lifecycleVersion"
kapt "androidx.room:room-compiler:$roomVersion"
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.browser:browser:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
implementation "androidx.core:core-ktx:1.0.1"
+ implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
implementation "androidx.preference:preference:1.0.0"
implementation "androidx.room:room-runtime:$roomVersion"
implementation 'com.github.luongvo:BadgeView:1.1.5'
@@ -74,6 +77,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
baseImplementation 'com.android.billingclient:billing:1.2'
baseImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.7'
+ testImplementation "androidx.arch.core:core-testing:$lifecycleVersion"
testImplementation "androidx.room:room-testing:$roomVersion"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml
index d708600d..29528d78 100644
--- a/mobile/src/main/AndroidManifest.xml
+++ b/mobile/src/main/AndroidManifest.xml
@@ -82,7 +82,6 @@
-
()
+ if (RepeaterService.supported) ServiceForegroundConnector(this, model, RepeaterService::class)
+ model.clients.observe(this, Observer> { badge.badgeNumber = it.size })
SmartSnackbar.Register(lifecycle, binding.fragmentHolder)
}
@@ -85,17 +87,6 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
else -> false
}
- override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
- clients = service as ClientMonitorService.Binder
- service.clientsChanged[this] = { badge.badgeNumber = it.size }
- }
-
- override fun onServiceDisconnected(name: ComponentName?) {
- val clients = clients ?: return
- this.clients = null
- clients.clientsChanged -= this
- }
-
private fun displayFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().replace(R.id.fragmentHolder, fragment).commitAllowingStateLoss()
diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt
similarity index 69%
rename from mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt
rename to mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt
index 19b7acfa..44d155b4 100644
--- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientMonitorService.kt
+++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientViewModel.kt
@@ -1,24 +1,20 @@
package be.mygod.vpnhotspot.client
-import android.app.Service
-import android.content.*
+import android.content.ComponentName
+import android.content.IntentFilter
+import android.content.ServiceConnection
import android.net.wifi.p2p.WifiP2pDevice
import android.os.IBinder
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.RepeaterService
import be.mygod.vpnhotspot.net.IpNeighbour
-import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.TetheringManager
-import be.mygod.vpnhotspot.util.StickyEvent1
+import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
import be.mygod.vpnhotspot.util.broadcastReceiver
-import be.mygod.vpnhotspot.util.stopAndUnbind
-
-class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Callback {
- inner class Binder : android.os.Binder() {
- val clientsChanged = StickyEvent1 { clients }
- }
- private val binder = Binder()
- override fun onBind(intent: Intent?) = binder
+class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callback {
private var tetheredInterfaces = emptySet()
private val receiver = broadcastReceiver { _, intent ->
val extras = intent.extras ?: return@broadcastReceiver
@@ -30,11 +26,7 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca
private var repeater: RepeaterService.Binder? = null
private var p2p: Collection = emptyList()
private var neighbours = emptyList()
- private var clients = emptyList()
- private set(value) {
- field = value
- binder.clientsChanged(value)
- }
+ val clients = MutableLiveData>()
private fun populateClients() {
val clients = HashMap, Client>()
@@ -53,7 +45,7 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca
}
client.ip += Pair(neighbour.ip, neighbour.state)
}
- this.clients = clients.values.sortedWith(compareBy { it.iface }.thenBy { it.mac })
+ this.clients.postValue(clients.values.sortedWith(compareBy { it.iface }.thenBy { it.mac }))
}
private fun refreshP2p() {
@@ -62,20 +54,14 @@ class ClientMonitorService : Service(), ServiceConnection, IpNeighbourMonitor.Ca
populateClients()
}
- override fun onCreate() {
- super.onCreate()
- if (RepeaterService.supported) {
- bindService(Intent(this, RepeaterService::class.java), this, Context.BIND_AUTO_CREATE)
- }
+ init {
+ app.registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
IpNeighbourMonitor.registerCallback(this)
- registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
}
- override fun onDestroy() {
- unregisterReceiver(receiver)
+ override fun onCleared() {
IpNeighbourMonitor.unregisterCallback(this)
- if (RepeaterService.supported) stopAndUnbind(this)
- super.onDestroy()
+ app.unregisterReceiver(receiver)
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt
index d8632025..0ff5b681 100644
--- a/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt
+++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/ClientsFragment.kt
@@ -1,10 +1,7 @@
package be.mygod.vpnhotspot.client
-import android.content.ComponentName
import android.content.DialogInterface
-import android.content.ServiceConnection
import android.os.Bundle
-import android.os.IBinder
import android.text.format.DateUtils
import android.text.format.Formatter
import android.util.LongSparseArray
@@ -19,6 +16,9 @@ import androidx.core.os.bundleOf
import androidx.databinding.BaseObservable
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProviders
+import androidx.lifecycle.get
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
@@ -31,13 +31,12 @@ import be.mygod.vpnhotspot.databinding.ListitemClientBinding
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.monitor.TrafficRecorder
import be.mygod.vpnhotspot.room.*
-import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.computeIfAbsentCompat
import be.mygod.vpnhotspot.util.toPluralInt
import be.mygod.vpnhotspot.widget.SmartSnackbar
import java.text.NumberFormat
-class ClientsFragment : Fragment(), ServiceConnection {
+class ClientsFragment : Fragment() {
class NicknameDialogFragment : AlertDialogFragment() {
companion object {
const val KEY_MAC = "mac"
@@ -198,7 +197,6 @@ class ClientsFragment : Fragment(), ServiceConnection {
private lateinit var binding: FragmentClientsBinding
private val adapter = ClientAdapter()
- private var clients: ClientMonitorService.Binder? = null
private var rates = HashMap, TrafficRate>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -210,21 +208,11 @@ class ClientsFragment : Fragment(), ServiceConnection {
binding.swipeRefresher.setOnRefreshListener {
IpNeighbourMonitor.instance?.flush()
}
- ServiceForegroundConnector(this, this, ClientMonitorService::class)
+ ViewModelProviders.of(requireActivity()).get().clients.observe(this,
+ Observer> { adapter.submitList(it.toMutableList()) })
return binding.root
}
- override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
- clients = service as ClientMonitorService.Binder
- service.clientsChanged[this] = { adapter.submitList(it.toMutableList()) }
- }
-
- override fun onServiceDisconnected(name: ComponentName?) {
- val clients = clients ?: return
- clients.clientsChanged -= this
- this.clients = null
- }
-
override fun onStart() {
super.onStart()
// we just put these two thing together as this is the only place we need to use this event for now