Better network connection observing
This commit is contained in:
parent
ee4db43136
commit
9bebe07d5a
@ -3,9 +3,9 @@ package com.topjohnwu.magisk.core
|
|||||||
import androidx.databinding.ObservableBoolean
|
import androidx.databinding.ObservableBoolean
|
||||||
import com.topjohnwu.magisk.DynAPK
|
import com.topjohnwu.magisk.DynAPK
|
||||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
|
import com.topjohnwu.magisk.core.utils.net.NetworkObserver
|
||||||
import com.topjohnwu.magisk.ktx.get
|
import com.topjohnwu.magisk.ktx.get
|
||||||
import com.topjohnwu.magisk.utils.CachedValue
|
import com.topjohnwu.magisk.utils.CachedValue
|
||||||
import com.topjohnwu.magisk.utils.net.NetworkObserver
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.topjohnwu.superuser.ShellUtils.fastCmd
|
import com.topjohnwu.superuser.ShellUtils.fastCmd
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
@ -38,7 +38,7 @@ object Info {
|
|||||||
val isConnected by lazy {
|
val isConnected by lazy {
|
||||||
ObservableBoolean(false).also { field ->
|
ObservableBoolean(false).also { field ->
|
||||||
NetworkObserver.observe(get()) {
|
NetworkObserver.observe(get()) {
|
||||||
UiThreadHandler.run { field.set(it.isAvailable) }
|
UiThreadHandler.run { field.set(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.topjohnwu.magisk.utils.net
|
package com.topjohnwu.magisk.core.utils.net
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
import android.annotation.TargetApi
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@ -6,11 +6,12 @@ import android.net.ConnectivityManager
|
|||||||
import android.net.Network
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
|
import androidx.collection.ArraySet
|
||||||
|
|
||||||
@TargetApi(21)
|
@TargetApi(21)
|
||||||
open class LollipopNetworkObserver(
|
open class LollipopNetworkObserver(
|
||||||
context: Context,
|
context: Context,
|
||||||
callback: NetInfoCallback
|
callback: ConnectionCallback
|
||||||
): NetworkObserver(context, callback) {
|
): NetworkObserver(context, callback) {
|
||||||
|
|
||||||
private val networkCallback = NetCallback()
|
private val networkCallback = NetCallback()
|
||||||
@ -22,17 +23,27 @@ open class LollipopNetworkObserver(
|
|||||||
manager.registerNetworkCallback(request, networkCallback)
|
manager.registerNetworkCallback(request, networkCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
override fun getCurrentState() {
|
||||||
|
callback(manager.activeNetworkInfo?.isConnected ?: false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun stopObserving() {
|
override fun stopObserving() {
|
||||||
manager.unregisterNetworkCallback(networkCallback)
|
manager.unregisterNetworkCallback(networkCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class NetCallback : ConnectivityManager.NetworkCallback() {
|
private inner class NetCallback : ConnectivityManager.NetworkCallback() {
|
||||||
|
|
||||||
|
private val activeList = ArraySet<Network>()
|
||||||
|
|
||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
emit(Connectivity.create(manager, network))
|
activeList.add(network)
|
||||||
|
callback(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLost(network: Network) {
|
override fun onLost(network: Network) {
|
||||||
emit(Connectivity.create(manager, network))
|
activeList.remove(network)
|
||||||
|
callback(!activeList.isEmpty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package com.topjohnwu.magisk.core.utils.net
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.os.PowerManager
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
|
||||||
|
@TargetApi(23)
|
||||||
|
class MarshmallowNetworkObserver(
|
||||||
|
context: Context,
|
||||||
|
callback: ConnectionCallback
|
||||||
|
): LollipopNetworkObserver(context, callback) {
|
||||||
|
|
||||||
|
private val receiver = IdleBroadcastReceiver()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val filter = IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)
|
||||||
|
app.registerReceiver(receiver, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stopObserving() {
|
||||||
|
super.stopObserving()
|
||||||
|
app.unregisterReceiver(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCurrentState() {
|
||||||
|
callback(manager.getNetworkCapabilities(manager.activeNetwork)
|
||||||
|
?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class IdleBroadcastReceiver: BroadcastReceiver() {
|
||||||
|
|
||||||
|
private fun Context.isIdleMode(): Boolean {
|
||||||
|
val pwm = getSystemService<PowerManager>() ?: return true
|
||||||
|
val isIgnoringOptimizations = pwm.isIgnoringBatteryOptimizations(packageName)
|
||||||
|
return pwm.isDeviceIdleMode && !isIgnoringOptimizations
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (context.isIdleMode()) {
|
||||||
|
callback(false)
|
||||||
|
} else {
|
||||||
|
getCurrentState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +1,30 @@
|
|||||||
package com.topjohnwu.magisk.utils.net
|
package com.topjohnwu.magisk.core.utils.net
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
|
||||||
typealias NetInfoCallback = (Connectivity) -> Unit
|
typealias ConnectionCallback = (Boolean) -> Unit
|
||||||
|
|
||||||
abstract class NetworkObserver protected constructor(
|
abstract class NetworkObserver(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val callback: NetInfoCallback
|
protected val callback: ConnectionCallback
|
||||||
) {
|
) {
|
||||||
|
|
||||||
protected val context = context.applicationContext
|
protected val app: Context = context.applicationContext
|
||||||
protected val manager = context.getSystemService<ConnectivityManager>()!!
|
protected val manager = context.getSystemService<ConnectivityManager>()!!
|
||||||
protected var last = Connectivity.create(manager)
|
|
||||||
|
|
||||||
init {
|
|
||||||
callback(last)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun emit(current: Connectivity) {
|
|
||||||
if (last != current)
|
|
||||||
callback(current)
|
|
||||||
last = current
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract fun stopObserving()
|
protected abstract fun stopObserving()
|
||||||
|
protected abstract fun getCurrentState()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun observe(context: Context, callback: NetInfoCallback): NetworkObserver {
|
fun observe(context: Context, callback: ConnectionCallback): NetworkObserver {
|
||||||
return when (Build.VERSION.SDK_INT) {
|
return when (Build.VERSION.SDK_INT) {
|
||||||
in 23 until Int.MAX_VALUE -> MarshmallowNetworkObserver(context, callback)
|
in 23 until Int.MAX_VALUE -> MarshmallowNetworkObserver(context, callback)
|
||||||
in 21 until 23 -> LollipopNetworkObserver(context, callback)
|
in 21 until 23 -> LollipopNetworkObserver(context, callback)
|
||||||
else -> PreLollipopNetworkObserver(context, callback)
|
else -> PreLollipopNetworkObserver(context, callback)
|
||||||
}
|
}.apply { getCurrentState() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,34 +1,38 @@
|
|||||||
@file:Suppress("DEPRECATION")
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package com.topjohnwu.magisk.utils.net
|
package com.topjohnwu.magisk.core.utils.net
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
import androidx.core.net.ConnectivityManagerCompat
|
||||||
|
|
||||||
class PreLollipopNetworkObserver(
|
class PreLollipopNetworkObserver(
|
||||||
context: Context,
|
context: Context,
|
||||||
callback: NetInfoCallback
|
callback: ConnectionCallback
|
||||||
): NetworkObserver(context, callback) {
|
): NetworkObserver(context, callback) {
|
||||||
|
|
||||||
private val receiver = ConnectivityBroadcastReceiver()
|
private val receiver = ConnectivityBroadcastReceiver()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val filter = IntentFilter()
|
val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
|
app.registerReceiver(receiver, filter)
|
||||||
context.registerReceiver(receiver, filter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopObserving() {
|
override fun stopObserving() {
|
||||||
context.unregisterReceiver(receiver)
|
app.unregisterReceiver(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCurrentState() {
|
||||||
|
callback(manager.activeNetworkInfo?.isConnected ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ConnectivityBroadcastReceiver: BroadcastReceiver() {
|
private inner class ConnectivityBroadcastReceiver: BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
emit(Connectivity.create(manager))
|
val info = ConnectivityManagerCompat.getNetworkInfoFromBroadcast(manager, intent)
|
||||||
|
callback(info?.isConnected ?: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,49 +0,0 @@
|
|||||||
@file:Suppress("DEPRECATION")
|
|
||||||
|
|
||||||
package com.topjohnwu.magisk.utils.net
|
|
||||||
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.Network
|
|
||||||
import android.net.NetworkInfo
|
|
||||||
import android.net.NetworkInfo.DetailedState
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
|
|
||||||
// Recreate NetworkInfo with Kotlin data class
|
|
||||||
data class Connectivity(
|
|
||||||
val state : NetworkInfo.State = NetworkInfo.State.DISCONNECTED,
|
|
||||||
val detailedState : DetailedState = DetailedState.IDLE,
|
|
||||||
val type : Int = -1,
|
|
||||||
val subType : Int = -1,
|
|
||||||
val isAvailable : Boolean = false,
|
|
||||||
val isFailover : Boolean = false,
|
|
||||||
val isRoaming : Boolean = false,
|
|
||||||
val typeName : String = "NONE",
|
|
||||||
val subTypeName : String = "NONE",
|
|
||||||
val reason : String? = null,
|
|
||||||
val extraInfo : String? = null
|
|
||||||
) {
|
|
||||||
private constructor(info: NetworkInfo) : this(
|
|
||||||
info.state,
|
|
||||||
info.detailedState,
|
|
||||||
info.type,
|
|
||||||
info.subtype,
|
|
||||||
info.isAvailable,
|
|
||||||
info.isFailover,
|
|
||||||
info.isRoaming,
|
|
||||||
info.typeName,
|
|
||||||
info.subtypeName,
|
|
||||||
info.reason,
|
|
||||||
info.extraInfo
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(manager: ConnectivityManager): Connectivity {
|
|
||||||
return manager.activeNetworkInfo?.let { Connectivity(it) } ?: Connectivity()
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(21)
|
|
||||||
fun create(manager: ConnectivityManager, network: Network): Connectivity {
|
|
||||||
return manager.getNetworkInfo(network)?.let { Connectivity(it) } ?: Connectivity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
@file:Suppress("DEPRECATION")
|
|
||||||
|
|
||||||
package com.topjohnwu.magisk.utils.net
|
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.net.NetworkInfo
|
|
||||||
import android.os.PowerManager
|
|
||||||
import androidx.core.content.getSystemService
|
|
||||||
|
|
||||||
@TargetApi(23)
|
|
||||||
class MarshmallowNetworkObserver(
|
|
||||||
context: Context,
|
|
||||||
callback: NetInfoCallback
|
|
||||||
): LollipopNetworkObserver(context, callback) {
|
|
||||||
|
|
||||||
private val idleReceiver = IdleBroadcastReceiver()
|
|
||||||
|
|
||||||
init {
|
|
||||||
val filter = IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)
|
|
||||||
context.registerReceiver(idleReceiver, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stopObserving() {
|
|
||||||
super.stopObserving()
|
|
||||||
context.unregisterReceiver(idleReceiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun emit(current: Connectivity) {
|
|
||||||
val typeChanged = last.type != current.type
|
|
||||||
val wasConnected = last.state == NetworkInfo.State.CONNECTED
|
|
||||||
val isDisconnected = current.state == NetworkInfo.State.DISCONNECTED
|
|
||||||
val isNotIdle = current.detailedState != NetworkInfo.DetailedState.IDLE
|
|
||||||
if (typeChanged && wasConnected && isDisconnected && isNotIdle) {
|
|
||||||
super.emit(current)
|
|
||||||
super.emit(last)
|
|
||||||
last = current
|
|
||||||
} else {
|
|
||||||
super.emit(current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class IdleBroadcastReceiver: BroadcastReceiver() {
|
|
||||||
|
|
||||||
private fun isIdleMode(context: Context): Boolean {
|
|
||||||
val packageName = context.packageName
|
|
||||||
val manager = context.getSystemService<PowerManager>()!!
|
|
||||||
val isIgnoringOptimizations = manager.isIgnoringBatteryOptimizations(packageName)
|
|
||||||
return manager.isDeviceIdleMode && !isIgnoringOptimizations
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
if (isIdleMode(context)) {
|
|
||||||
emit(Connectivity())
|
|
||||||
} else {
|
|
||||||
emit(Connectivity.create(manager))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user