practise BLE yes
This commit is contained in:
		| @@ -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> | ||||
		Reference in New Issue
	
	Block a user