practise BLE yes
This commit is contained in:
parent
3e6fe310e0
commit
a9564bb441
@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
androidApplication
|
||||
kotlinAndroid
|
||||
}
|
||||
|
||||
val packageName = "ru.myitschool.work"
|
||||
@ -18,14 +19,18 @@ android {
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildFeatures.viewBinding = true
|
||||
buildFeatures.dataBinding = true
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = Version.Kotlin.javaSource
|
||||
targetCompatibility = Version.Kotlin.javaSource
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.core:core-ktx:1.7.0")
|
||||
defaultLibrary()
|
||||
}
|
||||
|
@ -2,6 +2,35 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Request legacy Bluetooth permissions on older devices. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
||||
android:maxSdkVersion="30"/>
|
||||
|
||||
<!-- Needed only if your app looks for Bluetooth devices.
|
||||
If your app doesn't use Bluetooth scan results to derive physical
|
||||
location information, you can strongly assert that your app
|
||||
doesn't derive physical location. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
|
||||
<!-- Needed only if your app makes the device discoverable to Bluetooth
|
||||
devices. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||
|
||||
<!-- Needed only if your app communicates with already-paired Bluetooth
|
||||
devices. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
|
||||
|
||||
<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
|
||||
<uses-feature android:name="android.hardware.bluetooth" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
@ -11,6 +40,21 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Default"
|
||||
tools:targetApi="31" />
|
||||
tools:targetApi="31" >
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
android:value="" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
12
app/src/main/kotlin/ru/myitschool/work/ActivityViewModel.kt
Normal file
12
app/src/main/kotlin/ru/myitschool/work/ActivityViewModel.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package ru.myitschool.work
|
||||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class ActivityViewModel(
|
||||
|
||||
): ViewModel() {
|
||||
val foundDevice = MutableLiveData<BluetoothDevice>();
|
||||
val statemotors = MutableLiveData<String>("OFF");
|
||||
}
|
126
app/src/main/kotlin/ru/myitschool/work/BluetoothScanner.kt
Normal file
126
app/src/main/kotlin/ru/myitschool/work/BluetoothScanner.kt
Normal file
@ -0,0 +1,126 @@
|
||||
package ru.myitschool.work
|
||||
|
||||
import android.Manifest
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.bluetooth.le.BluetoothLeScanner
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
class BluetoothScanner(activityViewModel: ActivityViewModel, private val context: Context) {
|
||||
private val mBluetoothAdapter: BluetoothAdapter
|
||||
private val mBluetoothLeScanner: BluetoothLeScanner
|
||||
private var mScanCallback: ScanCallback? = null
|
||||
private val mHandler: Handler
|
||||
private var mScanning = false
|
||||
private var bluetoothDevice: BluetoothDevice? = null
|
||||
private val activityViewModel: ActivityViewModel
|
||||
|
||||
init {
|
||||
mHandler = Handler(Looper.getMainLooper())
|
||||
val bluetoothManager =
|
||||
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
context, Manifest.permission.BLUETOOTH_SCAN
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
}
|
||||
mBluetoothAdapter = bluetoothManager.adapter
|
||||
mBluetoothAdapter.startDiscovery()
|
||||
mBluetoothLeScanner = mBluetoothAdapter.bluetoothLeScanner
|
||||
this.activityViewModel = activityViewModel
|
||||
}
|
||||
|
||||
fun createScanSettings():ScanSettings{
|
||||
TODO()//Реализовать метод создания ScanSetting с настройками Балансированного режима сканирования и немедленной показе результатов сканирования
|
||||
return ScanSettings.Builder()
|
||||
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
|
||||
.setReportDelay(0)
|
||||
.build()
|
||||
}
|
||||
fun startScan(filters: ArrayList<ScanFilter>) {
|
||||
if (!mScanning) {
|
||||
Log.i(TAG, "Starting scan...")
|
||||
val settings = createScanSettings()
|
||||
mScanCallback = object : ScanCallback() {
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
super.onScanResult(callbackType, result)
|
||||
val device = result.device
|
||||
println("RESULT")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
context, Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
Log.i(TAG, "Found device: " + device.name + " (" + device.address + ")")
|
||||
bluetoothDevice = device
|
||||
activityViewModel.foundDevice.value = device
|
||||
}
|
||||
|
||||
override fun onBatchScanResults(results: List<ScanResult>) {
|
||||
super.onBatchScanResults(results)
|
||||
for (result in results) {
|
||||
val device = result.device
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
context, Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
Log.i(TAG, "Found device: " + device.name + " (" + device.address + ")")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScanFailed(errorCode: Int) {
|
||||
super.onScanFailed(errorCode)
|
||||
Log.e(
|
||||
TAG,
|
||||
"Scan failed with error code: $errorCode"
|
||||
)
|
||||
Toast.makeText(context, "Scan failed with error code: ", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
mBluetoothLeScanner.startScan(filters, settings, mScanCallback)
|
||||
mHandler.postDelayed({ stopScan() }, SCAN_PERIOD)
|
||||
mScanning = true
|
||||
} else {
|
||||
Log.i(TAG, "Scan already in progress")
|
||||
Toast.makeText(context, "Scan already in progress", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopScan() {
|
||||
if (mScanning) {
|
||||
Log.i(TAG, "Stopping scan...")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
context, Manifest.permission.BLUETOOTH_SCAN
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
mBluetoothLeScanner.stopScan(mScanCallback)
|
||||
mScanning = false
|
||||
} else {
|
||||
Log.i(TAG, "No scan in progress")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = BluetoothScanner::class.java.simpleName
|
||||
private const val SCAN_PERIOD: Long = 4000 // 4 seconds
|
||||
}
|
||||
}
|
389
app/src/main/kotlin/ru/myitschool/work/MainActivity.kt
Normal file
389
app/src/main/kotlin/ru/myitschool/work/MainActivity.kt
Normal file
@ -0,0 +1,389 @@
|
||||
package ru.myitschool.work
|
||||
|
||||
import android.Manifest
|
||||
import android.bluetooth.*
|
||||
import android.bluetooth.BluetoothDevice.*
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import ru.myitschool.work.databinding.ActivityMainBinding
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.function.Consumer
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private val BLP_SERVICE_UUID: UUID? = UUID.fromString("e7112e6c-c396-11ed-afa1-0242ac120002");//e7112e6c-c396-11ed-afa1-0242ac120002
|
||||
private val names:Array<String>? = arrayOf("RDB-1")
|
||||
private val mac:Array<String>? = arrayOf("0C:B8:15:F6:0D:52")
|
||||
|
||||
|
||||
val TAG ="CONTROLLER"
|
||||
|
||||
|
||||
private lateinit var bluetoothGattCallback: BluetoothGattCallback
|
||||
private lateinit var bluetoothScanner: BluetoothScanner
|
||||
private lateinit var activityViewModel: ActivityViewModel
|
||||
|
||||
private lateinit var service:BluetoothGattService;
|
||||
|
||||
|
||||
companion object{
|
||||
private var status:Int=-1;
|
||||
private var newState:Int=-1;
|
||||
private lateinit var gatt:BluetoothGatt;
|
||||
private var isOffMotors=false;
|
||||
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
activityViewModel = ViewModelProvider(this).get(
|
||||
ActivityViewModel::class.java
|
||||
)
|
||||
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
|
||||
|
||||
binding.vm =activityViewModel;
|
||||
binding.setLifecycleOwner(this);
|
||||
setContentView(binding.root)
|
||||
|
||||
if (allPermissionGranted()) {
|
||||
|
||||
} else {
|
||||
askPermissions()
|
||||
}
|
||||
|
||||
bluetoothScanner = BluetoothScanner(activityViewModel,this);
|
||||
|
||||
val scanningButton = binding.Scan
|
||||
scanningButton.setOnClickListener(View.OnClickListener {
|
||||
Scanning()
|
||||
})
|
||||
val connectButton = binding.Connect
|
||||
connectButton.setOnClickListener(View.OnClickListener {
|
||||
Connect()
|
||||
})
|
||||
val OnOffMotorsButton = binding.OnOffMotors
|
||||
OnOffMotorsButton.setOnClickListener(View.OnClickListener {
|
||||
OnOffMotors()
|
||||
})
|
||||
val position1Button = binding.Position1
|
||||
position1Button.setOnClickListener(View.OnClickListener {
|
||||
Position1()
|
||||
})
|
||||
val position2Button = binding.Position2
|
||||
position2Button.setOnClickListener(View.OnClickListener {
|
||||
Position2()
|
||||
})
|
||||
|
||||
|
||||
bluetoothGattCallback = object : BluetoothGattCallback(){
|
||||
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
|
||||
super.onConnectionStateChange(gatt, status, newState)
|
||||
Companion.newState = newState
|
||||
Companion.status = status
|
||||
if(newState==BluetoothProfile.STATE_CONNECTED)
|
||||
Companion.gatt = gatt!!
|
||||
|
||||
}
|
||||
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
|
||||
for(ser in gatt!!.services){
|
||||
println(" "+ ser.uuid+" "+ ser.characteristics.toString()+" "+ser.type+" "+ser.includedServices)
|
||||
}
|
||||
|
||||
service = gatt!!.getService(BLP_SERVICE_UUID)
|
||||
for(chara in service.characteristics) {
|
||||
println(TAG + " " + chara.uuid + " " + chara.properties + " " + chara.permissions + " ")
|
||||
}
|
||||
val characteristic0 = service.getCharacteristic(service.characteristics[0].uuid)
|
||||
Log.d(TAG,characteristic0.toString())
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(this@MainActivity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
|
||||
return
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
activityViewModel.statemotors.value = "Calibration"
|
||||
}
|
||||
gatt.readCharacteristic(service.characteristics[0])
|
||||
|
||||
}
|
||||
|
||||
override fun onCharacteristicRead(
|
||||
gatt: BluetoothGatt?,
|
||||
characteristic: BluetoothGattCharacteristic?,
|
||||
status: Int
|
||||
) {
|
||||
super.onCharacteristicRead(gatt, characteristic, status)
|
||||
|
||||
if (status === BluetoothGatt.GATT_SUCCESS) {
|
||||
// Получаем данные характеристики
|
||||
var value = characteristic!!.value.clone()
|
||||
|
||||
if(value[0]==(0).toByte() && value[1]==(0).toByte()) {//Если все двигатели выключены
|
||||
isOffMotors = true;
|
||||
//и включаем двигатели
|
||||
value = byteArrayOf(0b11111111.toByte(), 0b00001111.toByte())
|
||||
val characteristic0 = service.characteristics[0];
|
||||
characteristic0.value = value!!
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
this@MainActivity,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
gatt!!.writeCharacteristic(characteristic0) // перезаписываем состояния двигателей чтобы их включить
|
||||
|
||||
|
||||
}else{
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Toast.makeText(this@MainActivity, "Двигатели уже включены!", Toast.LENGTH_SHORT).show()
|
||||
activityViewModel.statemotors.value = "ON"
|
||||
}
|
||||
}
|
||||
// Делаем что-то с полученными данными
|
||||
} else {
|
||||
// Чтение характеристики не удалось
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt?,
|
||||
characteristic: BluetoothGattCharacteristic?,
|
||||
status: Int
|
||||
) {
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
|
||||
if (status === BluetoothGatt.GATT_SUCCESS) {
|
||||
if (characteristic == service.characteristics[0]){// данная характиристика отвечает за состояния вкл/выкл двигателя
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
activityViewModel.statemotors.value = "ON"
|
||||
}
|
||||
} else if (characteristic == service.characteristics[2]) { // данная характиристика отвечает за положение
|
||||
|
||||
println("VALUE "+Arrays.toString(characteristic!!.value))
|
||||
val floats = FloatArray(characteristic.value.size/4);
|
||||
var i = 0
|
||||
while (i*4 < characteristic.value.size) {
|
||||
val myFloat = ByteBuffer.wrap(characteristic.value).getFloat(i*4)
|
||||
floats.set(i,myFloat)
|
||||
i += 1
|
||||
}
|
||||
println("FLOAT "+Arrays.toString(floats))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (allPermissionGranted()) {
|
||||
bluetoothScanner = BluetoothScanner(activityViewModel,this);
|
||||
} else {
|
||||
askPermissions()
|
||||
}
|
||||
}
|
||||
|
||||
fun createScanFilter(name:String):ScanFilter{
|
||||
TODO()//Реализовать createScanFilter - Создание scan filter по имени
|
||||
return ScanFilter.Builder()
|
||||
.setDeviceName(name)
|
||||
.build()
|
||||
}
|
||||
fun Scanning(){
|
||||
println("Scanning")
|
||||
var filters: ArrayList<ScanFilter> = ArrayList();
|
||||
|
||||
if (names != null) {
|
||||
for (name in names) {
|
||||
println(name)
|
||||
val filter = createScanFilter(name)
|
||||
filters.add(filter)
|
||||
}
|
||||
}
|
||||
bluetoothScanner.startScan(filters)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fun Connect(){
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
pairDevice(activityViewModel.foundDevice.value)
|
||||
}
|
||||
|
||||
if(activityViewModel.foundDevice.value!=null) {
|
||||
val gatt: BluetoothGatt = activityViewModel.foundDevice.value!!
|
||||
.connectGatt(this, false, bluetoothGattCallback, TRANSPORT_AUTO)
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
gatt.readPhy()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fun OnOffMotors(){
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(this@MainActivity,Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
|
||||
}
|
||||
if(status == BluetoothGatt.GATT_SUCCESS) {
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
// Мы подключились, можно запускать обнаружение сервисов
|
||||
gatt?.discoverServices();
|
||||
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
// Мы успешно отключились (контролируемое отключение)
|
||||
gatt?.close();
|
||||
} else {
|
||||
// мы или подключаемся или отключаемся, просто игнорируем эти статусы
|
||||
}
|
||||
} else {
|
||||
// Произошла ошибка... разбираемся, что случилось!
|
||||
gatt?.close();
|
||||
}
|
||||
}
|
||||
|
||||
fun floatAAToByteArray(floatAA: ArrayList<ArrayList<Float>>):ByteArray{
|
||||
TODO()//Реализовать метод перевода из массива вещественных чисел к массиву байтов
|
||||
var value :ByteArray? = null
|
||||
value = ByteArray(floatAA.size*floatAA[0].size*Float.SIZE_BYTES)
|
||||
val buffer = ByteBuffer.wrap(value)
|
||||
for (i in floatAA.indices){
|
||||
for(j in floatAA[0].indices){
|
||||
buffer.putFloat(floatAA[i][j])
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
fun Position1(){
|
||||
val pos1 = arrayListOf<kotlin.collections.ArrayList<Float>>(arrayListOf(0.8f, 12f, 0f, 10f, 0f ))
|
||||
val characteristic = service.getCharacteristic(service.characteristics[2].uuid)
|
||||
Log.d(TAG,characteristic.uuid.toString())
|
||||
var value :ByteArray? = floatAAToByteArray(pos1)
|
||||
|
||||
characteristic.value = value!!
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
this@MainActivity,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
gatt!!.writeCharacteristic(characteristic)
|
||||
|
||||
}
|
||||
fun Position2(){
|
||||
TODO()//Реализать метод Position2 для передачи массива вещественных чисел на (третью характеристику) [0.3, 2, 4.5, 2, 0.4]
|
||||
val pos1 = arrayListOf<kotlin.collections.ArrayList<Float>>(arrayListOf(0.3f, 2f, 4.5f, 2f, 0.4f ))
|
||||
val characteristic = service.getCharacteristic(service.characteristics[2].uuid)
|
||||
Log.d(TAG,characteristic.uuid.toString())
|
||||
var value :ByteArray? = floatAAToByteArray(pos1)
|
||||
|
||||
characteristic.value = value!!
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
this@MainActivity,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
gatt!!.writeCharacteristic(characteristic)
|
||||
}
|
||||
|
||||
fun createPairingIntent(device:BluetoothDevice?):Intent{
|
||||
TODO()//метод должен отправить intent для запроса присоединения к устройству с вводом пин кода
|
||||
val intent = Intent(BluetoothDevice.ACTION_PAIRING_REQUEST)
|
||||
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device)
|
||||
intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
return intent
|
||||
}
|
||||
|
||||
|
||||
fun pairDevice(device: BluetoothDevice?) {
|
||||
val intent = createPairingIntent(device)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && ActivityCompat.checkSelfPermission(
|
||||
this,
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.startActivity(intent)
|
||||
}
|
||||
|
||||
|
||||
private val PERMISSIONS = arrayOf(Manifest.permission.BLUETOOTH_SCAN,Manifest.permission.BLUETOOTH_CONNECT)
|
||||
|
||||
private val requestLauncher = registerForActivityResult<Array<String>, Map<String, Boolean>>(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
) { permissions: Map<String, Boolean> ->
|
||||
val permissionGranted =
|
||||
AtomicBoolean(false)
|
||||
permissions.forEach { (key: String, value: Boolean) ->
|
||||
if (Arrays.asList(*PERMISSIONS).contains(key) && !value) {
|
||||
Toast.makeText(this, "$key $value", Toast.LENGTH_SHORT).show()
|
||||
permissionGranted.set(false)
|
||||
}
|
||||
}
|
||||
if (!permissionGranted.get()) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
"Permission request denied",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
//do something
|
||||
}
|
||||
}
|
||||
|
||||
private fun askPermissions() {
|
||||
requestLauncher.launch(PERMISSIONS)
|
||||
}
|
||||
|
||||
fun allPermissionGranted(): Boolean {
|
||||
val granted = AtomicBoolean(true)
|
||||
Arrays.asList(*PERMISSIONS).forEach(Consumer { it: String? ->
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
this,
|
||||
it!!
|
||||
) == PackageManager.PERMISSION_DENIED
|
||||
) {
|
||||
granted.set(false)
|
||||
}
|
||||
})
|
||||
return granted.get()
|
||||
}
|
||||
}
|
88
app/src/main/res/layout/activity_main.xml
Normal file
88
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<layout>
|
||||
<data>
|
||||
<variable
|
||||
name="vm"
|
||||
type="ru.myitschool.work.ActivityViewModel" />
|
||||
</data>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
<Button
|
||||
android:id="@+id/Scan"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:text="Scan"
|
||||
></Button>
|
||||
<TextView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="50dp"
|
||||
android:hint="DEVICE"
|
||||
android:text="@{vm.foundDevice.name}"
|
||||
android:gravity="center">
|
||||
|
||||
</TextView>
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/Connect"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:text="Connect"
|
||||
></Button>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
<Button
|
||||
android:id="@+id/OnOffMotors"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="5dp"
|
||||
android:text="OnOffMotors"
|
||||
></Button>
|
||||
<TextView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="50dp"
|
||||
android:hint="state motors"
|
||||
android:text="@{vm.statemotors}"
|
||||
android:gravity="center">
|
||||
</TextView>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
>
|
||||
|
||||
<Button
|
||||
android:id="@+id/Position1"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Position1"
|
||||
></Button>
|
||||
<Button
|
||||
android:id="@+id/Position2"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="5dp"
|
||||
android:text="Position2"
|
||||
></Button>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
@ -2,4 +2,5 @@
|
||||
plugins {
|
||||
androidApplication version Version.gradle apply false
|
||||
kotlinJvm version Version.Kotlin.language apply false
|
||||
kotlinAndroid version Version.Kotlin.language apply false
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user