diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index 327109798..e849fd8b6 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -108,7 +108,8 @@ class MainActivity : AppCompatActivity(), Logging, const val REQUEST_ENABLE_BT = 10 const val DID_REQUEST_PERM = 11 const val RC_SIGN_IN = 12 // google signin completed - const val RC_SELECT_DEVICE = 65549 // seems to be hardwired in CompanionDeviceManager + const val RC_SELECT_DEVICE = + 13 // seems to be hardwired in CompanionDeviceManager to add 65536 } @@ -405,14 +406,19 @@ class MainActivity : AppCompatActivity(), Logging, GoogleSignIn.getSignedInAccountFromIntent(data) handleSignInResult(task) } - RC_SELECT_DEVICE -> when (resultCode) { + (65536 + RC_SELECT_DEVICE) -> when (resultCode) { Activity.RESULT_OK -> { // User has chosen to pair with the Bluetooth device. val device: BluetoothDevice = data!!.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) debug("Received BLE pairing ${device.address}") - device.createBond() + if (device.bondState != BluetoothDevice.BOND_BONDED) { + device.createBond() + // FIXME - wait for bond to complete + } + // ... Continue interacting with the paired device. + RadioInterfaceService.setBondedDeviceAddress(this, device.address) } else -> diff --git a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt index c9314a633..b2ff2ab7e 100644 --- a/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/RadioInterfaceService.kt @@ -1,13 +1,13 @@ package com.geeksville.mesh.service +import android.annotation.SuppressLint import android.app.Service import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothManager +import android.companion.CompanionDeviceManager import android.content.Context import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build import android.os.IBinder import android.os.RemoteException import androidx.core.content.edit @@ -156,33 +156,62 @@ class RadioInterfaceService : Service(), Logging { } /// Return the device we are configured to use, or null for none - fun getBondedDeviceAddress(context: Context): String? { + @SuppressLint("NewApi") + fun getBondedDeviceAddress(context: Context): String? = + if (hasCompanionDeviceApi(context)) { + // Use new companion API - val allPaired = - getBluetoothAdapter(context)?.bondedDevices.orEmpty().map { it.address }.toSet() + val deviceManager = context.getSystemService(CompanionDeviceManager::class.java) + val associations = deviceManager.associations + val result = associations.firstOrNull() + debug("reading bonded devices: $result") + result + } else { + // Use classic API and a preferences string - // If the user has unpaired our device, treat things as if we don't have one - val addr = getPrefs(context).getString(DEVADDR_KEY, null) - return if (addr != null && !allPaired.contains(addr)) { - warn("Ignoring stale bond to $addr") - null - } else - addr - } + val allPaired = + getBluetoothAdapter(context)?.bondedDevices.orEmpty().map { it.address }.toSet() - fun setBondedDeviceAddress(context: Context, addr: String?) { - getPrefs(context).edit(commit = true) { - if (addr == null) - this.remove(DEVADDR_KEY) - else - putString(DEVADDR_KEY, addr) + // If the user has unpaired our device, treat things as if we don't have one + val address = getPrefs(context).getString(DEVADDR_KEY, null) + + if (address != null && !allPaired.contains(address)) { + warn("Ignoring stale bond to $address") + null + } else + address } + + @SuppressLint("NewApi") + fun setBondedDeviceAddress(context: Context, addr: String?) { // Record that this use has configured a radio GeeksvilleApplication.analytics.track( "mesh_bond" ) + debug("Setting bonded device to $addr") + if (hasCompanionDeviceApi((context))) { + // We only keep an association to one device at a time... + if (addr != null) { + val deviceManager = context.getSystemService(CompanionDeviceManager::class.java) + + deviceManager.associations.forEach { old -> + if (addr != old) { + debug("Forgetting old BLE association $old") + deviceManager.disassociate(old) + } + } + } + } else { + getPrefs(context).edit(commit = true) { + if (addr == null) + this.remove(DEVADDR_KEY) + else + putString(DEVADDR_KEY, addr) + } + } + // Force the service to reconnect val s = runningService if (s != null) { @@ -201,7 +230,7 @@ class RadioInterfaceService : Service(), Logging { } /// Can we use the modern BLE scan API? - fun hasCompanionDeviceApi(context: Context): Boolean = + fun hasCompanionDeviceApi(context: Context): Boolean = false /* ALAS - not ready for production yet if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val res = context.packageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP) @@ -210,7 +239,7 @@ class RadioInterfaceService : Service(), Logging { } else { warn("CompanionDevice API not available, falling back to classic scan") false - } + } */ } diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index cb0536750..1746b22d0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -24,7 +24,6 @@ import com.geeksville.android.GeeksvilleApplication import com.geeksville.android.Logging import com.geeksville.android.hideKeyboard import com.geeksville.mesh.MainActivity -import com.geeksville.mesh.MainActivity.Companion.RC_SELECT_DEVICE import com.geeksville.mesh.R import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.service.RadioInterfaceService @@ -396,9 +395,11 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { changeRadioButton.isEnabled = true changeRadioButton.setOnClickListener { debug("User clicked BLE change button") + + // Request code seems to be ignored anyways startIntentSenderForResult( chooserLauncher, - RC_SELECT_DEVICE, null, 0, 0, 0, null + MainActivity.RC_SELECT_DEVICE, null, 0, 0, 0, null ) } }