First Commit
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
/build
 | 
			
		||||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="net.nigreon.blegps">
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
 | 
			
		||||
    <application
 | 
			
		||||
        android:allowBackup="true"
 | 
			
		||||
        android:icon="@mipmap/ic_launcher"
 | 
			
		||||
        android:label="@string/app_name"
 | 
			
		||||
        android:roundIcon="@mipmap/ic_launcher_round"
 | 
			
		||||
        android:supportsRtl="true"
 | 
			
		||||
        android:theme="@style/AppTheme">
 | 
			
		||||
        <activity android:name=".MainActivity">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="android.intent.action.MAIN" />
 | 
			
		||||
 | 
			
		||||
                <category android:name="android.intent.category.LAUNCHER" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
        <service android:name=".BLEMockLocationService" ></service>
 | 
			
		||||
        <service android:name=".BLEHRService" ></service>
 | 
			
		||||
        <receiver android:name=".TaskerReceiver">
 | 
			
		||||
            <intent-filter>
 | 
			
		||||
                <action android:name="net.nigreon.blegps.TASKER_COMMAND" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </receiver>
 | 
			
		||||
    </application>
 | 
			
		||||
 | 
			
		||||
</manifest>
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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("<trkpt lat=\"$currentLatitude\" lon=\"$currentLongitude\"><ele>$currentElevation</ele><time>${SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date())}</time></trkpt>\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("<trkpt lat=\"$currentLatitude\" lon=\"$currentLongitude\"><ele>$currentElevation</ele><time>${SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date())}</time>\n" +
 | 
			
		||||
                        "<extensions>\n")
 | 
			
		||||
                        if(hrenable or tempenable)
 | 
			
		||||
                        {
 | 
			
		||||
                            writeGPX("<gpxtpx:TrackPointExtension>")
 | 
			
		||||
                            if(hrenable)
 | 
			
		||||
                            {
 | 
			
		||||
                                writeGPX("<gpxtpx:atemp>$currentHR</gpxtpx:atemp>")
 | 
			
		||||
                            }
 | 
			
		||||
                            if(tempenable)
 | 
			
		||||
                            {
 | 
			
		||||
                                writeGPX("<gpxtpx:atemp>$currentTemperature</gpxtpx:atemp>")
 | 
			
		||||
                            }
 | 
			
		||||
                            writeGPX("</gpxtpx:TrackPointExtension>\n")
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        writeGPX("<blegps:BLEGPSExtension><blegps:ehpe>$currentEHPE</blegps:ehpe><blegps:evpe>$currentEVPE</blegps:evpe><blegps:hdop>$currentHDOP</blegps:hdop><blegps:vdop>$currentVDOP</blegps:vdop><blegps:satused>$currentSatused</blegps:satused><blegps:satview>$currentSatview</blegps:satview><blegps:gpselevation>$currentElevationGPS</blegps:gpselevation></blegps:BLEGPSExtension>\n")
 | 
			
		||||
                        writeGPX("</extensions>\n</trkpt>\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 =
 | 
			
		||||
                        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n" +
 | 
			
		||||
                                "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" version=\"1.1\" " +
 | 
			
		||||
                                "xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\" " +
 | 
			
		||||
                                "xmlns:blegps=\"https://www.nigreon.net\"" +
 | 
			
		||||
                                ">\n" +
 | 
			
		||||
                                "<metadata>" +
 | 
			
		||||
                                "<name>${datefilename}</name>" +
 | 
			
		||||
                                "<desc>${datefilename}</desc>\n" +
 | 
			
		||||
                                "<time>${SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date())}</time>\n" +
 | 
			
		||||
                                "</metadata>\n" +
 | 
			
		||||
                                "<trk>\n" +
 | 
			
		||||
                                "<name>${datefilename}</name>\n" +
 | 
			
		||||
                                "<trkseg>\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 = "</trkseg></trk></gpx>\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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
    }*/
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = "</trkseg></trk></gpx>\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
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:aapt="http://schemas.android.com/aapt"
 | 
			
		||||
    android:width="108dp"
 | 
			
		||||
    android:height="108dp"
 | 
			
		||||
    android:viewportWidth="108"
 | 
			
		||||
    android:viewportHeight="108">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillType="evenOdd"
 | 
			
		||||
        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
 | 
			
		||||
        android:strokeWidth="1"
 | 
			
		||||
        android:strokeColor="#00000000">
 | 
			
		||||
        <aapt:attr name="android:fillColor">
 | 
			
		||||
            <gradient
 | 
			
		||||
                android:endX="78.5885"
 | 
			
		||||
                android:endY="90.9159"
 | 
			
		||||
                android:startX="48.7653"
 | 
			
		||||
                android:startY="61.0927"
 | 
			
		||||
                android:type="linear">
 | 
			
		||||
                <item
 | 
			
		||||
                    android:color="#44000000"
 | 
			
		||||
                    android:offset="0.0" />
 | 
			
		||||
                <item
 | 
			
		||||
                    android:color="#00000000"
 | 
			
		||||
                    android:offset="1.0" />
 | 
			
		||||
            </gradient>
 | 
			
		||||
        </aapt:attr>
 | 
			
		||||
    </path>
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#FFFFFF"
 | 
			
		||||
        android:fillType="nonZero"
 | 
			
		||||
        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
 | 
			
		||||
        android:strokeWidth="1"
 | 
			
		||||
        android:strokeColor="#00000000" />
 | 
			
		||||
</vector>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,170 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:width="108dp"
 | 
			
		||||
    android:height="108dp"
 | 
			
		||||
    android:viewportWidth="108"
 | 
			
		||||
    android:viewportHeight="108">
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#008577"
 | 
			
		||||
        android:pathData="M0,0h108v108h-108z" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M9,0L9,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,0L19,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M29,0L29,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M39,0L39,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M49,0L49,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M59,0L59,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M69,0L69,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M79,0L79,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M89,0L89,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M99,0L99,108"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,9L108,9"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,19L108,19"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,29L108,29"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,39L108,39"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,49L108,49"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,59L108,59"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,69L108,69"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,79L108,79"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,89L108,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M0,99L108,99"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,29L89,29"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,39L89,39"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,49L89,49"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,59L89,59"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,69L89,69"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M19,79L89,79"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M29,19L29,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M39,19L39,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M49,19L49,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M59,19L59,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M69,19L69,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
    <path
 | 
			
		||||
        android:fillColor="#00000000"
 | 
			
		||||
        android:pathData="M79,19L79,89"
 | 
			
		||||
        android:strokeWidth="0.8"
 | 
			
		||||
        android:strokeColor="#33FFFFFF" />
 | 
			
		||||
</vector>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,338 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<ScrollView
 | 
			
		||||
        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">
 | 
			
		||||
 | 
			
		||||
<LinearLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        tools:context=".MainActivity">
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity">
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="BLE GPS Power"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swblepower">
 | 
			
		||||
 | 
			
		||||
                </Switch>
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="BLE HR Power"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swblehrpower"/>
 | 
			
		||||
        <!--<Button
 | 
			
		||||
                android:text="Start Mock"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_margin="10dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:id="@+id/startmock"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="Stop Mock"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_margin="10dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:id="@+id/stopmock"/>-->
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
                xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:orientation="horizontal"
 | 
			
		||||
                tools:context=".MainActivity">
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="BMP nRF"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swbmpnrf"/>
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="BMP BT"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swbmpbt"/>
 | 
			
		||||
 | 
			
		||||
            <Switch
 | 
			
		||||
                    android:text="Ext Temp"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content" android:id="@+id/swexttemp"/>
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
            <LinearLayout
 | 
			
		||||
                    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:orientation="horizontal"
 | 
			
		||||
                    tools:context=".MainActivity">
 | 
			
		||||
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="GPS BLE"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swgpsble"/>
 | 
			
		||||
            <Switch
 | 
			
		||||
                    android:text="GPS Serial"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content" android:id="@+id/swgpsserial"/>
 | 
			
		||||
                <Switch
 | 
			
		||||
                        android:text="BMP2GPS"
 | 
			
		||||
                        android:layout_width="wrap_content"
 | 
			
		||||
                        android:layout_height="wrap_content" android:id="@+id/swbmp2gps"/>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Hello"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/text01"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Last fix time"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textlastfix"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Notification BMP"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textbmp"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Location"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textlocation"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Speed/Heading"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textspeedheading"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="HR"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/texthr"/>
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity">
 | 
			
		||||
    <Switch
 | 
			
		||||
            android:text="BLE GPS Verbose"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content" android:id="@+id/swblegpsverbose"/>
 | 
			
		||||
        <Switch
 | 
			
		||||
                android:text="Log2File"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swlog2file"/>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Quality"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textquality"/>
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Satellites"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textsatellites"/>
 | 
			
		||||
<!--    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="Read"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textread"/>
 | 
			
		||||
    <EditText
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:hint="Value Hint"
 | 
			
		||||
            android:id="@+id/edit01"/>
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity">
 | 
			
		||||
    <Button
 | 
			
		||||
            android:text="Read"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_margin="10dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:id="@+id/buttonread"/>
 | 
			
		||||
    <Button
 | 
			
		||||
            android:text="Write"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_margin="10dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:id="@+id/buttonwrite"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="Get Counter"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_margin="10dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:id="@+id/bCounter"/>
 | 
			
		||||
    </LinearLayout>-->
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity">
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="BMP Poller"
 | 
			
		||||
                android:layout_margin="0dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:layout_gravity="center_horizontal"
 | 
			
		||||
                android:id="@+id/textspinbmp"/>
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:id="@+id/spinbmp"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:entries="@array/poller" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
            xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
            xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity">
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:text="GPS Mode"
 | 
			
		||||
            android:layout_margin="0dp"
 | 
			
		||||
            android:padding="10dp"
 | 
			
		||||
            android:layout_gravity="center_horizontal"
 | 
			
		||||
            android:id="@+id/textspingpsmode"/>
 | 
			
		||||
    <Spinner
 | 
			
		||||
            android:id="@+id/spingpsmode"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:entries="@array/gpsmode"/>
 | 
			
		||||
        <!--<Switch
 | 
			
		||||
                android:text="BLE GPS Boost"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/swblegpsboost"/>-->
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
        <LinearLayout
 | 
			
		||||
                xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:orientation="horizontal"
 | 
			
		||||
                tools:context=".MainActivity">
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="GPS Poller"
 | 
			
		||||
                android:layout_margin="0dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:layout_gravity="center_horizontal"
 | 
			
		||||
                android:id="@+id/textspingps"/>
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:id="@+id/spingps"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:entries="@array/poller"/>
 | 
			
		||||
            <TextView
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:text="GPS BT"
 | 
			
		||||
                    android:layout_margin="0dp"
 | 
			
		||||
                    android:padding="10dp"
 | 
			
		||||
                    android:layout_gravity="center_horizontal"
 | 
			
		||||
                    android:id="@+id/textspingpssendbt"/>
 | 
			
		||||
            <Spinner
 | 
			
		||||
                    android:id="@+id/spingpssendbt"
 | 
			
		||||
                    android:layout_width="wrap_content"
 | 
			
		||||
                    android:layout_height="wrap_content"
 | 
			
		||||
                    android:entries="@array/poller"/>
 | 
			
		||||
 | 
			
		||||
        </LinearLayout>
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            tools:context=".MainActivity"
 | 
			
		||||
            android:focusableInTouchMode="true">
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="Calibrate BMP2GPS"
 | 
			
		||||
                android:layout_margin="0dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:layout_gravity="center_horizontal"
 | 
			
		||||
                android:id="@+id/textcalibratebmp2gps"/>
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:id="@+id/editcalibratebmp2gps"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:layout_gravity="center_horizontal"
 | 
			
		||||
                android:layout_margin="0dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:inputType="number" />
 | 
			
		||||
        <Button
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:text="Calibrate"
 | 
			
		||||
                android:layout_margin="0dp"
 | 
			
		||||
                android:padding="10dp"
 | 
			
		||||
                android:layout_gravity="center_horizontal"
 | 
			
		||||
                android:id="@+id/buttoncalibratebmp2gps"/>
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
</ScrollView>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <background android:drawable="@drawable/ic_launcher_background" />
 | 
			
		||||
    <foreground android:drawable="@drawable/ic_launcher_foreground" />
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <background android:drawable="@drawable/ic_launcher_background" />
 | 
			
		||||
    <foreground android:drawable="@drawable/ic_launcher_foreground" />
 | 
			
		||||
</adaptive-icon>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.9 KiB  | 
| 
		 After Width: | Height: | Size: 4.8 KiB  | 
| 
		 After Width: | Height: | Size: 2.0 KiB  | 
| 
		 After Width: | Height: | Size: 2.7 KiB  | 
| 
		 After Width: | Height: | Size: 4.4 KiB  | 
| 
		 After Width: | Height: | Size: 6.7 KiB  | 
| 
		 After Width: | Height: | Size: 6.2 KiB  | 
| 
		 After Width: | Height: | Size: 10 KiB  | 
| 
		 After Width: | Height: | Size: 8.9 KiB  | 
| 
		 After Width: | Height: | Size: 15 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<resources>
 | 
			
		||||
    <color name="colorPrimary">#008577</color>
 | 
			
		||||
    <color name="colorPrimaryDark">#00574B</color>
 | 
			
		||||
    <color name="colorAccent">#D81B60</color>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
<resources>
 | 
			
		||||
    <string name="app_name">BLEGPS</string>
 | 
			
		||||
    <string-array name="poller">
 | 
			
		||||
        <!--<item>250 ms</item>
 | 
			
		||||
        <item>500 ms</item>
 | 
			
		||||
        <item>750 ms</item>-->
 | 
			
		||||
        <item>1 s</item>
 | 
			
		||||
        <item>2 s</item>
 | 
			
		||||
        <item>3 s</item>
 | 
			
		||||
        <item>4 s</item>
 | 
			
		||||
        <item>5 s</item>
 | 
			
		||||
        <item>6 s</item>
 | 
			
		||||
        <item>7 s</item>
 | 
			
		||||
        <item>8 s</item>
 | 
			
		||||
        <item>9 s</item>
 | 
			
		||||
        <item>10 s</item>
 | 
			
		||||
        <item>20 s</item>
 | 
			
		||||
        <item>30 s</item>
 | 
			
		||||
        <item>40 s</item>
 | 
			
		||||
        <item>50 s</item>
 | 
			
		||||
        <item>1 min</item>
 | 
			
		||||
        <item>2 min</item>
 | 
			
		||||
        <item>3 min</item>
 | 
			
		||||
        <item>4 min</item>
 | 
			
		||||
        <item>5 min</item>
 | 
			
		||||
        <item>6 min</item>
 | 
			
		||||
        <item>7 min</item>
 | 
			
		||||
        <item>8 min</item>
 | 
			
		||||
        <item>9 min</item>
 | 
			
		||||
        <item>10 min</item>
 | 
			
		||||
        <item>20 min</item>
 | 
			
		||||
        <item>30 min</item>
 | 
			
		||||
        <item>40 min</item>
 | 
			
		||||
        <item>50 min</item>
 | 
			
		||||
        <item>60 min</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
    <string-array name="pollerval">
 | 
			
		||||
        <!--<item>0.25</item>
 | 
			
		||||
        <item>0.50</item>
 | 
			
		||||
        <item>0.75</item>-->
 | 
			
		||||
        <item>1</item>
 | 
			
		||||
        <item>2</item>
 | 
			
		||||
        <item>3</item>
 | 
			
		||||
        <item>4</item>
 | 
			
		||||
        <item>5</item>
 | 
			
		||||
        <item>6</item>
 | 
			
		||||
        <item>7</item>
 | 
			
		||||
        <item>8</item>
 | 
			
		||||
        <item>9</item>
 | 
			
		||||
        <item>10</item>
 | 
			
		||||
        <item>20</item>
 | 
			
		||||
        <item>30</item>
 | 
			
		||||
        <item>40</item>
 | 
			
		||||
        <item>50</item>
 | 
			
		||||
        <item>60</item>
 | 
			
		||||
        <item>120</item>
 | 
			
		||||
        <item>180</item>
 | 
			
		||||
        <item>240</item>
 | 
			
		||||
        <item>300</item>
 | 
			
		||||
        <item>360</item>
 | 
			
		||||
        <item>420</item>
 | 
			
		||||
        <item>480</item>
 | 
			
		||||
        <item>540</item>
 | 
			
		||||
        <item>600</item>
 | 
			
		||||
        <item>1200</item>
 | 
			
		||||
        <item>1800</item>
 | 
			
		||||
        <item>2400</item>
 | 
			
		||||
        <item>3000</item>
 | 
			
		||||
        <item>3600</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
    <string-array name="gpsmode">
 | 
			
		||||
        <item>Auto</item>
 | 
			
		||||
        <item>Normal</item>
 | 
			
		||||
        <item>Eco</item>
 | 
			
		||||
    </string-array>
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<resources>
 | 
			
		||||
 | 
			
		||||
    <!-- Base application theme. -->
 | 
			
		||||
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
 | 
			
		||||
        <!-- Customize your theme here. -->
 | 
			
		||||
        <item name="colorPrimary">@color/colorPrimary</item>
 | 
			
		||||
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
 | 
			
		||||
        <item name="colorAccent">@color/colorAccent</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
package net.nigreon.blegps
 | 
			
		||||
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
 | 
			
		||||
import org.junit.Assert.*
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Example local unit test, which will execute on the development machine (host).
 | 
			
		||||
 *
 | 
			
		||||
 * See [testing documentation](http://d.android.com/tools/testing).
 | 
			
		||||
 */
 | 
			
		||||
class ExampleUnitTest {
 | 
			
		||||
    @Test
 | 
			
		||||
    fun addition_isCorrect() {
 | 
			
		||||
        assertEquals(4, 2 + 2)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    ext.kotlin_version = '1.3.31'
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        jcenter()
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath 'com.android.tools.build:gradle:3.4.2'
 | 
			
		||||
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 | 
			
		||||
        // NOTE: Do not place your application dependencies here; they belong
 | 
			
		||||
        // in the individual module build.gradle files
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
    repositories {
 | 
			
		||||
        google()
 | 
			
		||||
        jcenter()
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
task clean(type: Delete) {
 | 
			
		||||
    delete rootProject.buildDir
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
# Project-wide Gradle settings.
 | 
			
		||||
# IDE (e.g. Android Studio) users:
 | 
			
		||||
# Gradle settings configured through the IDE *will override*
 | 
			
		||||
# any settings specified in this file.
 | 
			
		||||
# For more details on how to configure your build environment visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
 | 
			
		||||
# Specifies the JVM arguments used for the daemon process.
 | 
			
		||||
# The setting is particularly useful for tweaking memory settings.
 | 
			
		||||
org.gradle.jvmargs=-Xmx256m
 | 
			
		||||
# When configured, Gradle will run in incubating parallel mode.
 | 
			
		||||
# This option should only be used with decoupled projects. More details, visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 | 
			
		||||
# org.gradle.parallel=true
 | 
			
		||||
# Kotlin code style for this project: "official" or "obsolete":
 | 
			
		||||
kotlin.code.style=official
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
include ':app'
 | 
			
		||||