commit 2c47239f6e706f60c53526fcdc87cf2f02134cfb Author: Nigreon Date: Wed Jul 8 23:56:29 2020 +0200 First Commit diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..015cb99 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,34 @@ +apply plugin: 'com.android.application' + +apply plugin: 'kotlin-android' + +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 28 + buildToolsVersion "29.0.1" + defaultConfig { + applicationId "net.nigreon.blegps" + minSdkVersion 25 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} diff --git a/app/libs/FastBLE-2.3.4.jar b/app/libs/FastBLE-2.3.4.jar new file mode 100644 index 0000000..a2a8e5d Binary files /dev/null and b/app/libs/FastBLE-2.3.4.jar differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/net/nigreon/blegps/ExampleInstrumentedTest.kt b/app/src/androidTest/java/net/nigreon/blegps/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..bdce342 --- /dev/null +++ b/app/src/androidTest/java/net/nigreon/blegps/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package net.nigreon.blegps + +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getTargetContext() + assertEquals("net.nigreon.blegps", appContext.packageName) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..649ccde --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/net/nigreon/blegps/BLEHRService.kt b/app/src/main/java/net/nigreon/blegps/BLEHRService.kt new file mode 100644 index 0000000..e5c5656 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/BLEHRService.kt @@ -0,0 +1,224 @@ +package net.nigreon.blegps + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.bluetooth.BluetoothGatt +import android.content.Intent +import android.os.Binder +import android.os.Build +import android.os.IBinder +import android.support.v4.app.NotificationCompat +import android.support.v4.content.LocalBroadcastManager +import android.util.Log +import com.clj.fastble.BleManager +import com.clj.fastble.callback.BleGattCallback +import com.clj.fastble.callback.BleNotifyCallback +import com.clj.fastble.callback.BleWriteCallback +import com.clj.fastble.data.BleDevice +import com.clj.fastble.exception.BleException +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.util.* + +class BLEHRService : Service() { + private val LOG_TAG = "BLEHRService" + private val CHANNEL_ID = "NotifID2" + private val binder = sBinder() + + val timerActivity = Timer() + + private lateinit var bleDevice: BleDevice + private val serviceHeartRateUuid: String = "0000180d-0000-1000-8000-00805f9b34fb" + private val characteristicHRControlPointUuid: String = "00002a39-0000-1000-8000-00805f9b34fb" + private val characteristicHRMeasurementUuid: String = "00002a37-0000-1000-8000-00805f9b34fb" + + private fun initNotificationHR() { + BleManager.getInstance().notify( + bleDevice, + serviceHeartRateUuid, + characteristicHRMeasurementUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "Notify HR Success") + //initNotificationPressure() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify HR Failure $exception") + //initNotificationPressure() + } + + override fun onCharacteristicChanged(data: ByteArray) { + //Log.v(LOG_TAG, "Notify Temperature Characteristic changed") + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + //texttemp.text = buffer.float.toString() + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBTHRM).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTHRM, buffer.get(1)) + ) + } + }) + } + + private fun startHRBLE() { + BleManager.getInstance().connect("CC:2C:24:71:9C:BC", object : BleGattCallback() { + override fun onStartConnect() { + + } + + override fun onConnectFail(bleDevice: BleDevice, exception: BleException) { + Log.v(LOG_TAG, "BLE HR Connection Failed $exception") + } + + override fun onConnectSuccess( + bleDeviceConnect: BleDevice, + gattConnect: BluetoothGatt, + status: Int + ) { + Log.v(LOG_TAG, "BLE HR Connection OK") + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBTHR).putExtra( + ServicesConstants.BROADCAST_KEY.KEYBTSTATUSHR, + true + ) + ) + bleDevice = bleDeviceConnect + + initNotificationHR() + + val t = object : TimerTask() { + override fun run() { + startHRBLEActivity() + } + } + timerActivity.scheduleAtFixedRate(t, 0, 9500) + + } + + override fun onDisConnected( + isActiveDisConnected: Boolean, + bleDevice: BleDevice, + gatt: BluetoothGatt, + status: Int + ) { + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBTHR).putExtra( + ServicesConstants.BROADCAST_KEY.KEYBTSTATUSHR, + false + ) + ) + timerActivity.cancel() + Log.v(LOG_TAG, "BLE HR Disconnected") + } + }) + } + + private fun stopHRBLE() { + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBTHR).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUSHR, false) + ) + + BleManager.getInstance().disconnect(bleDevice) + } + + private fun startHRBLEActivity() { + val data: ByteArray = byteArrayOf(0x15,0x01,0x01) + BleManager.getInstance().write( + bleDevice, + serviceHeartRateUuid, + characteristicHRControlPointUuid, + data, + object : BleWriteCallback() { + override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) { + //Log.v(LOG_TAG, "Start Activity sended") + } + + override fun onWriteFailure(exception: BleException) { + Log.v(LOG_TAG, "Start Activity Failure $exception") + } + }) + } + + private fun stopHRBLEActivity() { + val data: ByteArray = byteArrayOf(0x15,0x01,0x00) + BleManager.getInstance().write( + bleDevice, + serviceHeartRateUuid, + characteristicHRControlPointUuid, + data, + object : BleWriteCallback() { + override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) { + Log.v(LOG_TAG, "Stop Activity sended") + } + + override fun onWriteFailure(exception: BleException) { + Log.v(LOG_TAG, "Stop Activity send Failure $exception") + } + }) + } + + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + if(intent.action == ServicesConstants.HRSERVICEACTION.STARTFOREGROUND_ACTION) { + Log.i(LOG_TAG, "Received Start Foreground Intent ") + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Create the NotificationChannel + val name = "ChannelName" + val descriptionText = "ChannelDescription" + val importance = NotificationManager.IMPORTANCE_DEFAULT + val mChannel = NotificationChannel(CHANNEL_ID, name, importance) + mChannel.description = descriptionText + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(mChannel) + } + + var notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setContentTitle("BLE HR") + .setContentText("BLE HR active") + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + //.setContentIntent(pendingIntent) + .build() + + //pBLE = BLEProvider(application, baseContext) + startHRBLE() + + startForeground(ServicesConstants.NOTIFICATION_ID.FOREGROUND_HR_SERVICE,notification) + } else if(intent.action == ServicesConstants.HRSERVICEACTION.STOPFOREGROUND_ACTION) { + Log.i(LOG_TAG, "Received Stop Foreground Intent ") + //pBLE.disconnectBLE() + stopHRBLE() + stopForeground(true) + stopSelf() + } + return START_STICKY + } + + override fun onDestroy() { + super.onDestroy() + Log.i(LOG_TAG, "In onDestroy") + } + + override fun onBind(intent: Intent): IBinder? { + Log.v(LOG_TAG, "in onBind") + return binder + } + + override fun onRebind(intent: Intent) { + Log.v(LOG_TAG, "in onRebind") + super.onRebind(intent) + } + + override fun onUnbind(intent: Intent): Boolean { + Log.v(LOG_TAG, "in onUnbind") + return true + } + + inner class sBinder : Binder() { + // Return this instance of LocalService so clients can call public methods + fun getService(): BLEHRService = this@BLEHRService + } +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/BLEMockLocationService.kt b/app/src/main/java/net/nigreon/blegps/BLEMockLocationService.kt new file mode 100644 index 0000000..bfb49bd --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/BLEMockLocationService.kt @@ -0,0 +1,378 @@ +package net.nigreon.blegps + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.location.LocationManager +import android.os.* +import android.support.v4.app.NotificationCompat +import android.support.v4.content.LocalBroadcastManager +import android.util.Log +import java.io.File +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.io.IOException +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.text.SimpleDateFormat +import java.util.* +import kotlin.experimental.or + + +class BLEMockLocationService : Service() { + private val LOG_TAG = "BLEMockLocationService" + private val CHANNEL_ID = "NotifID" + public val ACTIVATION_CHANGE = 1 + private lateinit var pBLE: BLEProvider + private lateinit var mockGPS: MockLocationProvider + private var locationReceived = false + private var qualityReceived = false + private var gpsverbose = false + private var gpxopened = false + private var hrenable = false + private var tempenable = false + private lateinit var gpxoutputstream: FileOutputStream + + var gpsConf: GPSConfiguration = GPSConfiguration() + + // Location + private var currentLatitude: Double = -1.0 + private var currentLongitude: Double = -1.0 + private var currentElevation: Double = -1.0 + private var currentSpeed: Float = -1.0f + private var currentHeading: Float = -1.0f + private var currentEHPE: Float = -1.0f + // Quality + private var currentEVPE: Float = -1.0f + private var currentHDOP: Float = -1.0f + private var currentVDOP: Float = -1.0f + private var currentSatview: Byte = -1 + private var currentSatused: Byte = -1 + private var currentElevationGPS: Double = -1.0 + + private var currentHR: Byte = 0 + private var currentTemperature: Float = 0.0f + + private val binder = sBinder() + + fun locationChanged(intent: Intent) + { + Log.v(LOG_TAG, "Latitude Service Broadcast received") + currentLatitude = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLAT,-1.0) + currentLongitude = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLON,-1.0) + currentEHPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONEHPE,-1.0f) + currentElevation = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONELE,-1.0) + currentSpeed = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONSPEED,-1.0f) + currentHeading = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONHEADING,-1.0f) + mockGPS.pushLocation(currentLatitude,currentLongitude,currentElevation, currentSpeed, currentHeading, currentEHPE) + locationReceived = true + storeGPX() + } + + fun qualityChanged(intent: Intent) + { + //Log.v(LOG_TAG, "Latitude Service Broadcast received") + currentEHPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEHPE,-1.0f) + currentEVPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEVPE,-1.0f) + currentHDOP = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYHDOP,-1.0f) + currentVDOP = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYVDOP,-1.0f) + currentSatview = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATVIEW,-1) + currentSatused = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATUSED,-1) + currentElevationGPS = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYELEGPS,-1.0) + qualityReceived = true + storeGPX() + } + + fun HRChanged(intent: Intent) + { + currentHR = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYBTHRM,-1) + } + + fun bmpStatusChanged(intent: Intent) + { + tempenable = intent.getBooleanExtra(ServicesConstants.BROADCAST_KEY.KEYBMPSTATUS, false) + } + + fun tempChanged(intent: Intent) + { + currentTemperature = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYTEMP, -1.0f) + } + + fun taskerChanged(bundle: Bundle) { + Log.v(LOG_TAG, "taskerChanged") + if(bundle.containsKey(ServicesConstants.BROADCAST_KEY.KEYBOOST)) { + /*if (bundle.getBoolean(ServicesConstants.BROADCAST_KEY.KEYBOOST)) { + //gpsConf.gpsBoost = intent.getBooleanExtra(ServicesConstants.BROADCAST_KEY.KEYBOOST, false) + gpsConf.gpsBoost = true + } else { + gpsConf.gpsBoost = false + }*/ + gpsConf.gpsBoost = bundle.getBoolean(ServicesConstants.BROADCAST_KEY.KEYBOOST) + sendConfBLE(gpsConf) + Log.v(LOG_TAG, "Received Tasker Intent : Boost ${gpsConf.gpsBoost}") + } + } + + fun storeGPX() + { + if(gpxopened) { + if(!gpsverbose and locationReceived) + { + //writeGPX("${SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date())} $currentLatitude $currentLongitude $currentElevation m\n") + writeGPX("$currentElevation\n") + locationReceived = false + qualityReceived = false + } else if(gpsverbose and locationReceived and qualityReceived) { + //writeGPX("${SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date())} $currentLatitude $currentLongitude $currentElevation m\n") + //writeGPX("$currentEHPE m $currentEVPE m $currentHDOP $currentVDOP $currentSatused/$currentSatview $currentElevationGPS m\n") + //if(hrenable) { writeGPX("$currentHR bpm\n")} + //if(tempenable) { writeGPX("${currentTemperature}°C\n")} + writeGPX("$currentElevation\n" + + "\n") + if(hrenable or tempenable) + { + writeGPX("") + if(hrenable) + { + writeGPX("$currentHR") + } + if(tempenable) + { + writeGPX("$currentTemperature") + } + writeGPX("\n") + } + + writeGPX("$currentEHPE$currentEVPE$currentHDOP$currentVDOP$currentSatused$currentSatview$currentElevationGPS\n") + writeGPX("\n\n") + locationReceived = false + qualityReceived = false + } + } + } + + fun writeGPX(str: String) + { + try { + gpxoutputstream.write(str.toByteArray()) + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + } + + override fun onCreate() { + super.onCreate() + + mockGPS = MockLocationProvider(LocationManager.GPS_PROVIDER, baseContext) + + val brReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + when (intent?.action) { + ServicesConstants.BROADCAST_FILTER.FILTERLOCATION -> locationChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERQUALITY-> qualityChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERBTHRM-> HRChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERTEMP-> tempChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERBMP-> bmpStatusChanged(intent) + + + //BROADCAST_CHANGE_TYPE_CHANGED -> handleChangeTypeChanged() + } + } + } + + val manager = LocalBroadcastManager.getInstance(this) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERLOCATION)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERQUALITY)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERBTHRM)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERTEMP)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERBMP)) + //pBLE.registerBMP() + } + + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + if(intent.action == ServicesConstants.MOCKSERVICEACTION.STARTFOREGROUND_ACTION) { + Log.i(LOG_TAG, "Received Start Foreground Intent ") + + // val intentNotif = Intent(this, MainActivity::class.java) +// intentNotif.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + // intentNotif.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACT + + //val pendingIntent = PendingIntent.getActivity(this, 0, intentNotif, 0) + + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // Create the NotificationChannel + val name = "ChannelName" + val descriptionText = "ChannelDescription" + val importance = NotificationManager.IMPORTANCE_DEFAULT + val mChannel = NotificationChannel(CHANNEL_ID, name, importance) + mChannel.description = descriptionText + // Register the channel with the system; you can't change the importance + // or other notification behaviors after this + val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(mChannel) + } + + var notification = NotificationCompat.Builder(this, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setContentTitle("BLE GPS") + .setContentText("BLE & Mock active") + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + //.setContentIntent(pendingIntent) + .build() + + pBLE = BLEProvider(application, baseContext) + mockGPS.start() + startForeground(ServicesConstants.NOTIFICATION_ID.FOREGROUND_MOCK_SERVICE,notification) + } else if(intent.action == ServicesConstants.MOCKSERVICEACTION.STOPFOREGROUND_ACTION) { + Log.i(LOG_TAG, "Received Stop Foreground Intent ") + pBLE.disconnectBLE() + mockGPS.shutdown() + stopForeground(true) + stopSelf() + } else if(intent.action == ServicesConstants.MOCKSERVICEACTION.TASKER_ACTION){ + Log.i(LOG_TAG, "intent action : ${intent.action}") + taskerChanged(intent.extras) + } + return START_STICKY + } + override fun onDestroy() { + super.onDestroy() + Log.i(LOG_TAG, "In onDestroy") + } + + override fun onBind(intent: Intent): IBinder? { + Log.v(LOG_TAG, "in onBind") + return binder + } + + override fun onRebind(intent: Intent) { + Log.v(LOG_TAG, "in onRebind") + super.onRebind(intent) + } + + override fun onUnbind(intent: Intent): Boolean { + Log.v(LOG_TAG, "in onUnbind") + return true + } + + fun sendCalibrateBLE(calibrateval: Int) + { + val buffer = ByteBuffer.allocate(4) + buffer.order(ByteOrder.LITTLE_ENDIAN) + buffer.putInt(calibrateval) + pBLE.sendCalibrate(buffer.array()) + } + + fun HRStatusChanged(enable: Boolean) + { + hrenable = enable + } + + fun openGPX(datefilename: String) { + //val datefilename: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) + var gpxfilename = File( + Environment.getExternalStorageDirectory().path + File.separator + "BTGPS", + datefilename + ".gpx" + ) + var gpxdir = File(Environment.getExternalStorageDirectory().path + File.separator + "BTGPS") + var success = true; + if (!gpxdir.exists()) { + success = gpxdir.mkdir(); + } + + if (success) { + if(!gpxfilename.exists()) { + try { + gpxoutputstream = FileOutputStream(gpxfilename, true) + //val gpxheader = "GPX Header\n" + val gpxheader = + "\n" + + "\n" + + "" + + "${datefilename}" + + "${datefilename}\n" + + "\n" + + "\n" + + "\n" + + "${datefilename}\n" + + "\n" + writeGPX(gpxheader) + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + } else { + try { + gpxoutputstream = FileOutputStream(gpxfilename, true) + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + } + gpxopened = true + } + } + + fun closeGPX() + { + //val gpxfooter = "GPX Footer\n" + val gpxfooter = "\n" + writeGPX(gpxfooter) + gpxoutputstream.close() + gpxopened = false + } + + //fun sendConfBLE(bmpnrf: Boolean, bmpble: Boolean, bmp2gps: Boolean, exttemp: Boolean, gpsble: Boolean, gpsbleverb: Boolean, gpsserial: Boolean, gpsmode: Int, gpspoller: Short, gpssendbt: Short, bmppoller: Short) { + fun sendConfBLE(gpsConfNew: GPSConfiguration) { + gpsConf = gpsConfNew + val buffer = ByteBuffer.allocate(8) + buffer.order(ByteOrder.LITTLE_ENDIAN) + var activateByte1: Byte = 0 + var activateByte2: Byte = 0 + + if(gpsConf.bmpNrf) { activateByte1 = activateByte1.or(0x01) } + if(gpsConf.bmpBT) { activateByte1 = activateByte1.or(0x02) } + if(gpsConf.bmp2gps) { activateByte1 = activateByte1.or(0x04) } + if(gpsConf.extTemp) { activateByte1 = activateByte1.or(0x08) } + + if(gpsConf.gpsBLE) { activateByte2 = activateByte2.or(0x01) } + if(gpsConf.gpsVerbose) { activateByte2 = activateByte2.or(0x02) } + if(gpsConf.gpsSerial) { activateByte2 = activateByte2.or(0x04) } + if(gpsConf.gpsMode == 1 || gpsConf.gpsBoost) { + activateByte2 = activateByte2.or(0x08) + } else if(gpsConf.gpsMode == 2) { + activateByte2 = activateByte2.or(0x10) + } + + buffer.put(activateByte1) + buffer.put(activateByte2) + if(gpsConf.gpsBoost) { + buffer.putShort(4) + buffer.putShort(gpsConf.bmpPollerSend) + buffer.putShort(4) + } else { + buffer.putShort(gpsConf.gpsPollerSend) + buffer.putShort(gpsConf.bmpPollerSend) + buffer.putShort(gpsConf.gpsSendBTSend) + } + pBLE.sendConf(buffer.array()) + } + + inner class sBinder : Binder() { + // Return this instance of LocalService so clients can call public methods + fun getService(): BLEMockLocationService = this@BLEMockLocationService + } +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/BLEProvider.kt b/app/src/main/java/net/nigreon/blegps/BLEProvider.kt new file mode 100644 index 0000000..835aa97 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/BLEProvider.kt @@ -0,0 +1,389 @@ +package net.nigreon.blegps +import android.app.Application +import android.bluetooth.BluetoothGatt +import android.content.Context +import android.content.Intent +import android.support.v4.content.LocalBroadcastManager +import android.util.Log +import com.clj.fastble.BleManager +import com.clj.fastble.data.BleDevice +import com.clj.fastble.exception.BleException +import com.clj.fastble.callback.BleGattCallback +import com.clj.fastble.callback.BleNotifyCallback +import com.clj.fastble.callback.BleReadCallback +import com.clj.fastble.callback.BleWriteCallback +import java.nio.ByteBuffer +import java.nio.ByteOrder +import android.os.CountDownTimer +import android.os.Handler + + +class BLEProvider(val application: Application, val baseContext: Context) +{ + private lateinit var bleDevice: BleDevice + + private val serviceEnvironmentalSensingUuid: String = "0000181a-0000-1000-8000-00805f9b34fb" + private val serviceLNUuid: String = "00001819-0000-1000-8000-00805f9b34fb" + private val characteristicPressureUuid: String = "00002a6d-0000-1000-8000-00805f9b34fb" + private val characteristicTemperatureUuid: String = "00002a6e-0000-1000-8000-00805f9b34fb" + private val characteristicLSUuid: String = "00002a67-0000-1000-8000-00805f9b34fb" + private val characteristicPQUuid: String = "00002a69-0000-1000-8000-00805f9b34fb" + private val serviceWriteUuid: String = "00002000-0000-1000-8000-00805f9b34fb" + private val characteristicSatUuid: String = "00002002-0000-1000-8000-00805f9b34fb" + private val characteristicWriteUuid: String = "00002001-0000-1000-8000-00805f9b34fb" + private val characteristicCalibrateUuid: String = "00002003-0000-1000-8000-00805f9b34fb" + + private var connected = false + private var reconnectcount = 0 + + + private val LOG_TAG = "BLEProvider" + //private lateinit var baseContext: Context + + + init + { + connectBLE() + } + + fun delayFunction(function: ()-> Unit, delay: Long) { + Handler().postDelayed(function, delay) + } + + private fun connectBLE() + { + //BleManager.getInstance().init(application) + /*BleManager.getInstance() + .enableLog(true) + .setReConnectCount(10, 60000)*/ + + //BleManager.getInstance().operateTimeout = 5000 + //BleManager.getInstance().connect("24:6F:28:16:C1:F2", object : BleGattCallback() { + BleManager.getInstance().connect("E9:8E:8A:12:6F:3F", object : BleGattCallback() { + override fun onStartConnect() { + + } + + override fun onConnectFail(bleDevice: BleDevice, exception: BleException) { + Log.v(LOG_TAG, "BLE Connection Failed $exception") + if(reconnectcount <= 15) { + reconnectcount++ + delayFunction( { connectBLE() }, 60000) + } else { + reconnectcount=0 + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBT).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUS, false) + ) + connected=false + } + + } + + override fun onConnectSuccess(bleDeviceConnect: BleDevice, gattConnect: BluetoothGatt, status: Int) { + Log.v(LOG_TAG, "BLE Connection OK") + connected = true + reconnectcount = 0 + bleDevice = bleDeviceConnect + //initNotificationTemperature() + object : CountDownTimer(3000, 500) { + var tickCount = 0 + override fun onFinish() { + // When timer is finished + // Execute your code here + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBT).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUS, true) + ) + } + + override fun onTick(millisUntilFinished: Long) { + //Log.v(LOG_TAG, "Tick: $millisUntilFinished") + when (tickCount) { + 0 -> initNotificationTemperature() + 1 -> initNotificationPQ() + 2 -> initNotificationPressure() + 3 -> initNotificationSat() + 4 -> initNotificationLS() + } + tickCount++ + /*if(millisUntilFinished == 5000L) + { + initNotificationTemperature() + } else if(millisUntilFinished == 4000L) { + initNotificationPQ() + } else if(millisUntilFinished == 3000L) { + initNotificationPressure() + } else if(millisUntilFinished == 2000L) { + initNotificationSat() + } else if(millisUntilFinished == 1000L) { + initNotificationLS() + }*/ + // millisUntilFinished The amount of time until finished. + } + }.start() + //initNotificationPressure() + //initNotificationLS() + + + } + + override fun onDisConnected( + isActiveDisConnected: Boolean, + bleDevice: BleDevice, + gatt: BluetoothGatt, + status: Int + ) { + //connected = false + //LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + // Intent(ServicesConstants.BROADCAST_FILTER.FILTERBT).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUS, false) + //) + Log.v(LOG_TAG, "BLE Disconnected") + if(connected) { + connectBLE() + } + } + }) + + } + + private fun initNotificationPressure() { + BleManager.getInstance().notify( + bleDevice, + serviceEnvironmentalSensingUuid, + characteristicPressureUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "BLE Notify Pressure Success") + //initNotificationLS() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify Pressure Failure $exception") + //initNotificationLS() + } + + override fun onCharacteristicChanged(data: ByteArray) { + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + Log.v(LOG_TAG, "BLE Notify Pressure Characteristic changed") + //textpressure.text = buffer.getInt().toString() + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERPRESSURE).putExtra(ServicesConstants.BROADCAST_KEY.KEYPRESSURE, buffer.int) + ) + } + }) + } + + private fun initNotificationTemperature() { + BleManager.getInstance().notify( + bleDevice, + serviceEnvironmentalSensingUuid, + characteristicTemperatureUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "Notify Temperature Success") + //initNotificationPressure() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify Temperature Failure $exception") + //initNotificationPressure() + } + + override fun onCharacteristicChanged(data: ByteArray) { + Log.v(LOG_TAG, "Notify Temperature Characteristic changed") + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + //texttemp.text = buffer.float.toString() + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERTEMP).putExtra(ServicesConstants.BROADCAST_KEY.KEYTEMP, buffer.short/100f) + ) + } + }) + } + + private fun initNotificationLS() { + BleManager.getInstance().notify( + bleDevice, + serviceLNUuid, + characteristicLSUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "Notify LS Success") + //initNotificationPQ() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify LS Failure $exception") + //initNotificationPQ() + } + + @UseExperimental(ExperimentalUnsignedTypes::class) + override fun onCharacteristicChanged(data: ByteArray) { + Log.v(LOG_TAG, "Notify LS Characteristic changed ${data.size}") + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + //val flags: UShort = buffer.short.toUShort() + val speed: Float = buffer.short.toUShort().toFloat()/100.0f + val latitude: Double = buffer.int/10000000.0 + val longitude: Double = buffer.int/10000000.0 + val ehpe: Float = buffer.int.toUInt().toFloat()/100.0f + //val ehpe: Float = 5.0f + val elevation: Double = buffer.int/100.0 + val heading: Float = buffer.short.toUShort().toFloat()/100.0f + Log.v(LOG_TAG, "LS $latitude $longitude $speed $heading") + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERLOCATION).putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLAT, latitude) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLON, longitude) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONEHPE, ehpe) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONELE, elevation) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONSPEED, speed) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONHEADING, heading) + + ) + } + }) + } + + private fun initNotificationPQ() { + BleManager.getInstance().notify( + bleDevice, + serviceLNUuid, + characteristicPQUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "Notify PQ Success") + //initNotificationSat() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify PQ Failure $exception") + //initNotificationSat() + } + + @UseExperimental(ExperimentalUnsignedTypes::class) + override fun onCharacteristicChanged(data: ByteArray) { + Log.v(LOG_TAG, "Notify PQ Characteristic changed") + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + //val flags = buffer.short + val sat_view: Byte = buffer.get().toUByte().toByte() + val sat_used: Byte = buffer.get().toUByte().toByte() + val ehpe: Float = buffer.int.toUInt().toFloat()/100.0f + val evpe: Float = buffer.int.toUInt().toFloat()/100.0f + val hdop: Float = buffer.get().toUByte().toByte()*2/10.0f + val vdop: Float = buffer.get().toUByte().toByte()*2/10.0f + val elevation_gps: Double = buffer.int/100.0 + Log.v(LOG_TAG, "PQ $sat_view $sat_used $ehpe $evpe $hdop $vdop $elevation_gps") + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERQUALITY).putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATVIEW, sat_view) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATUSED, sat_used) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEHPE, ehpe) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEVPE, evpe) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYHDOP, hdop) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYVDOP, vdop) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYELEGPS, elevation_gps) + ) + } + }) + } + + private fun initNotificationSat() { + BleManager.getInstance().notify( + bleDevice, + serviceWriteUuid, + characteristicSatUuid, + object : BleNotifyCallback() { + override fun onNotifySuccess() { + Log.v(LOG_TAG, "Notify Sat Success") + //initNotificationSat() + } + + override fun onNotifyFailure(exception: BleException) { + Log.v(LOG_TAG, "BLE Notify Sat Failure $exception") + //initNotificationSat() + } + + override fun onCharacteristicChanged(data: ByteArray) { + Log.v(LOG_TAG, "Notify Sat Characteristic changed") + val buffer = ByteBuffer.wrap(data) + buffer.order(ByteOrder.LITTLE_ENDIAN) + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERSAT).putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGPSALL, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGPSUSED, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATSBASALL, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATSBASUSED, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGLONASSALL, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGLONASSUSED, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGALILEOALL, buffer.get()) + .putExtra(ServicesConstants.BROADCAST_KEY.KEYSATGALILEOUSED, buffer.get()) + ) + } + }) + } + + fun disconnectBLE() + { + if(connected) { + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBT).putExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUS, false) + ) + connected = false + + + BleManager.getInstance().stopNotify( + bleDevice, + serviceEnvironmentalSensingUuid, + characteristicTemperatureUuid + ) + BleManager.getInstance() + .stopNotify(bleDevice, serviceEnvironmentalSensingUuid, characteristicPressureUuid) + BleManager.getInstance().stopNotify(bleDevice, serviceLNUuid, characteristicLSUuid) + BleManager.getInstance().stopNotify(bleDevice, serviceLNUuid, characteristicPQUuid) + BleManager.getInstance().stopNotify(bleDevice, serviceWriteUuid, characteristicSatUuid) + BleManager.getInstance().disconnect(bleDevice) + //BleManager.getInstance().destroy() + } + } + + fun sendCalibrate(data: ByteArray) { + if(connected) { + BleManager.getInstance().write( + bleDevice, + serviceWriteUuid, + characteristicCalibrateUuid, + data, + object : BleWriteCallback() { + override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) { + Log.v(LOG_TAG, "Conf sended") + } + + override fun onWriteFailure(exception: BleException) { + Log.v(LOG_TAG, "Conf send Failure $exception") + } + }) + } + } + fun sendConf(data: ByteArray) { + if (connected) { + BleManager.getInstance().write( + bleDevice, + serviceWriteUuid, + characteristicWriteUuid, + data, + object : BleWriteCallback() { + override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) { + Log.v(LOG_TAG, "Conf sended") + } + + override fun onWriteFailure(exception: BleException) { + Log.v(LOG_TAG, "Conf send Failure $exception") + } + }) + } + } + /*fun registerBMP() + { + initNotificationPressure() + initNotificationTemperature() + }*/ +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/GPSConfiguration.kt b/app/src/main/java/net/nigreon/blegps/GPSConfiguration.kt new file mode 100644 index 0000000..2968ce3 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/GPSConfiguration.kt @@ -0,0 +1,16 @@ +package net.nigreon.blegps + +class GPSConfiguration { + var bmpNrf: Boolean = false + var bmpBT: Boolean = false + var bmp2gps: Boolean = false + var extTemp: Boolean = false + var gpsBLE: Boolean = false + var gpsVerbose: Boolean = false + var gpsSerial: Boolean = false + var gpsMode: Int = 0 + var gpsBoost: Boolean = false + var gpsPollerSend: Short = 0 + var gpsSendBTSend: Short = 0 + var bmpPollerSend: Short = 0 +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/MainActivity.kt b/app/src/main/java/net/nigreon/blegps/MainActivity.kt new file mode 100644 index 0000000..9c9f831 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/MainActivity.kt @@ -0,0 +1,614 @@ +package net.nigreon.blegps + +import android.support.v7.app.AppCompatActivity +import android.os.Bundle +import kotlinx.android.synthetic.main.activity_main.* +import android.content.Intent +import android.os.IBinder +import android.content.ComponentName +import android.content.Context +import android.content.ServiceConnection +import android.support.v4.content.LocalBroadcastManager +import android.content.BroadcastReceiver +import android.content.IntentFilter +import android.os.Handler +import android.util.Log +import android.view.View +import android.widget.AdapterView +import android.location.Location +import com.clj.fastble.BleManager +import java.text.SimpleDateFormat +import java.util.* +import android.content.SharedPreferences +import android.os.Environment +import java.io.File +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.io.IOException + +//https://stackoverflow.com/questions/1625249/android-how-to-bind-spinner-to-custom-object-list + +class MainActivity : AppCompatActivity() { + + private val LOG_TAG = "MainActivity" + + private lateinit var mBoundService: BLEMockLocationService + var mServiceBound = false + + private lateinit var mBoundServiceHR: BLEHRService + var mServiceBoundHR = false + + var currentPressure: Int = -1 + var currentTemperature: Float = -1.0f + var BTConnected = false + var BTHRConnected = false + var lastLocation: Location = Location("LastLocation") + + private lateinit var gpxfilename: String + private var gpxopened = false + + private lateinit var sharedPreferences: SharedPreferences + + + /*override fun onStart() { + super.onStart() + // Bind to LocalService + + }*/ + + fun delayFunction(function: ()-> Unit, delay: Long) { + Handler().postDelayed(function, delay) + } + + fun disconnectBT() + { + Intent(this, BLEMockLocationService::class.java).also { intent -> + intent.action = ServicesConstants.MOCKSERVICEACTION.STOPFOREGROUND_ACTION + startService(intent) + } + unbindService(mServiceConnection) + mServiceBound = false + } + + fun disconnectBTHR() + { + Intent(this, BLEHRService::class.java).also { intent -> + intent.action = ServicesConstants.HRSERVICEACTION.STOPFOREGROUND_ACTION + startService(intent) + } + unbindService(mServiceConnectionHR) + mServiceBoundHR = false + } + + fun filter01changed(intent: Intent) + { + Log.v(LOG_TAG, "Filter01 Broadcast received") + text01.text=intent.getIntExtra(ServicesConstants.BROADCAST_KEY.KEY01,-1).toString() + + } + fun temperatureChanged(intent: Intent) + { + Log.v(LOG_TAG, "Temperature Broadcast received") + currentTemperature = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYTEMP, -1.0f) + writeBMPText() + } + fun pressureChanged(intent: Intent) + { + Log.v(LOG_TAG, "Pressure Broadcast received") + currentPressure = intent.getIntExtra(ServicesConstants.BROADCAST_KEY.KEYPRESSURE,-1) + writeBMPText() + } + + fun BTChanged(intent: Intent) + { + val connected = intent.getBooleanExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUS,false) + if(connected) { + BTConnected=true + text01.text = "BT Connected" + Log.v(LOG_TAG, "BT Connected Broadcast received") + mBoundService.HRStatusChanged(BTHRConnected) + sendConfToBLEService() + if(swlog2file.isChecked()) + { + mBoundService.openGPX(gpxfilename) + gpxopened = true + } + } else { + text01.text = "BT Disconnected" + Log.v(LOG_TAG, "BT Disconnected Broadcast received") + BTConnected=false + swblepower.setChecked(false) + } + writeBMPText() + } + + fun BTChangedHR(intent: Intent) + { + val connected = intent.getBooleanExtra(ServicesConstants.BROADCAST_KEY.KEYBTSTATUSHR,false) + if(connected) { + BTHRConnected=true + text01.text = "BT HR Connected" + Log.v(LOG_TAG, "BT HR Connected Broadcast received") + if(BTConnected) { mBoundService.HRStatusChanged(true) } + } else { + text01.text = "BT HR Disconnected" + Log.v(LOG_TAG, "BT HR Disconnected Broadcast received") + BTHRConnected=false + if(BTConnected) { mBoundService.HRStatusChanged(false) } + } + writeBMPText() + } + + fun BTChangedHRM(intent: Intent) + { + texthr.text = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYBTHRM,0).toString() + " bpm" + } + + private fun convertLatLon(latitude: Double, longitude: Double): String { + val builder = StringBuilder() + + + val latitudeDegrees = Location.convert(Math.abs(latitude), Location.FORMAT_MINUTES) + //val latitudeSplit1 = latitudeDegrees.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (latitude < 0) { + builder.append("S ") + } else { + builder.append("N ") + } + val latitudeSplit1 = latitudeDegrees.split(':') + builder.append(latitudeSplit1[0]) + builder.append("°") + val latitudeSplit2 = latitudeSplit1[1].split(',') + builder.append(latitudeSplit2[0]) + builder.append(".") + builder.append(latitudeSplit2[1]) + builder.append(" ") + + + val longitudeDegrees = Location.convert(Math.abs(longitude), Location.FORMAT_MINUTES) + if (longitude < 0) { + builder.append("W ") + } else { + builder.append("E ") + } + val longitudeSplit1 = longitudeDegrees.split(':') + builder.append(longitudeSplit1[0]) + builder.append("°") + val longitudeSplit2 = longitudeSplit1[1].split(',') + builder.append(longitudeSplit2[0]) + builder.append(".") + builder.append(longitudeSplit2[1]) + + + return builder.toString() + } + + fun writeBMPText() + { + textbmp.text = "${currentPressure/100.0f} hPa $currentTemperature°C" + } + + fun writeLocationText(intent: Intent) + { + val currentLatitude = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLAT,-1.0) + val currentLongitude = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONLON,-1.0) + val currentEHPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONEHPE,-1.0f) + val currentElevation = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONELE,-1.0) + val currentSpeed = (intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONSPEED,-1.0f))/1000.0f*3600.0f + val currentHeading = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYLOCATIONHEADING,-1.0f) + var currentLocation: Location = Location("CurrentLocation") + currentLocation.latitude = currentLatitude + currentLocation.longitude = currentLongitude + + textlastfix.text = "${SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SSS").format(Date())}" + textlocation.text = "${convertLatLon(currentLatitude, currentLongitude)} $currentElevation m \n $currentLatitude $currentLongitude $currentElevation m" + textspeedheading.text = "$currentSpeed km/h $currentHeading° ${currentLocation.distanceTo(lastLocation)} m" + lastLocation = currentLocation + + if(swblegpsverbose.isChecked == false) { + textquality.text = "$currentEHPE m" + textsatellites.text = "Satellites in verbose" + } + } + + fun writeQualityText(intent: Intent) + { + val currentEHPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEHPE,-1.0f) + val currentEVPE = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYEVPE,-1.0f) + val currentHDOP = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYHDOP,-1.0f) + val currentVDOP = intent.getFloatExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYVDOP,-1.0f) + val sat_view = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATVIEW,-1) + val sat_used = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYSATUSED,-1) + val elevation_gps = intent.getDoubleExtra(ServicesConstants.BROADCAST_KEY.KEYQUALITYELEGPS,-1.0) + textquality.text = "$currentEHPE m $currentEVPE m $currentHDOP $currentVDOP $sat_used/$sat_view $elevation_gps m" + } + + fun writeSatText(intent: Intent) + { + val gpsall = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGPSALL,-1) + val gpsused = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGPSUSED,-1) + val sbasall = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATSBASALL,-1) + val sbasused = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATSBASUSED,-1) + val glonassall = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGLONASSALL,-1) + val glonassused = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGLONASSUSED,-1) + val galileoall = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGALILEOALL,-1) + val galileoused = intent.getByteExtra(ServicesConstants.BROADCAST_KEY.KEYSATGALILEOUSED,-1) + textsatellites.text = "GPS: $gpsused/$gpsall SBAS: $sbasused/$sbasall GLONASS: $glonassused/$glonassall GALILEO: $galileoused/$galileoall" + } + private fun sendCalibrateToBLEService() + { + if(BTConnected) { + val calibrateval: Int = editcalibratebmp2gps.text.toString().toInt()*100 + mBoundService.sendCalibrateBLE(calibrateval) + } + } + private fun sendConfToBLEService() + { + if(BTConnected) { + val bmppollersend: Float = resources.getStringArray(R.array.pollerval)[spinbmp.selectedItemPosition].toFloat() * 4 + var gpspollersend: Float + var gpssendbtsend: Float + var gpsmode: Int + + /*if(swblegpsboost.isChecked) + { + gpspollersend = 4f + gpssendbtsend = 4f + gpsmode = 1 + } else {*/ + gpspollersend = resources.getStringArray(R.array.pollerval)[spingps.selectedItemPosition].toFloat() * 4 + gpssendbtsend = resources.getStringArray(R.array.pollerval)[spingpssendbt.selectedItemPosition].toFloat() * 4 + gpsmode = spingpsmode.selectedItemPosition + //} + + var gpsConf: GPSConfiguration = GPSConfiguration() + + gpsConf.bmpNrf = swbmpnrf.isChecked + gpsConf.bmpBT = swbmpbt.isChecked + gpsConf.bmp2gps = swbmp2gps.isChecked + gpsConf.extTemp = swexttemp.isChecked + gpsConf.gpsBLE = swgpsble.isChecked + gpsConf.gpsVerbose = swblegpsverbose.isChecked + //gpsConf.gpsBoost = swblegpsboost.isChecked + gpsConf.gpsSerial = swgpsserial.isChecked + gpsConf.gpsMode = gpsmode + gpsConf.gpsPollerSend = gpspollersend.toShort() + gpsConf.gpsSendBTSend = gpssendbtsend.toShort() + gpsConf.bmpPollerSend = bmppollersend.toShort() + + mBoundService.sendConfBLE(gpsConf) + + } + } + private fun sendStopConfToBLEService() + { + if(BTConnected) { + val gpspollersend: Float = + resources.getStringArray(R.array.pollerval)[spingps.selectedItemPosition].toFloat() * 4 + val bmppollersend: Float = + resources.getStringArray(R.array.pollerval)[spinbmp.selectedItemPosition].toFloat() * 4 + val gpssendbtsend: Float = + resources.getStringArray(R.array.pollerval)[spingpssendbt.selectedItemPosition].toFloat() * 4 + + var gpsConf: GPSConfiguration = GPSConfiguration() + + gpsConf.bmpNrf = false + gpsConf.bmpBT = false + gpsConf.bmp2gps = false + gpsConf.extTemp = false + gpsConf.gpsBLE = false + gpsConf.gpsVerbose = false + gpsConf.gpsSerial = false + gpsConf.gpsMode = spingpsmode.selectedItemPosition + gpsConf.gpsPollerSend = gpspollersend.toShort() + gpsConf.gpsSendBTSend = gpssendbtsend.toShort() + gpsConf.bmpPollerSend = bmppollersend.toShort() + + mBoundService.sendConfBLE(gpsConf) + + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + BleManager.getInstance().init(application) + BleManager.getInstance() + .enableLog(true) + .setReConnectCount(1, 5000) + + BleManager.getInstance().operateTimeout = 5000 + + val brReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + + when (intent?.action) { + ServicesConstants.BROADCAST_FILTER.FILTER01 -> filter01changed(intent) + ServicesConstants.BROADCAST_FILTER.FILTERBT -> BTChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERBTHR -> BTChangedHR(intent) + ServicesConstants.BROADCAST_FILTER.FILTERBTHRM -> BTChangedHRM(intent) + ServicesConstants.BROADCAST_FILTER.FILTERTEMP -> temperatureChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERPRESSURE -> pressureChanged(intent) + ServicesConstants.BROADCAST_FILTER.FILTERLOCATION -> writeLocationText(intent) + ServicesConstants.BROADCAST_FILTER.FILTERQUALITY -> writeQualityText(intent) + ServicesConstants.BROADCAST_FILTER.FILTERSAT -> writeSatText(intent) + + //BROADCAST_CHANGE_TYPE_CHANGED -> handleChangeTypeChanged() + } + } + } + + spinbmp.setSelection(11) + spingps.setSelection(3) + spingpsmode.setSelection(1) + spingpssendbt.setSelection(10) + + lastLocation.latitude = 0.0 + lastLocation.longitude = 0.0 + + sharedPreferences = baseContext.getSharedPreferences("blegps_config", MODE_PRIVATE) + + /*sharedPreferences + .edit() + .putInt("inttest", 64) + .putString("stringtest", "24:6F:28:16:C1:F2") + .apply()*/ + + //text01.text = "MAC ${sharedPreferences.getString("stringtest", null)}" + + //mButton.setEnabled(false) + + /*buttonread.setOnClickListener { + //text01.text=edit01.text.toString() + BleManager.getInstance().read( + bleDevice, + serviceWriteUuid, + characteristicWriteUuid, + object : BleReadCallback() { + override fun onReadSuccess(data: ByteArray) { + text01.text = "Read OK" + textread.text = data.toString() + } + + override fun onReadFailure(exception: BleException) { + text01.text = "Read Failure $exception" + } + } + ) + } + buttonwrite.setOnClickListener { + val writeba: ByteArray = edit01.text.toString().toByteArray() + BleManager.getInstance().write( + bleDevice, + serviceWriteUuid, + characteristicWriteUuid, + writeba, + object : BleWriteCallback() { + override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray) { + text01.text = "Write OK" + } + + override fun onWriteFailure(exception: BleException) { + text01.text = "Write Failure $exception" + } + } + ) + }*/ + + swblepower.setOnCheckedChangeListener { _, isChecked -> + if(isChecked) { + Intent(this, BLEMockLocationService::class.java).also { intent -> + bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE) + intent.action = ServicesConstants.MOCKSERVICEACTION.STARTFOREGROUND_ACTION + startService(intent) + } + } else { + sendStopConfToBLEService() + delayFunction({ disconnectBT() }, 1500) + } + } + + swblehrpower.setOnCheckedChangeListener { _, isChecked -> + if(isChecked) { + Intent(this, BLEHRService::class.java).also { intent -> + bindService(intent, mServiceConnectionHR, Context.BIND_AUTO_CREATE) + intent.action = ServicesConstants.HRSERVICEACTION.STARTFOREGROUND_ACTION + startService(intent) + } + } else { + //sendStopConfToBLEService() + delayFunction({ disconnectBTHR() }, 1500) + } + } + + swbmpnrf.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + } + swbmpbt.setOnCheckedChangeListener { _, checked -> + if(checked) { + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBMP).putExtra(ServicesConstants.BROADCAST_KEY.KEYBMPSTATUS, true) + ) + } else { + LocalBroadcastManager.getInstance(baseContext).sendBroadcast( + Intent(ServicesConstants.BROADCAST_FILTER.FILTERBMP).putExtra(ServicesConstants.BROADCAST_KEY.KEYBMPSTATUS, false) + ) + } + sendConfToBLEService() + } + swbmp2gps.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + } + swexttemp.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + } + swgpsble.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + } + swblegpsverbose.setOnCheckedChangeListener { _, _ -> + sendConfToBLEService() + } + swgpsserial.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + } + /*swblegpsboost.setOnCheckedChangeListener { _,_ -> + sendConfToBLEService() + }*/ + swlog2file.setOnCheckedChangeListener { _, checked -> + if(checked) { + gpxfilename = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) + if (BTConnected) { + mBoundService.openGPX(gpxfilename) + gpxopened = true + } + } else { + if(BTConnected) { + mBoundService.closeGPX() + } else if(gpxopened) { + var gpxhandle = File( + Environment.getExternalStorageDirectory().path + File.separator + "BTGPS", + gpxfilename + ".gpx" + ) + var gpxoutputstream = FileOutputStream(gpxhandle, true) + try { + val gpxfooter = "\n" + gpxoutputstream.write(gpxfooter.toByteArray()) + } catch (e: FileNotFoundException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + gpxoutputstream.close() + } + gpxopened = false + } + //sendConfToBLEService() + } + + spingpsmode.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(p0: AdapterView<*>?) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + sendConfToBLEService() + } + + } + + spinbmp.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(p0: AdapterView<*>?) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + sendConfToBLEService() + } + + } + + spingps.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(p0: AdapterView<*>?) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + sendConfToBLEService() + } + + } + spingpssendbt.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onNothingSelected(p0: AdapterView<*>?) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { + sendConfToBLEService() + } + + } + + buttoncalibratebmp2gps.setOnClickListener { + //text01.text = editcalibratebmp2gps.text + sendCalibrateToBLEService() + } + + /*startmock.setOnClickListener { + //val startIntent = Intent(this,BLEMockLocationService::class.java) + //startIntent.action = ServicesConstants.MOCKSERVICEACTION.STARTFOREGROUND_ACTION + //startService(startIntent) + Intent(this, BLEMockLocationService::class.java).also { intent -> + bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE) + intent.action = ServicesConstants.MOCKSERVICEACTION.STARTFOREGROUND_ACTION + startService(intent) + } + } + stopmock.setOnClickListener { + //val stopIntent = Intent(this,BLEMockLocationService::class.java) + //stopIntent.action = ServicesConstants.MOCKSERVICEACTION.STOPFOREGROUND_ACTION + //startService(stopIntent) + //LocalBroadcastManager.getInstance(this) + // .unregisterReceiver(brReceiver) + Intent(this, BLEMockLocationService::class.java).also { intent -> + intent.action = ServicesConstants.MOCKSERVICEACTION.STOPFOREGROUND_ACTION + startService(intent) + } + unbindService(mServiceConnection) + mServiceBound = false + + }*/ + /*bCounter.setOnClickListener { + textread.text=mBoundService.getCounter().toString() + }*/ + + + val manager = LocalBroadcastManager.getInstance(this) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTER01)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERBT)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERBTHR)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERBTHRM)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERTEMP)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERPRESSURE)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERLOCATION)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERQUALITY)) + manager.registerReceiver(brReceiver, IntentFilter(ServicesConstants.BROADCAST_FILTER.FILTERSAT)) + + //LocalBroadcastManager.getInstance(this) + // .unregisterReceiver(broadCastReceiver) + } + + override fun onPause() { + super.onPause() + if(!swlog2file.isChecked) { + swblegpsverbose.setChecked(false) + } + } + + private val mServiceConnection = object : ServiceConnection { + + override fun onServiceDisconnected(name: ComponentName) { + mServiceBound = false + } + + override fun onServiceConnected(name: ComponentName, service: IBinder) { + val binder = service as BLEMockLocationService.sBinder + mBoundService = binder.getService() + mServiceBound = true + } + } + + private val mServiceConnectionHR = object : ServiceConnection { + + override fun onServiceDisconnected(name: ComponentName) { + mServiceBoundHR = false + } + + override fun onServiceConnected(name: ComponentName, service: IBinder) { + val binderHR = service as BLEHRService.sBinder + mBoundServiceHR = binderHR.getService() + mServiceBoundHR = true + } + } + +} diff --git a/app/src/main/java/net/nigreon/blegps/MockLocationProvider.kt b/app/src/main/java/net/nigreon/blegps/MockLocationProvider.kt new file mode 100644 index 0000000..7fa3f19 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/MockLocationProvider.kt @@ -0,0 +1,40 @@ +package net.nigreon.blegps + +import android.content.Context +import android.location.Location +import android.location.LocationManager +import android.os.SystemClock + +class MockLocationProvider(val providerName: String, val ctx: Context) { + + private val lm = ctx.getSystemService( + Context.LOCATION_SERVICE + ) as LocationManager + + fun start() { + + lm.addTestProvider( + providerName, false, false, false, false, true, + true, true, 0, 5 + ) + lm.setTestProviderEnabled(providerName, true) + } + + fun pushLocation(lat: Double, lon: Double, alt: Double, speed: Float, heading: Float, accuracy: Float) { + val mockLocation = Location(providerName) + mockLocation.latitude = lat + mockLocation.longitude = lon + mockLocation.altitude = alt + mockLocation.speed = speed + mockLocation.bearing = heading + mockLocation.time = System.currentTimeMillis() + mockLocation.accuracy = accuracy + mockLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos() + + lm.setTestProviderLocation(providerName, mockLocation) + } + + fun shutdown() { + lm.removeTestProvider(providerName) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/ServicesConstants.kt b/app/src/main/java/net/nigreon/blegps/ServicesConstants.kt new file mode 100644 index 0000000..4ae0109 --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/ServicesConstants.kt @@ -0,0 +1,73 @@ +package net.nigreon.blegps + +class ServicesConstants { + interface MOCKSERVICEACTION { + companion object { + val MAIN_ACTION = "net.nigreon.blegps.mockservice.action.main" + val STARTFOREGROUND_ACTION = "net.nigreon.blegps.mockservice.action.startforeground" + val STOPFOREGROUND_ACTION = "net.nigreon.blegps.mockservice.action.stopforeground" + val TASKER_ACTION = "net.nigreon.blegps.mockservice.action.tasker" + } + } + interface HRSERVICEACTION { + companion object { + //val MAIN_ACTION = "net.nigreon.blegps.mockservice.action.main" + val STARTFOREGROUND_ACTION = "net.nigreon.blegps.hrservice.action.startforeground" + val STOPFOREGROUND_ACTION = "net.nigreon.blegps.hrservice.action.stopforeground" + } + } + interface NOTIFICATION_ID { + companion object { + val FOREGROUND_MOCK_SERVICE = 101 + val FOREGROUND_HR_SERVICE = 102 + } + } + interface BROADCAST_FILTER { + companion object { + const val FILTER01 = "just.a.filter" + const val FILTERBT = "filter.bt" + const val FILTERBMP = "filter.bmp" + const val FILTERBTHR = "filter.bthr" + const val FILTERBTHRM = "filter.bthrm" + const val FILTERTEMP = "filter.temp" + const val FILTERPRESSURE = "filter.pressure" + const val FILTERLOCATION = "filter.location" + const val FILTERQUALITY = "filter.quality" + const val FILTERSAT = "filter.sat" + const val FILTERTASKER= "filter.tasker" + } + } + interface BROADCAST_KEY { + companion object { + const val KEY01 = "key01" + const val KEYBTSTATUS = "btstatus" + const val KEYBTSTATUSHR = "btstatushr" + const val KEYBTHRM = "bthrm" + const val KEYBMPSTATUS = "bmpstatus" + const val KEYTEMP = "temperature" + const val KEYPRESSURE = "pressure" + const val KEYBOOST = "boost" + const val KEYLOCATIONLAT = "latitude" + const val KEYLOCATIONLON = "longitude" + const val KEYLOCATIONELE = "elevation" + const val KEYLOCATIONSPEED = "speed" + const val KEYLOCATIONHEADING = "heading" + const val KEYLOCATIONEHPE = "lehpe" + const val KEYQUALITYSATVIEW = "satview" + const val KEYQUALITYSATUSED = "satused" + const val KEYQUALITYEHPE = "ehpe" + const val KEYQUALITYEVPE = "evpe" + const val KEYQUALITYHDOP = "hdop" + const val KEYQUALITYVDOP = "vdop" + const val KEYQUALITYELEGPS = "elevation_gps" + const val KEYSATGPSALL = "gpsall" + const val KEYSATGPSUSED = "gpsused" + const val KEYSATSBASALL = "sbasall" + const val KEYSATSBASUSED = "sbasused" + const val KEYSATGLONASSALL = "glonassall" + const val KEYSATGLONASSUSED = "glonassused" + const val KEYSATGALILEOALL = "galileoall" + const val KEYSATGALILEOUSED = "galileoused" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/nigreon/blegps/TaskerReceiver.kt b/app/src/main/java/net/nigreon/blegps/TaskerReceiver.kt new file mode 100644 index 0000000..4aff95c --- /dev/null +++ b/app/src/main/java/net/nigreon/blegps/TaskerReceiver.kt @@ -0,0 +1,23 @@ +package net.nigreon.blegps + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.support.v4.content.ContextCompat +import android.support.v4.content.LocalBroadcastManager +import android.util.Log + +class TaskerReceiver: BroadcastReceiver() { + private val LOG_TAG = "TaskerReceiver" + override fun onReceive(context: Context, intent: Intent) { + Log.v(LOG_TAG, "Receive") + val serviceIntent = Intent(context, BLEMockLocationService::class.java) + serviceIntent.action=ServicesConstants.MOCKSERVICEACTION.TASKER_ACTION + + //serviceIntent.putExtras(Intent(ServicesConstants.BROADCAST_FILTER.FILTERTASKER).putExtra(ServicesConstants.BROADCAST_KEY.KEYBOOST, false)) + serviceIntent.putExtras(intent) + //LocalBroadcastManager.getInstance(context).sendBroadcast( + // Intent(ServicesConstants.BROADCAST_FILTER.FILTERTASKER).putExtra(ServicesConstants.BROADCAST_KEY.KEYBOOST, true)) + ContextCompat.startForegroundService(context, serviceIntent) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..94fddf9 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +