List devices

This commit is contained in:
Nikonell
2023-06-24 17:34:18 +07:00
parent 1964f95927
commit 5609190f72
11 changed files with 452 additions and 112 deletions

123
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,123 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -2,6 +2,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.bluetooth" />
<uses-feature android:name="android.hardware.bluetooth_le" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@@ -12,6 +22,9 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HeliBLE" android:theme="@style/Theme.HeliBLE"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name=".ControlActivity"
android:exported="false" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true"> android:exported="true">

View File

@@ -0,0 +1,5 @@
package com.listerk.helible
object AppState {
lateinit var bleDevice: BleDevice;
}

View File

@@ -0,0 +1,3 @@
package com.listerk.helible
data class BleDevice(val name: String, val address: String, val rssi: Int)

View File

@@ -0,0 +1,39 @@
package com.listerk.helible
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
class BleDeviceAdapter(private val devices: List<BleDevice>, private val gotoControlBtn: Button) :
RecyclerView.Adapter<BleDeviceAdapter.BleDeviceViewHolder>() {
private lateinit var itemView: View
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BleDeviceViewHolder {
itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_ble_device, parent, false)
return BleDeviceViewHolder(itemView)
}
override fun getItemCount(): Int = devices.size
override fun onBindViewHolder(holder: BleDeviceViewHolder, position: Int) {
holder.nameView.text = devices[position].name
holder.addressView.text = devices[position].address
holder.rssiView.text = devices[position].rssi.toString()
holder.cardView.setOnClickListener {
AppState.bleDevice = devices[position]
gotoControlBtn.isEnabled = true
}
}
class BleDeviceViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val cardView = itemView.rootView
val nameView = itemView.findViewById<TextView>(R.id.deviceName)
val addressView = itemView.findViewById<TextView>(R.id.deviceAddress)
val rssiView = itemView.findViewById<TextView>(R.id.deviceRssi)
}
}

View File

@@ -0,0 +1,67 @@
package com.listerk.helible
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.SeekBar
import android.widget.TextView
class ControlActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_control)
var sliderR1Value = 0
var sliderR2Value = 0
var sliderR3Value = 0
val sliderR1ValueText = findViewById<TextView>(R.id.sliderR1Value)
val sliderR2ValueText = findViewById<TextView>(R.id.sliderR2Value)
val sliderR3ValueText = findViewById<TextView>(R.id.sliderR3Value)
val sliderR1 = findViewById<SeekBar>(R.id.sliderR1)
val sliderR2 = findViewById<SeekBar>(R.id.sliderR2)
val sliderR3 = findViewById<SeekBar>(R.id.sliderR3)
sliderR1.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR1Value = progress
val val_text = getString(R.string.r_slider_text, 1, progress)
sliderR1ValueText.text = val_text
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
sliderR2.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR2Value = progress
val val_text = getString(R.string.r_slider_text, 2, progress)
sliderR2ValueText.text = val_text
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
sliderR3.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR3Value = progress
val val_text = getString(R.string.r_slider_text, 3, progress)
sliderR3ValueText.text = val_text
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
}

View File

@@ -1,67 +1,74 @@
package com.listerk.helible package com.listerk.helible
import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.widget.SeekBar import android.os.Handler
import android.widget.TextView import android.util.Log
import android.widget.Button
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val bluetoothAdapter: BluetoothAdapter by lazy {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
private val bleScanner: BluetoothLeScanner by lazy {
bluetoothAdapter.bluetoothLeScanner
}
private val foundDevices = mutableListOf<BleDevice>()
private val leScanCallback: ScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
super.onScanResult(callbackType, result)
val bleDevicesView = findViewById<RecyclerView>(R.id.bleDevicesView)
if (result.device.name.isNullOrBlank()) {
return
}
val deviceExists = foundDevices.any { it.address == result.device.address }
if (!deviceExists) {
foundDevices.add(BleDevice(result.device.name, result.device.address, result.rssi))
bleDevicesView.adapter?.notifyItemChanged(foundDevices.size - 1)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
var sliderR1Value = 0 val gotoControlButton = findViewById<Button>(R.id.gotoControlButton)
var sliderR2Value = 0 gotoControlButton.setOnClickListener {
var sliderR3Value = 0 val intent = Intent(this@MainActivity, ControlActivity::class.java)
startActivity(intent)
val sliderR1ValueText = findViewById<TextView>(R.id.sliderR1Value)
val sliderR2ValueText = findViewById<TextView>(R.id.sliderR2Value)
val sliderR3ValueText = findViewById<TextView>(R.id.sliderR3Value)
val sliderR1 = findViewById<SeekBar>(R.id.sliderR1)
val sliderR2 = findViewById<SeekBar>(R.id.sliderR2)
val sliderR3 = findViewById<SeekBar>(R.id.sliderR3)
sliderR1.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR1Value = progress
val val_text = getString(R.string.r_slider_text, 1, progress)
sliderR1ValueText.text = val_text
} }
override fun onStartTrackingTouch(seekBar: SeekBar?) {} val bleDevicesView = findViewById<RecyclerView>(R.id.bleDevicesView)
bleDevicesView.layoutManager = LinearLayoutManager(this)
bleDevicesView.adapter = BleDeviceAdapter(foundDevices, gotoControlButton)
override fun onStopTrackingTouch(seekBar: SeekBar?) { bleScanner.startScan(leScanCallback)
}
})
sliderR2.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR2Value = progress
val val_text = getString(R.string.r_slider_text, 2, progress)
sliderR2ValueText.text = val_text
} }
override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onResume() {
super.onResume()
override fun onStopTrackingTouch(seekBar: SeekBar?) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT), 1)
} }
})
sliderR3.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
sliderR3Value = progress
val val_text = getString(R.string.r_slider_text, 3, progress)
sliderR3ValueText.text = val_text
} }
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
} }

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<TextView
android:id="@+id/helloText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello helicopter!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/sliderR1"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/helloText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR1Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R1: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<SeekBar
android:id="@+id/sliderR2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/sliderR1Value"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR2Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R2: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<SeekBar
android:id="@+id/sliderR3"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/sliderR2Value"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR3Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R3: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -4,70 +4,37 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".ControlActivity">
<TextView <TextView
android:id="@+id/helloText" android:id="@+id/devicesTitle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Hello helicopter!" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="12dp"
android:textSize="24sp"
android:textStyle="bold"
android:text="Устройства" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bleDevicesView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/devicesTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:listitem="@layout/item_ble_device" />
<Button
android:id="@+id/gotoControlButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Далее"
android:enabled="false"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintBottom_toBottomOf="parent" />
<SeekBar
android:id="@+id/sliderR1"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/helloText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR1Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R1: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<SeekBar
android:id="@+id/sliderR2"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/sliderR1Value"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR2Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R2: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<SeekBar
android:id="@+id/sliderR3"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:max="65535"
app:layout_constraintTop_toBottomOf="@+id/sliderR2Value"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sliderR3Value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R3: 0 / 65536"
app:layout_constraintTop_toBottomOf="@+id/sliderR3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:paddingHorizontal="12dp"
android:paddingVertical="4dp">
<TextView
android:id="@+id/deviceName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:textSize="18sp"
android:text="Helicopter BLE" />
<TextView
android:id="@+id/deviceAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceName"
android:textSize="14sp"
android:text="C3:7A:F4:6E:2F:D6" />
<TextView
android:id="@+id/deviceRssi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="16sp"
android:text="-70" />
</androidx.constraintlayout.widget.ConstraintLayout>