Add device count to other tiles too
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
package be.mygod.vpnhotspot.manage
|
||||||
|
|
||||||
|
import android.service.quicksettings.Tile
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import be.mygod.vpnhotspot.R
|
||||||
|
import be.mygod.vpnhotspot.net.IpNeighbour
|
||||||
|
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
||||||
|
import be.mygod.vpnhotspot.util.KillableTileService
|
||||||
|
|
||||||
|
@RequiresApi(24)
|
||||||
|
abstract class IpNeighbourMonitoringTileService : KillableTileService(), IpNeighbourMonitor.Callback {
|
||||||
|
private var neighbours: Collection<IpNeighbour> = emptyList()
|
||||||
|
abstract fun updateTile()
|
||||||
|
|
||||||
|
override fun onStartListening() {
|
||||||
|
super.onStartListening()
|
||||||
|
IpNeighbourMonitor.registerCallback(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStopListening() {
|
||||||
|
IpNeighbourMonitor.unregisterCallback(this)
|
||||||
|
super.onStopListening()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun Tile.subtitleDevices(filter: (String) -> Boolean) {
|
||||||
|
val size = neighbours
|
||||||
|
.filter { it.state != IpNeighbour.State.FAILED && filter(it.dev) }
|
||||||
|
.distinctBy { it.lladdr }
|
||||||
|
.size
|
||||||
|
if (size > 0) subtitle(resources.getQuantityString(
|
||||||
|
R.plurals.quick_settings_hotspot_secondary_label_num_devices, size, size))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onIpNeighbourAvailable(neighbours: Collection<IpNeighbour>) {
|
||||||
|
this.neighbours = neighbours
|
||||||
|
updateTile()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,10 @@ import android.service.quicksettings.Tile
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import be.mygod.vpnhotspot.LocalOnlyHotspotService
|
import be.mygod.vpnhotspot.LocalOnlyHotspotService
|
||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.util.KillableTileService
|
|
||||||
import be.mygod.vpnhotspot.util.stopAndUnbind
|
import be.mygod.vpnhotspot.util.stopAndUnbind
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(26)
|
||||||
class LocalOnlyHotspotTileService : KillableTileService() {
|
class LocalOnlyHotspotTileService : IpNeighbourMonitoringTileService() {
|
||||||
private val tile by lazy { Icon.createWithResource(application, R.drawable.ic_action_perm_scan_wifi) }
|
private val tile by lazy { Icon.createWithResource(application, R.drawable.ic_action_perm_scan_wifi) }
|
||||||
|
|
||||||
private var binder: LocalOnlyHotspotService.Binder? = null
|
private var binder: LocalOnlyHotspotService.Binder? = null
|
||||||
@@ -28,6 +27,24 @@ class LocalOnlyHotspotTileService : KillableTileService() {
|
|||||||
super.onStopListening()
|
super.onStopListening()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateTile() {
|
||||||
|
val binder = binder ?: return
|
||||||
|
qsTile?.run {
|
||||||
|
icon = tile
|
||||||
|
subtitle(null)
|
||||||
|
val iface = binder.iface
|
||||||
|
if (iface.isNullOrEmpty()) {
|
||||||
|
state = Tile.STATE_INACTIVE
|
||||||
|
label = getText(R.string.tethering_temp_hotspot)
|
||||||
|
} else {
|
||||||
|
state = Tile.STATE_ACTIVE
|
||||||
|
label = binder.configuration?.ssid ?: getText(R.string.tethering_temp_hotspot)
|
||||||
|
subtitleDevices { it == iface }
|
||||||
|
}
|
||||||
|
updateTile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onClick() {
|
override fun onClick() {
|
||||||
val binder = binder
|
val binder = binder
|
||||||
when {
|
when {
|
||||||
@@ -39,19 +56,7 @@ class LocalOnlyHotspotTileService : KillableTileService() {
|
|||||||
|
|
||||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
binder = service as LocalOnlyHotspotService.Binder
|
binder = service as LocalOnlyHotspotService.Binder
|
||||||
service.ifaceChanged[this] = {
|
service.ifaceChanged[this] = { updateTile() }
|
||||||
qsTile?.run {
|
|
||||||
icon = tile
|
|
||||||
if (it.isNullOrEmpty()) {
|
|
||||||
state = Tile.STATE_INACTIVE
|
|
||||||
label = getText(R.string.tethering_temp_hotspot)
|
|
||||||
} else {
|
|
||||||
state = Tile.STATE_ACTIVE
|
|
||||||
label = service.configuration?.ssid ?: getText(R.string.tethering_temp_hotspot)
|
|
||||||
}
|
|
||||||
updateTile()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onServiceConnected(name, service)
|
super.onServiceConnected(name, service)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import be.mygod.vpnhotspot.net.TetherType
|
|||||||
import be.mygod.vpnhotspot.net.TetheringManager
|
import be.mygod.vpnhotspot.net.TetheringManager
|
||||||
import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces
|
import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
||||||
import be.mygod.vpnhotspot.util.KillableTileService
|
|
||||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||||
import be.mygod.vpnhotspot.util.readableMessage
|
import be.mygod.vpnhotspot.util.readableMessage
|
||||||
import be.mygod.vpnhotspot.util.stopAndUnbind
|
import be.mygod.vpnhotspot.util.stopAndUnbind
|
||||||
@@ -26,14 +25,14 @@ import java.io.IOException
|
|||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
@RequiresApi(24)
|
@RequiresApi(24)
|
||||||
sealed class TetheringTileService : KillableTileService(), TetheringManager.StartTetheringCallback {
|
sealed class TetheringTileService : IpNeighbourMonitoringTileService(), TetheringManager.StartTetheringCallback {
|
||||||
protected val tileOff by lazy { Icon.createWithResource(application, icon) }
|
protected val tileOff by lazy { Icon.createWithResource(application, icon) }
|
||||||
protected val tileOn by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_on) }
|
protected val tileOn by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_on) }
|
||||||
|
|
||||||
protected abstract val labelString: Int
|
protected abstract val labelString: Int
|
||||||
protected abstract val tetherType: TetherType
|
protected abstract val tetherType: TetherType
|
||||||
protected open val icon get() = tetherType.icon
|
protected open val icon get() = tetherType.icon
|
||||||
protected var tethered: List<String>? = null
|
private var tethered: List<String>? = null
|
||||||
protected val interested get() = tethered?.filter { TetherType.ofInterface(it) == tetherType }
|
protected val interested get() = tethered?.filter { TetherType.ofInterface(it) == tetherType }
|
||||||
protected var binder: TetheringService.Binder? = null
|
protected var binder: TetheringService.Binder? = null
|
||||||
|
|
||||||
@@ -73,8 +72,9 @@ sealed class TetheringTileService : KillableTileService(), TetheringManager.Star
|
|||||||
binder = null
|
binder = null
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun updateTile() {
|
override fun updateTile() {
|
||||||
qsTile?.run {
|
qsTile?.run {
|
||||||
|
subtitle(null)
|
||||||
val interested = interested
|
val interested = interested
|
||||||
when {
|
when {
|
||||||
interested == null -> {
|
interested == null -> {
|
||||||
@@ -89,6 +89,7 @@ sealed class TetheringTileService : KillableTileService(), TetheringManager.Star
|
|||||||
val binder = binder ?: return
|
val binder = binder ?: return
|
||||||
state = Tile.STATE_ACTIVE
|
state = Tile.STATE_ACTIVE
|
||||||
icon = if (interested.all(binder::isActive)) tileOn else tileOff
|
icon = if (interested.all(binder::isActive)) tileOn else tileOff
|
||||||
|
subtitleDevices(interested::contains)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
label = getText(labelString)
|
label = getText(labelString)
|
||||||
@@ -172,6 +173,7 @@ sealed class TetheringTileService : KillableTileService(), TetheringManager.Star
|
|||||||
|
|
||||||
override fun updateTile() {
|
override fun updateTile() {
|
||||||
qsTile?.run {
|
qsTile?.run {
|
||||||
|
subtitle(null)
|
||||||
val interested = interested
|
val interested = interested
|
||||||
if (interested == null) {
|
if (interested == null) {
|
||||||
state = Tile.STATE_UNAVAILABLE
|
state = Tile.STATE_UNAVAILABLE
|
||||||
@@ -181,6 +183,7 @@ sealed class TetheringTileService : KillableTileService(), TetheringManager.Star
|
|||||||
val binder = binder ?: return
|
val binder = binder ?: return
|
||||||
state = Tile.STATE_ACTIVE
|
state = Tile.STATE_ACTIVE
|
||||||
icon = if (interested.isNotEmpty() && interested.all(binder::isActive)) tileOn else tileOff
|
icon = if (interested.isNotEmpty() && interested.all(binder::isActive)) tileOn else tileOff
|
||||||
|
subtitleDevices(interested::contains)
|
||||||
}
|
}
|
||||||
false -> {
|
false -> {
|
||||||
state = Tile.STATE_INACTIVE
|
state = Tile.STATE_INACTIVE
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ enum class TetherType(@DrawableRes val icon: Int) {
|
|||||||
.map { it.toPattern() }
|
.map { it.toPattern() }
|
||||||
|
|
||||||
@RequiresApi(30)
|
@RequiresApi(30)
|
||||||
private fun updateRegexs() {
|
private fun updateRegexs() = synchronized(this) {
|
||||||
|
if (!requiresUpdate) return@synchronized
|
||||||
requiresUpdate = false
|
requiresUpdate = false
|
||||||
TetheringManager.registerTetheringEventCallback(null, this)
|
TetheringManager.registerTetheringEventCallback(null, this)
|
||||||
val tethering = "com.android.networkstack.tethering" to app.packageManager.getResourcesForApplication(
|
val tethering = "com.android.networkstack.tethering" to app.packageManager.getResourcesForApplication(
|
||||||
@@ -59,7 +60,8 @@ enum class TetherType(@DrawableRes val icon: Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(30)
|
@RequiresApi(30)
|
||||||
override fun onTetherableInterfaceRegexpsChanged(args: Array<out Any?>?) {
|
override fun onTetherableInterfaceRegexpsChanged(args: Array<out Any?>?) = synchronized(this) {
|
||||||
|
if (requiresUpdate) return@synchronized
|
||||||
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentToString()}")
|
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentToString()}")
|
||||||
TetheringManager.unregisterTetheringEventCallback(this)
|
TetheringManager.unregisterTetheringEventCallback(this)
|
||||||
requiresUpdate = true
|
requiresUpdate = true
|
||||||
@@ -92,6 +94,7 @@ enum class TetherType(@DrawableRes val icon: Int) {
|
|||||||
iface == null -> NONE
|
iface == null -> NONE
|
||||||
iface == p2pDev -> WIFI_P2P
|
iface == p2pDev -> WIFI_P2P
|
||||||
requiresUpdate -> {
|
requiresUpdate -> {
|
||||||
|
Timber.d("requiresUpdate")
|
||||||
if (Build.VERSION.SDK_INT >= 30) updateRegexs() else error("unexpected requiresUpdate")
|
if (Build.VERSION.SDK_INT >= 30) updateRegexs() else error("unexpected requiresUpdate")
|
||||||
ofInterface(iface, p2pDev)
|
ofInterface(iface, p2pDev)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user