Improve quick settings tiles reliability

Android apparently can decide to kill TileService when there are too many. Therefore, let's check if our service is connected before doing anything.

Source: https://android.googlesource.com/platform/frameworks/base/+/e1d13c9/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java#52
This commit is contained in:
Mygod
2018-12-25 12:17:43 +08:00
parent 426b93226d
commit 36b0284573
5 changed files with 50 additions and 23 deletions

View File

@@ -3,7 +3,6 @@ package be.mygod.vpnhotspot.manage
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.drawable.Icon
import android.os.IBinder
import android.service.quicksettings.Tile
@@ -14,7 +13,7 @@ import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.util.stopAndUnbind
@RequiresApi(26)
class LocalOnlyHotspotTileService : TetherListeningTileService(), ServiceConnection {
class LocalOnlyHotspotTileService : TetherListeningTileService() {
private val tile by lazy { Icon.createWithResource(application, R.drawable.ic_device_wifi_tethering) }
private var binder: LocalOnlyHotspotService.Binder? = null
@@ -30,13 +29,17 @@ class LocalOnlyHotspotTileService : TetherListeningTileService(), ServiceConnect
override fun onClick() {
val binder = binder
if (binder?.iface != null) binder.stop()
else ContextCompat.startForegroundService(this, Intent(this, LocalOnlyHotspotService::class.java))
when {
binder == null -> tapPending = true
binder.iface != null -> binder.stop()
else -> ContextCompat.startForegroundService(this, Intent(this, LocalOnlyHotspotService::class.java))
}
}
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
binder = service as LocalOnlyHotspotService.Binder
updateTile()
super.onServiceConnected(name, service)
}
override fun onServiceDisconnected(name: ComponentName?) {

View File

@@ -3,20 +3,19 @@ package be.mygod.vpnhotspot.manage
import android.content.ComponentName
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 androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.RepeaterService
import be.mygod.vpnhotspot.util.KillableTileService
import be.mygod.vpnhotspot.util.stopAndUnbind
@RequiresApi(24)
class RepeaterTileService : TileService(), ServiceConnection {
class RepeaterTileService : KillableTileService() {
private val tile by lazy { Icon.createWithResource(application, R.drawable.ic_action_settings_input_antenna) }
private var binder: RepeaterService.Binder? = null
@@ -34,7 +33,7 @@ class RepeaterTileService : TileService(), ServiceConnection {
override fun onClick() {
val binder = binder
when (binder?.service?.status) {
if (binder == null) tapPending = true else when (binder.service.status) {
RepeaterService.Status.ACTIVE -> binder.shutdown()
RepeaterService.Status.IDLE ->
ContextCompat.startForegroundService(this, Intent(this, RepeaterService::class.java))
@@ -42,10 +41,11 @@ class RepeaterTileService : TileService(), ServiceConnection {
}
}
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
binder = service as RepeaterService.Binder
service.statusChanged[this] = { updateTile() }
service.groupChanged[this] = this::updateTile
super.onServiceConnected(name, service)
}
override fun onServiceDisconnected(name: ComponentName?) {

View File

@@ -1,13 +1,13 @@
package be.mygod.vpnhotspot.manage
import android.content.IntentFilter
import android.service.quicksettings.TileService
import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.util.KillableTileService
import be.mygod.vpnhotspot.util.broadcastReceiver
@RequiresApi(24)
abstract class TetherListeningTileService : TileService() {
abstract class TetherListeningTileService : KillableTileService() {
protected var tethered: List<String> = emptyList()
private val receiver = broadcastReceiver { _, intent ->

View File

@@ -3,7 +3,6 @@ package be.mygod.vpnhotspot.manage
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.graphics.drawable.Icon
import android.os.IBinder
import android.service.quicksettings.Tile
@@ -22,8 +21,7 @@ import java.io.IOException
import java.lang.reflect.InvocationTargetException
@RequiresApi(24)
sealed class TetheringTileService : TetherListeningTileService(), ServiceConnection,
TetheringManager.OnStartTetheringCallback {
sealed class TetheringTileService : TetherListeningTileService(), TetheringManager.OnStartTetheringCallback {
protected val tileOff by lazy { Icon.createWithResource(application, icon) }
protected val tileOn by lazy { Icon.createWithResource(application, R.drawable.ic_quick_settings_tile_on) }
@@ -49,6 +47,7 @@ sealed class TetheringTileService : TetherListeningTileService(), ServiceConnect
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
binder = service as TetheringService.Binder
service.routingsChanged[this] = { updateTile() }
super.onServiceConnected(name, service)
}
override fun onServiceDisconnected(name: ComponentName?) {
@@ -89,10 +88,13 @@ sealed class TetheringTileService : TetherListeningTileService(), ServiceConnect
override fun onClick() {
val interested = interested
if (interested.isEmpty()) safeInvoker { start() } else {
val inactive = interested.filter { binder?.isActive(it) != true }
if (inactive.isEmpty()) safeInvoker { stop() }
else ContextCompat.startForegroundService(this, Intent(this, TetheringService::class.java)
.putExtra(TetheringService.EXTRA_ADD_INTERFACES, inactive.toTypedArray()))
val binder = binder
if (binder == null) tapPending = true else {
val inactive = interested.filter { !binder.isActive(it) }
if (inactive.isEmpty()) safeInvoker { stop() }
else ContextCompat.startForegroundService(this, Intent(this, TetheringService::class.java)
.putExtra(TetheringService.EXTRA_ADD_INTERFACES, inactive.toTypedArray()))
}
}
}
@@ -154,10 +156,13 @@ sealed class TetheringTileService : TetherListeningTileService(), ServiceConnect
}
override fun onClick() = if (tethering?.active == true) {
val inactive = interested.filter { binder?.isActive(it) != true }
if (inactive.isEmpty()) safeInvoker { stop() }
else ContextCompat.startForegroundService(this, Intent(this, TetheringService::class.java)
.putExtra(TetheringService.EXTRA_ADD_INTERFACES, inactive.toTypedArray()))
val binder = binder
if (binder == null) tapPending = true else {
val inactive = interested.filter { !binder.isActive(it) }
if (inactive.isEmpty()) safeInvoker { stop() }
else ContextCompat.startForegroundService(this, Intent(this, TetheringService::class.java)
.putExtra(TetheringService.EXTRA_ADD_INTERFACES, inactive.toTypedArray()))
}
} else safeInvoker { start() }
}

View File

@@ -0,0 +1,19 @@
package be.mygod.vpnhotspot.util
import android.content.ComponentName
import android.content.ServiceConnection
import android.os.IBinder
import android.service.quicksettings.TileService
import androidx.annotation.RequiresApi
@RequiresApi(24)
abstract class KillableTileService : TileService(), ServiceConnection {
protected var tapPending = false
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
if (tapPending) {
tapPending = false
onClick()
}
}
}