we now request perms

pull/8/head
geeksville 2020-01-21 13:12:01 -08:00
rodzic 1c942a10b3
commit f48ce97d5e
5 zmienionych plików z 148 dodań i 85 usunięć

Wyświetl plik

@ -9,7 +9,7 @@ android {
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.geeksville.meshutil"
minSdkVersion 18
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"

1
app/src/main/.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1 @@
assets/firmware.bin

Wyświetl plik

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- only useful if this phone can do BTLE -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- needed to access bluetooth when app is background -->
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- for job intent service -->

Wyświetl plik

@ -1,8 +1,10 @@
package com.geeksville.meshutil
import android.Manifest
import android.bluetooth.*
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Handler
import android.util.Log
@ -10,6 +12,8 @@ import com.google.android.material.snackbar.Snackbar
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
@ -19,6 +23,7 @@ class MainActivity : AppCompatActivity() {
companion object {
const val REQUEST_ENABLE_BT = 10
const val DID_REQUEST_PERM = 11
}
private val bluetoothAdapter: BluetoothAdapter by lazy(LazyThreadSafetyMode.NONE) {
@ -26,6 +31,38 @@ class MainActivity : AppCompatActivity() {
bluetoothManager.adapter!!
}
fun requestPermission() {
val perms = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.WAKE_LOCK)
val missingPerms = perms.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
if (missingPerms.isNotEmpty()) {
missingPerms.forEach {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, it)) {
// FIXME
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
}
}
// Ask for all the missing perms
ActivityCompat.requestPermissions(this, missingPerms.toTypedArray(), DID_REQUEST_PERM)
// DID_REQUEST_PERM is an
// app-defined int constant. The callback method gets the
// result of the request.
} else {
// Permission has already been granted
SoftwareUpdateService.enqueueWork(this, SoftwareUpdateService.scanDevicesIntent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
@ -43,7 +80,7 @@ class MainActivity : AppCompatActivity() {
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
}
SoftwareUpdateService.enqueueWork(this, SoftwareUpdateService.scanDevicesIntent)
requestPermission()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {

Wyświetl plik

@ -1,9 +1,11 @@
package com.geeksville.meshutil
import android.bluetooth.*
import android.bluetooth.le.*
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.ParcelUuid
import android.os.SystemClock
import android.util.Log
import android.widget.Toast
@ -76,90 +78,102 @@ class SoftwareUpdateService : JobIntentService() {
}
}
// For each device that appears in our scan, ask for its GATT, when the gatt arrives,
// check if it is an eligable device and store it in our list of candidates
// if that device later disconnects remove it as a candidate
private val leScanCallback = BluetoothAdapter.LeScanCallback { device, _, _ ->
lateinit var bluetoothGatt: BluetoothGatt // late init so we can declare our callback and use this there
//var connectionState = STATE_DISCONNECTED
// Various callback methods defined by the BLE API.
val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt,
status: Int,
newState: Int
) {
//val intentAction: String
when (newState) {
BluetoothProfile.STATE_CONNECTED -> {
//intentAction = ACTION_GATT_CONNECTED
//connectionState = STATE_CONNECTED
// broadcastUpdate(intentAction)
assert(bluetoothGatt.discoverServices())
}
BluetoothProfile.STATE_DISCONNECTED -> {
//intentAction = ACTION_GATT_DISCONNECTED
//connectionState = STATE_DISCONNECTED
// broadcastUpdate(intentAction)
}
}
}
// New services discovered
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
assert(status == BluetoothGatt.GATT_SUCCESS)
// broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED)
val service = gatt.services.find { it.uuid == SW_UPDATE_UUID }
if (service != null) {
// FIXME instead of slamming in the target device here, instead make it a param for startUpdate
updateService = service
// FIXME instead of keeping the connection open, make start update just reconnect (needed once user can choose devices)
updateGatt = bluetoothGatt
enqueueWork(this@SoftwareUpdateService, startUpdateIntent)
} else {
// drop our connection - we don't care about this device
bluetoothGatt.disconnect()
}
}
// Result of a characteristic read operation
override fun onCharacteristicRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
assert(status == BluetoothGatt.GATT_SUCCESS)
if (characteristic == totalSizeDesc) {
// Our read of this has completed, either fail or continue updating
val readvalue =
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0)
assert(readvalue != 0) // FIXME - handle this case
enqueueWork(this@SoftwareUpdateService, sendNextBlockIntent)
}
// broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
assert(status == BluetoothGatt.GATT_SUCCESS)
if (characteristic == dataDesc) {
enqueueWork(this@SoftwareUpdateService, sendNextBlockIntent)
}
}
private val scanCallback = object : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
throw NotImplementedError()
}
// For each device that appears in our scan, ask for its GATT, when the gatt arrives,
// check if it is an eligable device and store it in our list of candidates
// if that device later disconnects remove it as a candidate
override fun onScanResult(callbackType: Int, result: ScanResult) {
// We don't need any more results now
bluetoothAdapter.bluetoothLeScanner.stopScan(this)
lateinit var bluetoothGatt: BluetoothGatt // late init so we can declare our callback and use this there
//var connectionState = STATE_DISCONNECTED
// Various callback methods defined by the BLE API.
val gattCallback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(
gatt: BluetoothGatt,
status: Int,
newState: Int
) {
//val intentAction: String
when (newState) {
BluetoothProfile.STATE_CONNECTED -> {
//intentAction = ACTION_GATT_CONNECTED
//connectionState = STATE_CONNECTED
// broadcastUpdate(intentAction)
assert(bluetoothGatt.discoverServices())
}
BluetoothProfile.STATE_DISCONNECTED -> {
//intentAction = ACTION_GATT_DISCONNECTED
//connectionState = STATE_DISCONNECTED
// broadcastUpdate(intentAction)
}
}
}
// New services discovered
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
assert(status == BluetoothGatt.GATT_SUCCESS)
// broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED)
val service = gatt.services.find { it.uuid == SW_UPDATE_UUID }
if (service != null) {
// FIXME instead of slamming in the target device here, instead make it a param for startUpdate
updateService = service
// FIXME instead of keeping the connection open, make start update just reconnect (needed once user can choose devices)
updateGatt = bluetoothGatt
enqueueWork(this@SoftwareUpdateService, startUpdateIntent)
} else {
// drop our connection - we don't care about this device
bluetoothGatt.disconnect()
}
}
// Result of a characteristic read operation
override fun onCharacteristicRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic,
status: Int
) {
assert(status == BluetoothGatt.GATT_SUCCESS)
if (characteristic == totalSizeDesc) {
// Our read of this has completed, either fail or continue updating
val readvalue =
characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0)
assert(readvalue != 0) // FIXME - handle this case
enqueueWork(this@SoftwareUpdateService, sendNextBlockIntent)
}
// broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic)
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
assert(status == BluetoothGatt.GATT_SUCCESS)
if (characteristic == dataDesc) {
enqueueWork(this@SoftwareUpdateService, sendNextBlockIntent)
}
}
}
bluetoothGatt = result.device.connectGatt(this@SoftwareUpdateService, false, gattCallback)!!
}
bluetoothGatt = device.connectGatt(this, false, gattCallback)!!
}
private fun scanLeDevice(enable: Boolean) {
when (enable) {
true -> {
@ -169,11 +183,21 @@ class SoftwareUpdateService : JobIntentService() {
bluetoothAdapter.stopLeScan(leScanCallback)
}, SCAN_PERIOD)
mScanning = true */
assert(bluetoothAdapter.startLeScan(leScanCallback))
val scanner = bluetoothAdapter.bluetoothLeScanner
// filter and only accept devices that have a sw update service
val filter = ScanFilter.Builder().setServiceUuid(ParcelUuid(SW_UPDATE_UUID)).build()
val settings = ScanSettings.Builder().
setScanMode(ScanSettings.SCAN_MODE_BALANCED).
setMatchMode(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT).
setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH).
build()
scanner.startScan(listOf(filter), settings, scanCallback)
}
else -> {
// mScanning = false
bluetoothAdapter.stopLeScan(leScanCallback)
// bluetoothAdapter.stopLeScan(leScanCallback)
}
}
}