Merge pull request #210 from simondankelmann/simondankelmann/dbMigration

Simondankelmann/db migration
This commit is contained in:
Simon Dankelmann 2024-01-02 10:22:27 +01:00 committed by GitHub
commit 72e0aee1aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 140 additions and 387 deletions

View File

@ -3,7 +3,20 @@
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
<State>
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="adb-ONYX9H7LWSGU7PVG-Zd1vHj._adb-tls-connect._tcp" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-01-02T09:12:19.995152136Z" />
</State>
</entry>
</value>
</component>

View File

@ -16,7 +16,7 @@ android {
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0.7"
versionName = "1.0.8"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

Binary file not shown.

View File

@ -12,7 +12,7 @@
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0.7",
"versionName": "1.0.8",
"outputFile": "app-debug.apk"
}
],

Binary file not shown.

View File

@ -12,7 +12,7 @@
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0.7",
"versionName": "1.0.8",
"outputFile": "app-release.apk"
}
],

View File

@ -84,10 +84,12 @@ class ContinuityActionModalAdvertisementSetGenerator: IAdvertisementSetGenerator
}
private val _manufacturerId = 76 // 0x004c == 76 = Apple
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets: MutableList<AdvertisementSet> = mutableListOf()
_nearbyActions.map { nearbyAction ->
val data = inputData ?: _nearbyActions
data.map { nearbyAction ->
var advertisementSet: AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_IOS
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_CONTINUITY_ACTION_MODALS

View File

@ -88,10 +88,12 @@ class ContinuityIos17CrashAdvertisementSetGenerator: IAdvertisementSetGenerator
return advertisementSet
}
}
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets: MutableList<AdvertisementSet> = mutableListOf()
_nearbyActions.map { nearbyAction ->
val data = inputData ?: _nearbyActions
data.map { nearbyAction ->
var advertisementSet: AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_IOS
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_CONTINUITY_IOS_17_CRASH

View File

@ -100,10 +100,12 @@ class ContinuityNewAirtagPopUpAdvertisementSetGenerator: IAdvertisementSetGenera
}
}
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
deviceData.forEach{deviceData ->
val data = inputData ?: deviceData
data.forEach{deviceData ->
val colorMap = getColorMap(deviceData.key)
val prefix = "05" // => NEW AIRTAG

View File

@ -96,10 +96,12 @@ class ContinuityNewDevicePopUpAdvertisementSetGenerator: IAdvertisementSetGenera
}
}
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
deviceData.forEach{deviceData ->
val data = inputData ?: deviceData
data.forEach{deviceData ->
val prefix = "07" // => NEW DEVICE
val color = "00"

View File

@ -263,10 +263,12 @@ class ContinuityNotYourDevicePopUpAdvertisementSetGenerator: IAdvertisementSetGe
}
}
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
deviceData.forEach{deviceData ->
val data = inputData ?: deviceData
data.forEach{deviceData ->
val colorMap = getColorMap(deviceData.key)
val prefix = "01" // => NOT YOUR DEVICE

View File

@ -56,11 +56,13 @@ class EasySetupBudsAdvertisementSetGenerator:IAdvertisementSetGenerator{
"011716" to "Sleek Black Buds2",
)
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
val data = inputData ?: _genuineBudsIds
// BUDS
_genuineBudsIds.map {
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_SAMSUNG
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_EASY_SETUP_BUDS

View File

@ -54,13 +54,13 @@ class EasySetupWatchAdvertisementSetGenerator:IAdvertisementSetGenerator{
"20" to "Green Watch6 Classic 43m",
)
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
val data = inputData ?: _genuineWatchIds
// WATCHES
_genuineWatchIds.map {
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_SAMSUNG
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_EASY_SETUP_WATCH

View File

@ -41,10 +41,12 @@ class FastPairDebugAdvertisementSetGenerator:IAdvertisementSetGenerator{
val serviceUuid = ParcelUuid(UUID.fromString("0000fe2c-0000-1000-8000-00805f9b34fb"))
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
_genuineDeviceIds.map {
val data = inputData ?: _genuineDeviceIds
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_ANDROID

View File

@ -511,10 +511,12 @@ class FastPairDevicesAdvertisementSetGenerator:IAdvertisementSetGenerator{
val serviceUuid = ParcelUuid(UUID.fromString("0000fe2c-0000-1000-8000-00805f9b34fb"))
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
_genuineDeviceIds.map {
val data = inputData ?: _genuineDeviceIds
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_ANDROID

View File

@ -55,10 +55,12 @@ class FastPairNonProductionAdvertisementSetGenerator:IAdvertisementSetGenerator{
val serviceUuid = ParcelUuid(UUID.fromString("0000fe2c-0000-1000-8000-00805f9b34fb"))
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
_genuineDeviceIds.map {
val data = inputData ?: _genuineDeviceIds
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_ANDROID

View File

@ -29,10 +29,12 @@ class FastPairPhoneSetupAdvertisementSetGenerator:IAdvertisementSetGenerator{
val serviceUuid = ParcelUuid(UUID.fromString("0000fe2c-0000-1000-8000-00805f9b34fb"))
override fun getAdvertisementSets():List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
_genuineDeviceIds.map {
val data = inputData ?: _genuineDeviceIds
data.map {
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_ANDROID

View File

@ -3,5 +3,6 @@ package de.simon.dankelmann.bluetoothlespam.AdvertisementSetGenerators
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSet
interface IAdvertisementSetGenerator {
fun getAdvertisementSets():List<AdvertisementSet>
fun getAdvertisementSets(inputData: Map<String, String>?):List<AdvertisementSet>
}

View File

@ -57,10 +57,12 @@ class LovespousePlayAdvertisementSetGenerator:IAdvertisementSetGenerator {
private val _manufacturerId = 255 // 0xFF == 255 == Typo Products, LLC
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets: MutableList<AdvertisementSet> = mutableListOf()
lovespousePlays.forEach { lovespousePlay ->
val data = inputData ?: lovespousePlays
data.forEach { lovespousePlay ->
var advertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_LOVESPOUSE
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_LOVESPOUSE_PLAY

View File

@ -33,10 +33,12 @@ class LovespouseStopAdvertisementSetGenerator:IAdvertisementSetGenerator {
private val _manufacturerId = 255 // 0xFF == 255 == Typo Products, LLC
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets: MutableList<AdvertisementSet> = mutableListOf()
lovespouseStops.forEach { lovespouseStop ->
val data = inputData ?: lovespouseStops
data.forEach { lovespouseStop ->
var advertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_LOVESPOUSE
advertisementSet.type = AdvertisementSetType.ADVERTISEMENT_TYPE_LOVESPOUSE_STOP

View File

@ -22,23 +22,27 @@ class SwiftPairAdvertisementSetGenerator : IAdvertisementSetGenerator {
// https://github.com/Flipper-XFW/Xtreme-Firmware/blob/dev/applications/external/ble_spam/protocols/swiftpair.c
private val _prependedBytes = StringHelpers.decodeHex("030080")
private var _deviceNames = mutableListOf(
"Device 1",
"Device 2",
"Device 3",
"Device 4",
"Device 5",
"Device 6",
"Device 7",
"Device 8",
"Device 9",
"Device 10")
private val _deviceNames = mapOf(
"Device 1" to "Not used...",
"Device 2" to "Not used...",
"Device 3" to "Not used...",
"Device 4" to "Not used...",
"Device 5" to "Not used...",
"Device 6" to "Not used...",
"Device 7" to "Not used...",
"Device 8" to "Not used...",
"Device 9" to "Not used...",
"Device 10" to "Not used...",
)
private val _manufacturerId = 6 // 0x0006 == 6 = Microsoft
override fun getAdvertisementSets(): List<AdvertisementSet> {
override fun getAdvertisementSets(inputData: Map<String, String>?): List<AdvertisementSet> {
var advertisementSets:MutableList<AdvertisementSet> = mutableListOf()
_deviceNames.map {deviceName ->
val data = inputData ?: _deviceNames
data.map {deviceName ->
var advertisementSet:AdvertisementSet = AdvertisementSet()
advertisementSet.target = AdvertisementTarget.ADVERTISEMENT_TARGET_WINDOWS
@ -63,7 +67,7 @@ class SwiftPairAdvertisementSetGenerator : IAdvertisementSetGenerator {
val manufacturerSpecificData = ManufacturerSpecificData()
manufacturerSpecificData.manufacturerId = _manufacturerId
manufacturerSpecificData.manufacturerSpecificData = _prependedBytes.plus(deviceName.toByteArray())
manufacturerSpecificData.manufacturerSpecificData = _prependedBytes.plus(deviceName.key.toByteArray())
advertisementSet.advertiseData.manufacturerData.add(manufacturerSpecificData)
advertisementSet.advertiseData.includeTxPower = false
@ -71,7 +75,7 @@ class SwiftPairAdvertisementSetGenerator : IAdvertisementSetGenerator {
// advertisementSet.scanResponse.includeTxPower = false
// General Data
advertisementSet.title = deviceName
advertisementSet.title = deviceName.key
// Callbacks
advertisementSet.advertisingSetCallback = GenericAdvertisingSetCallback()

View File

@ -42,6 +42,7 @@ import de.simon.dankelmann.bluetoothlespam.Database.Entities.AdvertisingSetParam
import de.simon.dankelmann.bluetoothlespam.Database.Entities.AssociatonCollectionListEntity
import de.simon.dankelmann.bluetoothlespam.Database.Entities.AssociationListSetEntity
import de.simon.dankelmann.bluetoothlespam.Database.Entities.PeriodicAdvertisingParametersEntity
import de.simon.dankelmann.bluetoothlespam.Database.Migrations.Migration_1_2
import de.simon.dankelmann.bluetoothlespam.Helpers.DatabaseHelpers
@androidx.room.Database(
@ -56,7 +57,7 @@ import de.simon.dankelmann.bluetoothlespam.Helpers.DatabaseHelpers
AssociatonCollectionListEntity::class,
AssociationListSetEntity::class,
PeriodicAdvertisingParametersEntity::class],
version = 1,
version = 2,
exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
@ -94,6 +95,8 @@ abstract class AppDatabase : RoomDatabase() {
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "BluetoothLeSpamDatabase.db")
.addCallback(seedDatabaseCallback(context))
.addMigrations(Migration_1_2)
//.fallbackToDestructiveMigration()
.build()
private fun seedDatabaseCallback(context: Context): Callback {
@ -136,7 +139,7 @@ abstract class AppDatabase : RoomDatabase() {
)
advertisementSetGenerators.forEach{ generator ->
val advertisementSets = generator.getAdvertisementSets()
val advertisementSets = generator.getAdvertisementSets(null)
advertisementSets.forEach{ advertisementSet ->
DatabaseHelpers.saveAdvertisementSet(advertisementSet)
}

View File

@ -0,0 +1,41 @@
package de.simon.dankelmann.bluetoothlespam.Database.Migrations
import android.util.Log
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import de.simon.dankelmann.bluetoothlespam.AdvertisementSetGenerators.ContinuityActionModalAdvertisementSetGenerator
import de.simon.dankelmann.bluetoothlespam.AppContext.AppContext
import de.simon.dankelmann.bluetoothlespam.Database.AppDatabase
import de.simon.dankelmann.bluetoothlespam.Helpers.DatabaseHelpers
val Migration_1_2 = object : Migration(1,2) {
private val _logTag = "Migration_1_2"
override fun migrate(database: SupportSQLiteDatabase) {
Log.d(_logTag, "Executing Migration...")
val nearbyActionsAdded = mapOf(
"05" to "Apple Watch",
"24" to "Apple Vision Pro",
"2F" to "Connect to other Device",
"21" to "Software Update",
)
val continuityActionModalAdvertisementSetGenerator = ContinuityActionModalAdvertisementSetGenerator()
val nearbyActionsAddedAdvertisementSets = continuityActionModalAdvertisementSetGenerator.getAdvertisementSets(nearbyActionsAdded)
Thread {
synchronized(this) {
AppDatabase.getInstance().isSeeding = true
nearbyActionsAddedAdvertisementSets.forEach{ advertisementSet ->
DatabaseHelpers.saveAdvertisementSet(advertisementSet)
}
AppDatabase.getInstance().isSeeding = false
}
}.start()
Log.d(_logTag, "Finished Executing Migration...")
}
}

View File

@ -1,6 +1,7 @@
package de.simon.dankelmann.bluetoothlespam.Helpers
import android.os.ParcelUuid
import androidx.sqlite.db.SupportSQLiteDatabase
import de.simon.dankelmann.bluetoothlespam.Database.AppDatabase
import de.simon.dankelmann.bluetoothlespam.Database.Entities.AdvertiseDataEntity
import de.simon.dankelmann.bluetoothlespam.Database.Entities.AdvertiseDataManufacturerSpecificDataEntity
@ -26,9 +27,10 @@ class DatabaseHelpers {
companion object{
private const val _logTag = "DatabaseHelpers"
fun saveAdvertisementSet(advertisementSet: AdvertisementSet):Int{
fun saveAdvertisementSet(advertisementSet: AdvertisementSet,):Int{
var database = AppDatabase.getInstance()
val database = AppDatabase.getInstance()
var advertisementSetEntity:AdvertisementSetEntity = AdvertisementSetEntity(
advertisementSet.id,

View File

@ -510,8 +510,7 @@ class StartFragment : Fragment() {
var database = AppDatabase.getInstance()
if(database != null){
removeMissingRequirement("Database is not initialized")
if(!database.isSeeding){
if(!database.isSeeding && !database.inTransaction()){
removeMissingRequirement("Database is Seeding")
_viewModel!!.isSeeding.postValue(false)
var numberOfAdvertisementSetEntities = database.advertisementSetDao().getAll().count()

View File

@ -1,303 +0,0 @@
package de.simon.dankelmann.bluetoothlespam.ui.swiftPair
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.LinearLayout
import android.widget.SeekBar
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieDrawable
import de.simon.dankelmann.bluetoothlespam.AdvertisementSetGenerators.SwiftPairAdvertisementSetGenerator
import de.simon.dankelmann.bluetoothlespam.AppContext.AppContext
import de.simon.dankelmann.bluetoothlespam.Constants.LogLevel
import de.simon.dankelmann.bluetoothlespam.Enums.AdvertisementError
import de.simon.dankelmann.bluetoothlespam.Enums.TxPowerLevel
import de.simon.dankelmann.bluetoothlespam.Handlers.AdvertisementSetQueueHandler
import de.simon.dankelmann.bluetoothlespam.Interfaces.Callbacks.IAdvertisementServiceCallback
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSet
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSetList
import de.simon.dankelmann.bluetoothlespam.Models.LogEntryModel
import de.simon.dankelmann.bluetoothlespam.R
import de.simon.dankelmann.bluetoothlespam.databinding.FragmentSwiftpairBinding
class SwiftPairFragment: Fragment(), IAdvertisementServiceCallback {
private var _binding: FragmentSwiftpairBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private var _viewModel: SwiftPairViewModel? = null
private var _advertisementSetQueueHandler: AdvertisementSetQueueHandler = AppContext.getAdvertisementSetQueueHandler()
private val _advertisementSets = SwiftPairAdvertisementSetGenerator().getAdvertisementSets()
private val _logTag = "SwiftPairFragment"
private lateinit var _toggleButton:Button
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val viewModel = ViewModelProvider(this).get(SwiftPairViewModel::class.java)
_viewModel = viewModel
_binding = FragmentSwiftpairBinding.inflate(inflater, container, false)
val root: View = binding.root
_advertisementSetQueueHandler.addAdvertisementServiceCallback(this)
_advertisementSetQueueHandler.clearAdvertisementSetCollection()
_advertisementSetQueueHandler.addAdvertisementSetList(getAdvertisementSetList())
setupUi()
return root
}
fun getAdvertisementSetList(): AdvertisementSetList {
var advertisementSetList = AdvertisementSetList()
advertisementSetList.title = "Swift Pairing"
advertisementSetList.advertisementSets = _advertisementSets.toMutableList()
return advertisementSetList
}
override fun onResume() {
super.onResume()
_advertisementSetQueueHandler.addAdvertisementServiceCallback(this)
_advertisementSetQueueHandler.clearAdvertisementSetCollection()
_advertisementSetQueueHandler.addAdvertisementSetList(getAdvertisementSetList())
}
override fun onPause() {
super.onPause()
_advertisementSetQueueHandler.removeAdvertisementServiceCallback(this)
if( _advertisementSetQueueHandler != null && _advertisementSetQueueHandler!!.isActive()){
stopAdvertising()
_advertisementSetQueueHandler.clearAdvertisementSetCollection()
}
}
fun startAdvertising(){
if( _advertisementSetQueueHandler != null){
_advertisementSetQueueHandler!!.activate()
val logEntry = LogEntryModel()
logEntry.level = LogLevel.Info
logEntry.message = "Started Advertising"
_viewModel!!.addLogEntry(logEntry)
_viewModel!!.isTransmitting.postValue(true)
_toggleButton.text = "Stop Advertising"
} else {
val logEntry = LogEntryModel()
logEntry.level = LogLevel.Info
logEntry.message = "Could not start Advertising"
_viewModel!!.addLogEntry(logEntry)
}
}
fun stopAdvertising(){
if( _advertisementSetQueueHandler != null){
_advertisementSetQueueHandler!!.deactivate()
val logEntry = LogEntryModel()
logEntry.level = LogLevel.Info
logEntry.message = "Stopped Advertising"
_viewModel!!.addLogEntry(logEntry)
_viewModel!!.isTransmitting.postValue(false)
_toggleButton.text = "Start Advertising"
} else {
val logEntry = LogEntryModel()
logEntry.level = LogLevel.Info
logEntry.message = "Could not stop Advertising"
_viewModel!!.addLogEntry(logEntry)
}
}
fun setupUi(){
if(_viewModel != null){
// toggle button
val toggleBtn: Button = binding.advertiseButton
_toggleButton = toggleBtn
//animation view
val animationView: LottieAnimationView = binding.swiftPairAnimation
val toggleOnClickListener = View.OnClickListener { view ->
if( _advertisementSetQueueHandler != null){
if (! _advertisementSetQueueHandler!!.isActive()) {
startAdvertising()
} else {
stopAdvertising()
}
}
}
toggleBtn.setOnClickListener(toggleOnClickListener)
animationView.setOnClickListener(toggleOnClickListener)
_viewModel!!.isTransmitting.observe(viewLifecycleOwner) {
if(it == true){
animationView.repeatCount = LottieDrawable.INFINITE
animationView.playAnimation()
} else {
animationView.cancelAnimation()
}
}
// txPower
val fastPairingTxPowerSeekbar = binding.swiftPairTxPowerSeekbar
val fastPairingTxPowerSeekbarLabel: TextView = binding.swiftPairTxPowerSeekbarLabel
fastPairingTxPowerSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
var newTxPowerLevel = progress
var newTxPowerLabel = "High"
when (progress) {
0 -> {
newTxPowerLabel = "Ultra Low"
}
1 -> {
newTxPowerLabel = "Low"
}
2 -> {
newTxPowerLabel = "Medium"
}
3 -> {
newTxPowerLabel = "High"
} else -> {
newTxPowerLevel = 3
newTxPowerLabel = "High"
}
}
fastPairingTxPowerSeekbarLabel.text = "TX Power: ${newTxPowerLabel}"
if(_advertisementSetQueueHandler != null){
_advertisementSetQueueHandler!!.setTxPowerLevel(TxPowerLevel.TX_POWER_HIGH)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// you can probably leave this empty
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// you can probably leave this empty
}
})
// seekbar
val fastPairingRepeatitionSeekbar: SeekBar = binding.swiftPairRepeatitionSeekbar
val fastPairingRepeatitionLabel: TextView = binding.swiftPairRepeatitionSeekbarLabel
fastPairingRepeatitionSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
fastPairingRepeatitionLabel.text = "Advertise every ${progress} Seconds"
if( _advertisementSetQueueHandler != null){
_advertisementSetQueueHandler!!.setIntervalSeconds(progress)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// currently not in use
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// currently not in use
}
})
// status label
val statusLabelFastPairing: TextView = binding.statusLabelswiftPair
_viewModel!!.statusText.observe(viewLifecycleOwner) {
statusLabelFastPairing.text = it
}
// log scroll view
val logView: LinearLayout = binding.swiftPairLogLinearView
_viewModel!!.logEntries.observe(viewLifecycleOwner) {
logView.removeAllViews()
it.reversed().map { logEntryModel ->
val logEntryTextView: TextView = TextView(logView.context)
logEntryTextView.text = logEntryModel.message
when (logEntryModel.level){
LogLevel.Info -> {
logEntryTextView.setTextColor(ContextCompat.getColor(logView.context, R.color.log_info))
}
LogLevel.Warning -> {
logEntryTextView.setTextColor(ContextCompat.getColor(logView.context, R.color.log_warning))
}
LogLevel.Error -> {
logEntryTextView.setTextColor(ContextCompat.getColor(logView.context, R.color.log_error))
}
LogLevel.Success -> {
logEntryTextView.setTextColor(ContextCompat.getColor(logView.context, R.color.log_success))
}
}
logView.addView(logEntryTextView)
}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onAdvertisementSetStart(advertisementSet: AdvertisementSet?) {
if(advertisementSet != null){
var message = "Advertising: ${advertisementSet.title}"
_viewModel!!.setStatusText(message)
var logEntry = LogEntryModel()
logEntry.level = LogLevel.Info
logEntry.message = message
_viewModel!!.addLogEntry(logEntry)
}
}
override fun onAdvertisementSetStop(advertisementSet: AdvertisementSet?) {
Log.i(_logTag, "onAdvertisementSetStop called")
}
override fun onAdvertisementSetSucceeded(advertisementSet: AdvertisementSet?) {
var logEntry = LogEntryModel()
logEntry.level = LogLevel.Success
logEntry.message = "Started advertising successfully"
_viewModel!!.addLogEntry(logEntry)
}
override fun onAdvertisementSetFailed(advertisementSet: AdvertisementSet?, advertisementError: AdvertisementError) {
var message = if (advertisementError == AdvertisementError.ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
"ADVERTISE_FAILED_FEATURE_UNSUPPORTED"
} else if (advertisementError == AdvertisementError.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
"ADVERTISE_FAILED_TOO_MANY_ADVERTISERS"
} else if (advertisementError == AdvertisementError.ADVERTISE_FAILED_ALREADY_STARTED) {
"ADVERTISE_FAILED_ALREADY_STARTED"
} else if (advertisementError == AdvertisementError.ADVERTISE_FAILED_DATA_TOO_LARGE) {
"ADVERTISE_FAILED_DATA_TOO_LARGE"
} else if (advertisementError == AdvertisementError.ADVERTISE_FAILED_INTERNAL_ERROR) {
"ADVERTISE_FAILED_INTERNAL_ERROR"
} else {
"Unknown Error"
}
var logEntry = LogEntryModel()
logEntry.level = LogLevel.Error
logEntry.message = message
_viewModel!!.addLogEntry(logEntry)
}
}

View File

@ -1,31 +0,0 @@
package de.simon.dankelmann.bluetoothlespam.ui.swiftPair
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import de.simon.dankelmann.bluetoothlespam.Models.LogEntryModel
class SwiftPairViewModel : ViewModel(){
private val _statusText = MutableLiveData<String>().apply {
value = "Start Swift Pairing"
}
public fun setStatusText(text:String){
_statusText.postValue(text)
}
val isTransmitting = MutableLiveData<Boolean>().apply {
value = false
}
val logEntries = MutableLiveData<List<LogEntryModel>>().apply {
value = listOf()
}
fun addLogEntry(logEntry: LogEntryModel){
logEntries.value = logEntries.value?.plus(logEntry) ?: listOf(logEntry)
}
val statusText: LiveData<String> = _statusText
}