Add Bluetooth on/off into consideration when using Bluetooth tethering

This commit is contained in:
Mygod
2019-03-18 19:02:50 +08:00
parent 621b6eac74
commit e112b10c55
10 changed files with 75 additions and 25 deletions

View File

@@ -1,14 +1,23 @@
package be.mygod.vpnhotspot.manage
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothProfile
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.util.broadcastReceiver
import be.mygod.vpnhotspot.widget.SmartSnackbar
import timber.log.Timber
class BluetoothTethering(context: Context) : BluetoothProfile.ServiceListener, AutoCloseable {
companion object {
class BluetoothTethering(context: Context, val stateListener: (Int) -> Unit) :
BluetoothProfile.ServiceListener, AutoCloseable {
companion object : BroadcastReceiver() {
/**
* PAN Profile
* From BluetoothProfile.java.
@@ -17,6 +26,42 @@ class BluetoothTethering(context: Context) : BluetoothProfile.ServiceListener, A
private val isTetheringOn by lazy @SuppressLint("PrivateApi") {
Class.forName("android.bluetooth.BluetoothPan").getDeclaredMethod("isTetheringOn")
}
private fun registerBluetoothStateListener(receiver: BroadcastReceiver) =
app.registerReceiver(receiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
private val Intent.bluetoothState get() = getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
private var pendingCallback: TetheringManager.OnStartTetheringCallback? = null
/**
* https://android.googlesource.com/platform/packages/apps/Settings/+/b1af85d/src/com/android/settings/TetherSettings.java#215
*/
@TargetApi(24)
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.bluetoothState) {
BluetoothAdapter.STATE_ON -> {
TetheringManager.start(TetheringManager.TETHERING_BLUETOOTH, true, pendingCallback!!)
}
BluetoothAdapter.STATE_OFF, BluetoothAdapter.ERROR -> { }
else -> return // ignore transition states
}
pendingCallback = null
app.unregisterReceiver(this)
}
/**
* https://android.googlesource.com/platform/packages/apps/Settings/+/b1af85d/src/com/android/settings/TetherSettings.java#384
*/
@RequiresApi(24)
fun start(callback: TetheringManager.OnStartTetheringCallback) {
if (pendingCallback != null) return
val adapter = BluetoothAdapter.getDefaultAdapter()
if (adapter?.state == BluetoothAdapter.STATE_OFF) {
registerBluetoothStateListener(this)
pendingCallback = callback
adapter.enable()
} else TetheringManager.start(TetheringManager.TETHERING_BLUETOOTH, true, callback)
}
}
private var pan: BluetoothProfile? = null
@@ -29,6 +74,8 @@ class BluetoothTethering(context: Context) : BluetoothProfile.ServiceListener, A
isTetheringOn.invoke(pan) as Boolean
}
private val receiver = broadcastReceiver { _, intent -> stateListener(intent.bluetoothState) }
init {
try {
BluetoothAdapter.getDefaultAdapter()?.getProfileProxy(context, this, PAN)
@@ -36,6 +83,7 @@ class BluetoothTethering(context: Context) : BluetoothProfile.ServiceListener, A
Timber.w(e)
SmartSnackbar.make(e).show()
}
registerBluetoothStateListener(receiver)
}
override fun onServiceDisconnected(profile: Int) {

View File

@@ -3,6 +3,7 @@ package be.mygod.vpnhotspot.manage
import android.content.IntentFilter
import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces
import be.mygod.vpnhotspot.util.KillableTileService
import be.mygod.vpnhotspot.util.broadcastReceiver
@@ -11,14 +12,14 @@ abstract class TetherListeningTileService : KillableTileService() {
protected var tethered: List<String> = emptyList()
private val receiver = broadcastReceiver { _, intent ->
tethered = TetheringManager.getTetheredIfaces(intent.extras ?: return@broadcastReceiver)
tethered = intent.tetheredIfaces
updateTile()
}
override fun onStartListening() {
super.onStartListening()
tethered = TetheringManager.getTetheredIfaces(registerReceiver(
receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))?.extras ?: return)
val intent = registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
if (intent != null) tethered = intent.tetheredIfaces
}
override fun onStopListening() {

View File

@@ -149,7 +149,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
}
@RequiresApi(24)
class Bluetooth(parent: TetheringFragment) : TetherManager(parent), LifecycleObserver {
private val tethering = BluetoothTethering(parent.requireContext())
private val tethering = BluetoothTethering(parent.requireContext()) { onTetheringStarted() }
init {
parent.lifecycle.addObserver(this)
@@ -163,7 +163,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
override val type get() = VIEW_TYPE_BLUETOOTH
override val isStarted get() = tethering.active == true
override fun start() = TetheringManager.start(TetheringManager.TETHERING_BLUETOOTH, true, this)
override fun start() = BluetoothTethering.start(this)
override fun stop() {
TetheringManager.stop(TetheringManager.TETHERING_BLUETOOTH)
Thread.sleep(1) // give others a room to breathe

View File

@@ -21,6 +21,8 @@ import be.mygod.vpnhotspot.*
import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding
import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.TetheringManager.localOnlyTetheredIfaces
import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.broadcastReceiver
import kotlinx.android.synthetic.main.activity_main.*
@@ -88,10 +90,8 @@ class TetheringFragment : Fragment(), ServiceConnection, MenuItem.OnMenuItemClic
var binder: TetheringService.Binder? = null
private val adapter = ManagerAdapter()
private val receiver = broadcastReceiver { _, intent ->
val extras = intent.extras ?: return@broadcastReceiver
adapter.update(TetheringManager.getTetheredIfaces(extras),
TetheringManager.getLocalOnlyTetheredIfaces(extras),
extras.getStringArrayList(TetheringManager.EXTRA_ERRORED_TETHER)!!)
adapter.update(intent.tetheredIfaces, intent.localOnlyTetheredIfaces,
intent.getStringArrayListExtra(TetheringManager.EXTRA_ERRORED_TETHER))
}
private fun updateMonitorList(canMonitor: List<String> = emptyList()) {

View File

@@ -127,7 +127,7 @@ sealed class TetheringTileService : TetherListeningTileService(), TetheringManag
override val labelString get() = R.string.tethering_manage_bluetooth
override val tetherType get() = TetherType.BLUETOOTH
override fun start() = TetheringManager.start(TetheringManager.TETHERING_BLUETOOTH, true, this)
override fun start() = BluetoothTethering.start(this)
override fun stop() {
TetheringManager.stop(TetheringManager.TETHERING_BLUETOOTH)
Thread.sleep(1) // give others a room to breathe
@@ -135,7 +135,7 @@ sealed class TetheringTileService : TetherListeningTileService(), TetheringManag
}
override fun onStartListening() {
tethering = BluetoothTethering(this)
tethering = BluetoothTethering(this) { updateTile() }
super.onStartListening()
}
override fun onStopListening() {