This commit is contained in:
2025-01-04 15:46:02 +01:00
parent 09b3ec6d68
commit d854b5ceec
9 changed files with 1008 additions and 951 deletions

View File

@@ -1,47 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.oilcheckkotlin">
<!-- for Android below 12 start -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- for Android below 12 end -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<!-- android:icon="@mipmap/ic_launcher"-->
<!-- android:roundIcon="@mipmap/ic_launcher_round"-->
<application
android:allowBackup="true"
android:icon="@drawable/draw_icon_blue"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.OilCheckKotlin">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".BLEConnectionService"></service>
<service android:name=".NLService"
android:exported="true"
android:enabled="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.oilcheckkotlin">
<!-- for Android below 12 start -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!-- for Android below 12 end -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<!-- android:icon="@mipmap/ic_launcher"-->
<!-- android:roundIcon="@mipmap/ic_launcher_round"-->
<application
android:allowBackup="true"
android:icon="@drawable/draw_icon_blue"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.OilCheckKotlin">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".BLEConnectionService"></service>
<service android:name=".NLService"
android:exported="true"
android:enabled="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
</manifest>

View File

@@ -1,209 +1,233 @@
package com.example.oilcheckkotlin
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.location.LocationManager
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.location.LocationManagerCompat
class BLEConnectionService : Service() {
val CHANNEL_DEFAULT_IMPORTANCE = "1"
val ONGOING_NOTIFICATION_ID = 2
var bleController: BLEController? = null
var deviceAddress: String? = null
var nlService = NLService()
private val myThread = Thread {
while (true){
Log.d("Runnable", "Working")
if(bleController == null) {
val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!LocationManagerCompat.isLocationEnabled(lm)) {
// Start Location Settings Activity, you should explain to the user why he need to enable location before.
startActivity(Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
Log.d("Debug", "bleController null")
// bleController = BLEController.getInstance(applicationContext)
bleController = BLEController(applicationContext)
} else if(!bleController!!.isConnected()){
// not connected
Log.d("Debug", "bleController not null but not connected")
bleController!!.init()
Log.d("Debug", "tried to init ble controller")
} else{
// controller is connected
Log.d("Debug", "BLE device connected")
bleController!!.stopScanner()
}
Thread.sleep(12000)
}
}
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if(intent?.action.equals("STARTService")){
Log.d("DEBUG", "Startflag set")
myThread.start()
// setup ble connection
val channel_id =
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
createNotificationChannel("my_service", "My Background Service")
} else {
""
}
val serviceIntent: PendingIntent = Intent(this, BLEConnectionService::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE)
}
val myIntent = Intent(this, MainActivity::class.java).apply {
var flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val contentIntent: PendingIntent = PendingIntent.getActivity(this, 0, myIntent, PendingIntent.FLAG_IMMUTABLE)
val notification: Notification = Notification.Builder(this, channel_id)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(R.drawable.icon)
.setContentIntent(serviceIntent)
// .setTicker(getText(R.string.ticker_text))
.build()
startForeground(101, notification)
// startService(Intent(this, NLService::class.java)
// .setAction("StartNLService")
// )
val nlServiceIntent: PendingIntent = Intent(this, NLService::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE)
}
val nlNotification: Notification = Notification.Builder(this, channel_id)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(R.drawable.icon)
.setContentIntent(nlServiceIntent)
// .setTicker(getText(R.string.ticker_text))
.build()
startForeground(101, nlNotification)
// setup notification listener
// val nlServiceIntent: PendingIntent = Intent(this, NLService::class.java).let { notificationIntent ->
// PendingIntent.getActivity(this, 0, notificationIntent,
// PendingIntent.FLAG_IMMUTABLE)
// }
//
// val nlNotification: Notification = Notification.Builder(this, channel_id)
// .setContentTitle("Oil-Check")
// .setContentText("running")
// .setSmallIcon(R.drawable.icon)
// .setContentIntent(nlServiceIntent)
//// .setTicker(getText(R.string.ticker_text))
// .build()
// startForeground(101, nlNotification)
} else if (intent?.action.equals("STOPService")){
Log.d("DEBUG", "Stopflag set")
stopForeground(true)
stopSelfResult(101)
stopSelf()
} else if (intent?.action.equals("StartNLService")) {
//
}
else if(intent?.action.equals("Toggle")){
try {
bleController!!.sendData("X".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "tried to toggle, but failed")
}
} else if(intent?.action.equals("X")){
try {
bleController!!.sendData("X".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send X, but connection failed")
}
} else if(intent?.action.equals("XX")){
try {
bleController!!.sendData("XX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XX, but connection failed")
}
} else if(intent?.action.equals("XXX")){
try {
bleController!!.sendData("XXX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XXX, but connection failed")
}
} else if(intent?.action.equals("XXXX")){
try {
bleController!!.sendData("XXXX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XXXX, but connection failed")
}
} else if(intent?.action.equals("OTA")) {
try {
bleController!!.sendData("U".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to update firmware, but connection failed")
}
}
else{
Log.d("Debug", "Intent without arguments occured in service")
}
return START_STICKY
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String{
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
override fun onBind(p0: Intent?): IBinder? {
// TODO("Not yet implemented")
return null;
}
override fun onDestroy() {
super.onDestroy()
this.myThread.interrupt()
}
package com.example.oilcheckkotlin
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.location.LocationManager
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.location.LocationManagerCompat
class BLEConnectionService : Service() {
val CHANNEL_DEFAULT_IMPORTANCE = "1"
val ONGOING_NOTIFICATION_ID = 2
var bleController: BLEController? = null
var deviceAddress: String? = null
var nlService = NLService()
private val myThread = Thread {
while (true){
Log.d("Runnable", "Working")
if(bleController == null) {
val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!LocationManagerCompat.isLocationEnabled(lm)) {
// Start Location Settings Activity, you should explain to the user why he need to enable location before.
startActivity(Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
Log.d("Debug", "bleController null")
bleController = BLEController(applicationContext)
if(!bleController!!.isConnected()){
bleController!!.init()
}
} else if(!bleController!!.isConnected()){
// not connected
Log.d("Debug", "bleController not null but not connected")
bleController!!.init()
Log.d("Debug", "tried to init ble controller")
} else{
// controller is connected
Log.d("Debug", "BLE device connected")
bleController!!.stopScanner()
}
Thread.sleep(12000)
}
}
override fun onCreate() {
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("DEBUG", "onStartCommand of BLE Connection Service")
if(intent?.action.equals("STARTService")){
Log.d("DEBUG", "Startflag set")
try {
myThread.start()
}
catch (e: Exception){
Log.d("DEBUG", "tried to start Thread, but failed :(")
}
// setup ble connection
val channel_id =
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
createNotificationChannel("my_service", "My Background Service")
} else {
""
}
val serviceIntent: PendingIntent = Intent(this, BLEConnectionService::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE)
}
val myIntent = Intent(this, MainActivity::class.java).apply {
var flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val activityIntent = Intent(this, MainActivity::class.java)
// val contentIntent: PendingIntent = PendingIntent.getActivity(this, 0, myIntent, PendingIntent.FLAG_IMMUTABLE)
val contentIntent = PendingIntent.getActivity(this, 0, activityIntent, PendingIntent.FLAG_MUTABLE);
// create stop button
// val intent = Intent(this, BLEConnectionService::class.java)
// .setAction("STOPService")
// val stopIntent = PendingIntent.getBroadcast(this, 0, intent, 0)
val notification: Notification = Notification.Builder(this, channel_id)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(R.drawable.icon)
.setContentIntent(serviceIntent)
// .setContentIntent(contentIntent)
// .setTicker(getText(R.string.ticker_text))
// .addAction(R.drawable.icon, "Stop", contentIntent)
.build()
startForeground(101, notification)
// startService(Intent(this, NLService::class.java)
// .setAction("StartNLService")
// )
val nlServiceIntent: PendingIntent = Intent(this, NLService::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE)
}
val nlNotification: Notification = Notification.Builder(this, channel_id)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(R.drawable.icon)
.setContentIntent(nlServiceIntent)
// .addAction(R.drawable.icon, "Stop", contentIntent)
// .setTicker(getText(R.string.ticker_text))
.build()
startForeground(101, nlNotification)
// setup notification listener
// val nlServiceIntent: PendingIntent = Intent(this, NLService::class.java).let { notificationIntent ->
// PendingIntent.getActivity(this, 0, notificationIntent,
// PendingIntent.FLAG_IMMUTABLE)
// }
//
// val nlNotification: Notification = Notification.Builder(this, channel_id)
// .setContentTitle("Oil-Check")
// .setContentText("running")
// .setSmallIcon(R.drawable.icon)
// .setContentIntent(nlServiceIntent)
//// .setTicker(getText(R.string.ticker_text))
// .build()
// startForeground(101, nlNotification)
} else if (intent?.action.equals("STOPService")){
Log.d("DEBUG", "Stopflag set")
stopForeground(true)
stopSelfResult(101)
stopSelf()
} else if (intent?.action.equals("StartNLService")) {
//
}
else if(intent?.action.equals("Toggle")){
try {
bleController!!.sendData("XX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "tried to toggle, but failed")
}
} else if(intent?.action.equals("X")){
try {
bleController!!.sendData("X".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send X, but connection failed")
}
} else if(intent?.action.equals("XX")){
try {
bleController!!.sendData("XX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XX, but connection failed")
}
} else if(intent?.action.equals("XXX")){
try {
bleController!!.sendData("XXX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XXX, but connection failed")
}
} else if(intent?.action.equals("XXXX")){
try {
bleController!!.sendData("XXXX".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to send XXXX, but connection failed")
}
} else if(intent?.action.equals("OTA")) {
try {
bleController!!.sendData("U".toByteArray(Charsets.UTF_8))
}
catch (e: Exception){
Log.d("Debug", "Tried to update firmware, but connection failed")
}
}
else{
Log.d("Debug", "Intent without arguments occured in service")
}
return START_STICKY
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(channelId: String, channelName: String): String{
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
override fun onBind(p0: Intent?): IBinder? {
// TODO("Not yet implemented")
return null;
}
override fun onDestroy() {
super.onDestroy()
this.myThread.interrupt()
}
}

View File

@@ -1,338 +1,380 @@
package com.example.oilcheckkotlin
import android.Manifest
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import java.util.Locale
class BLEController(ctx: Context) : BLEControllerListener{
companion object{
var instance: BLEController? = null
fun getInstance(ctx: Context?): BLEController? {
Log.d("BLEController", "called")
if (null == instance){
instance = BLEController(ctx!!)
}
return instance
}
}
private val SCAN_PERIOD: Long = 10000
private var deviceAddress: String? = null
var ctx: Context
private var devices = hashMapOf<String, BluetoothDevice>()
private var scanner: BluetoothLeScanner? = null
var bluetoothManager: BluetoothManager? = null
private var btGattChar: BluetoothGattCharacteristic? = null
private lateinit var bluetoothGatt: BluetoothGatt
private var device: BluetoothDevice? = null
private val listeners: ArrayList<BLEControllerListener> = ArrayList<BLEControllerListener>()
private var connectionState = false
fun stopScanner(){
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
try {
scanner!!.stopScan(bleCallback)
}
catch (e: Exception){
Log.d("Debug", "Scanner seems to run, stopping")
}
}
// constructor
init {
Log.d("Debug", "constructor called")
this.bluetoothManager = ctx.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
this.ctx = ctx
}
fun init(){
Log.d("Debug", "init")
this.devices?.clear()
Log.d("Debug", "get scanner")
this.scanner = this.bluetoothManager?.adapter?.bluetoothLeScanner
Log.d("Debug", "got scanner")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
// requestBluetooth.launch(enableBtIntent)
Log.d("Debug", "permission needed")
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
} else{
Log.d("Debug", "permission granted")
}
}
Log.d("Debug", "try to scan")
this.scanner?.startScan(bleCallback)
}
var bleCallback = object: ScanCallback(){
override fun onScanResult(callbackType: Int, result: ScanResult?) {
// Log.d("Debug", "onScanResult called")
val device = result?.device
// Log.d("Debug", "device result exists")
if (!devices?.containsKey(device?.address)!! && isThisTheDevice(device)) {
Log.d("Debug", "found the device")
deviceFound(device!!)
Log.d("Debug", device.address)
}
}
override fun onBatchScanResults(results: List<ScanResult?>?) {
Log.d("Debug", "onBatchScanResults called")
for (sr in results!!) {
val device = sr?.device
if (!devices!!.containsKey(device!!.address) && isThisTheDevice(device)) {
deviceFound(device!!)
}
}
}
override fun onScanFailed(errorCode: Int) {
Log.i("[BLE]", "scan failed with errorcode: $errorCode")
}
}
private fun isThisTheDevice(device: BluetoothDevice?): Boolean {
try {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return false
}
Log.d("BLE", device!!.name)
} catch (e: Exception) {
Log.d("BLE", "Device with null-Name found")
}
return null != device!!.name && device.name.startsWith("OilCheck")
}
private fun deviceFound(device: BluetoothDevice) {
Log.d("Debug", "deviceFound called")
// connectToDevice(device.address)
devices.put(device.address, device)
fireDeviceFound(device)
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
scanner!!.stopScan(bleCallback)
}
private fun fireDeviceFound(device: BluetoothDevice) {
// for (l in listeners) {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
Log.d("Debug", "BLEDeviceFound called")
BLEDeviceFound(device.name.trim { it <= ' ' }, device.address)
// }
}
fun connectToDevice(address: String?) {
Log.d("Debug", "connectToDevice")
this.device = devices[address!!]
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
scanner!!.stopScan(bleCallback)
try {
Log.i("[BLE]", "connect to device " + device!!.getAddress())
} catch (e: java.lang.Exception) {
Log.d("Debug", "Connection to device failed :(")
}
this.bluetoothGatt = device!!.connectGatt(null, true, this.bleConnectCallback)
}
private val bleConnectCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
val CHANNEL_ID = "ForegroundServiceChannel"
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
connectionState = true
Log.d("Debug", "connection state changed to connected")
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
Log.i("[BLE]", "start service discovery " + bluetoothGatt.discoverServices())
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
connectionState = false
Log.d("Debug", "connection state changed to not connected")
btGattChar = null
Log.w("[BLE]", "DISCONNECTED with status $status")
fireDisconnected()
} else {
Log.i("[BLE]", "unknown state $newState and status $status")
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (null == btGattChar) {
for (service in gatt.services) {
if (service.uuid.toString().uppercase(Locale.getDefault())
.startsWith("00001811")
) {
val gattCharacteristics = service.characteristics
for (bgc in gattCharacteristics) {
if (bgc.uuid.toString().uppercase(Locale.getDefault())
.startsWith("00002A46")
) {
val chprop = bgc.properties
if (chprop and BluetoothGattCharacteristic.PROPERTY_WRITE or (chprop and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
btGattChar = bgc
Log.i("[BLE]", "CONNECTED and ready to send")
fireConnected()
}
}
}
}
}
}
}
}
private fun fireDisconnected() {
for (l in listeners){
l.BLEControllerDisconnected()
}
device = null
}
fun isConnected():Boolean {
if(!connectionState){
return false
}
return true
}
fun sendData(data: ByteArray?) {
btGattChar!!.value = data
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
bluetoothGatt.writeCharacteristic(btGattChar)
}
private fun fireConnected() {
for (l in listeners) {
l.BLEControllerConnected()
}
}
override fun BLEControllerConnected() {
TODO("Not yet implemented")
}
override fun BLEControllerDisconnected() {
TODO("Not yet implemented")
}
override fun BLEDeviceFound(name: String?, address: String?) {
// log("Device $name found with address $address")
deviceAddress = address
Log.d("Debug", "connectToDevice called")
// btnConnect.setEnabled(true)
connectToDevice(deviceAddress)
}
package com.example.oilcheckkotlin
import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter.LeScanCallback
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.core.app.ActivityCompat
import java.util.Locale
class BLEController(ctx: Context) : BLEControllerListener{
companion object{
var instance: BLEController? = null
fun getInstance(ctx: Context?): BLEController? {
Log.d("BLEController", "called")
if (null == instance){
instance = BLEController(ctx!!)
}
return instance
}
}
private val SCAN_PERIOD: Long = 10000
private var deviceAddress: String? = null
var ctx: Context
private var devices = hashMapOf<String, BluetoothDevice>()
private var scanner: BluetoothLeScanner? = null
var bluetoothManager: BluetoothManager? = null
private var btGattChar: BluetoothGattCharacteristic? = null
private lateinit var bluetoothGatt: BluetoothGatt
private var device: BluetoothDevice? = null
private val listeners: ArrayList<BLEControllerListener> = ArrayList<BLEControllerListener>()
private var connectionState = false
private var scanning = false
fun stopScanner(){
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
try {
scanner!!.stopScan(bleCallback)
}
catch (e: Exception){
Log.d("Debug", "Scanner seems to run, stopping")
}
}
// constructor
init {
Log.d("Debug", "constructor called")
this.bluetoothManager = ctx.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
this.ctx = ctx
}
fun init(){
Log.d("Debug", "init")
this.devices?.clear()
Log.d("Debug", "get scanner")
this.scanner = this.bluetoothManager?.adapter?.bluetoothLeScanner
Log.d("Debug", "got scanner")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
// requestBluetooth.launch(enableBtIntent)
Log.d("Debug", "permission needed")
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
} else{
Log.d("Debug", "permission granted")
}
}
Log.d("Debug", "try to scan")
// this.scanner?.startScan(bleCallback)
this.scanForDevice()
}
@SuppressLint("MissingPermission")
fun scanForDevice(){
Log.d("DEBUG", "SCAN for Device started")
if(!scanning){
Handler(Looper.getMainLooper()).postDelayed({
scanning = false
this.scanner?.stopScan(bleCallback)
}, SCAN_PERIOD)
Log.d("DEBUG", "nach Haendler")
scanning = true
val bleScanSettings =
ScanSettings.Builder().setCallbackType((ScanSettings.CALLBACK_TYPE_FIRST_MATCH or ScanSettings.CALLBACK_TYPE_MATCH_LOST)).build()
val filter = ScanFilter.Builder().setDeviceName("OilCheck").build()
//
val devFilter: MutableList<ScanFilter> = ArrayList()
devFilter.add(filter)
this.scanner?.startScan(devFilter, bleScanSettings, bleCallback)
}
else{
scanning = false
this.scanner?.stopScan(bleCallback)
}
}
var bleCallback = object: ScanCallback(){
override fun onScanResult(callbackType: Int, result: ScanResult?) {
Log.d("Debug", "onScanResult called")
// val device = result?.device
val device = result?.getDevice()
// Log.d("Debug", "device result exists")
if (!devices?.containsKey(device?.address)!! && isThisTheDevice(device)) {
Log.d("Debug", "found the device")
deviceFound(device!!)
Log.d("Debug", device.address)
}
}
override fun onBatchScanResults(results: List<ScanResult?>?) {
Log.d("Debug", "onBatchScanResults called")
for (sr in results!!) {
val device = sr?.device
if (!devices!!.containsKey(device!!.address) && isThisTheDevice(device)) {
deviceFound(device!!)
}
}
}
override fun onScanFailed(errorCode: Int) {
Log.i("[BLE]", "scan failed with errorcode: $errorCode")
}
}
private fun isThisTheDevice(device: BluetoothDevice?): Boolean {
try {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return false
}
Log.d("BLE", device!!.name)
} catch (e: Exception) {
Log.d("BLE", "Device with null-Name found")
}
// return null != device!!.name && device.name.startsWith("OilCheck")
// "94:B9:7E:C0:53:FE") debugger
// "30:83:98:00:89:86" KTM
return null != (device!!.address.startsWith("94:B9:7E:C0:53:FE")
or device!!.address.startsWith("30:83:98:00:89:86"))
}
private fun deviceFound(device: BluetoothDevice) {
Log.d("Debug", "deviceFound called")
// connectToDevice(device.address)
devices.put(device.address, device)
fireDeviceFound(device)
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
scanner!!.stopScan(bleCallback)
}
private fun fireDeviceFound(device: BluetoothDevice) {
// for (l in listeners) {
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
Log.d("Debug", "BLEDeviceFound called")
BLEDeviceFound("device.name.trim { it <= ' ' }", device.address)
// }
}
fun connectToDevice(address: String?) {
Log.d("Debug", "connectToDevice")
this.device = devices[address!!]
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_SCAN
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
scanner!!.stopScan(bleCallback)
try {
Log.i("[BLE]", "connect to device " + device!!.getAddress())
} catch (e: java.lang.Exception) {
Log.d("Debug", "Connection to device failed :(")
}
this.bluetoothGatt = device!!.connectGatt(null, true, this.bleConnectCallback)
}
private val bleConnectCallback: BluetoothGattCallback = object : BluetoothGattCallback() {
val CHANNEL_ID = "ForegroundServiceChannel"
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
connectionState = true
Log.d("Debug", "connection state changed to connected")
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
Log.i("[BLE]", "start service discovery " + bluetoothGatt.discoverServices())
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
connectionState = false
Log.d("Debug", "connection state changed to not connected")
btGattChar = null
Log.w("[BLE]", "DISCONNECTED with status $status")
fireDisconnected()
} else {
Log.i("[BLE]", "unknown state $newState and status $status")
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
if (null == btGattChar) {
for (service in gatt.services) {
if (service.uuid.toString().uppercase(Locale.getDefault())
.startsWith("00001811")
) {
val gattCharacteristics = service.characteristics
for (bgc in gattCharacteristics) {
if (bgc.uuid.toString().uppercase(Locale.getDefault())
.startsWith("00002A46")
) {
val chprop = bgc.properties
if (chprop and BluetoothGattCharacteristic.PROPERTY_WRITE or (chprop and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
btGattChar = bgc
Log.i("[BLE]", "CONNECTED and ready to send")
fireConnected()
}
}
}
}
}
}
}
}
private fun fireDisconnected() {
for (l in listeners){
l.BLEControllerDisconnected()
}
device = null
}
fun isConnected():Boolean {
if(!connectionState){
return false
}
return true
}
fun sendData(data: ByteArray?) {
btGattChar!!.value = data
if (ActivityCompat.checkSelfPermission(
ctx,
Manifest.permission.BLUETOOTH_CONNECT
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
bluetoothGatt.writeCharacteristic(btGattChar)
}
private fun fireConnected() {
for (l in listeners) {
l.BLEControllerConnected()
}
}
override fun BLEControllerConnected() {
TODO("Not yet implemented")
}
override fun BLEControllerDisconnected() {
TODO("Not yet implemented")
}
override fun BLEDeviceFound(name: String?, address: String?) {
deviceAddress = address
Log.d("Debug", "connectToDevice called")
// btnConnect.setEnabled(true)
connectToDevice(deviceAddress)
}
}

View File

@@ -1,14 +1,14 @@
package com.example.oilcheckkotlin
/*
* (c) Matey Nenov (https://www.thinker-talk.com)
*
* Licensed under Creative Commons: By Attribution 3.0
* http://creativecommons.org/licenses/by/3.0/
*
*/
interface BLEControllerListener {
fun BLEControllerConnected()
fun BLEControllerDisconnected()
fun BLEDeviceFound(name: String?, address: String?)
package com.example.oilcheckkotlin
/*
* (c) Matey Nenov (https://www.thinker-talk.com)
*
* Licensed under Creative Commons: By Attribution 3.0
* http://creativecommons.org/licenses/by/3.0/
*
*/
interface BLEControllerListener {
fun BLEControllerConnected()
fun BLEControllerDisconnected()
fun BLEDeviceFound(name: String?, address: String?)
}

View File

@@ -1,213 +1,213 @@
package com.example.oilcheckkotlin
import android.app.Notification
import android.content.Intent
import android.os.IBinder
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import java.util.regex.Pattern
class NLService : NotificationListenerService() {
// override fun onBind(intent: Intent?): IBinder? {
// return super.onBind(intent)
// }
//
// override fun onNotificationPosted(sbn: StatusBarNotification?) {
// // Implement what you want here
// }
//
// override fun onNotificationRemoved(sbn: StatusBarNotification?) {
// // Implement what you want here
// }
//
// private final IBinder mBinder = new LocalBinder();
override fun onBind(intent: Intent): IBinder? {
return super.onBind(intent)
}
//returns the instance of the service
// public class LocalBinder extends Binder{
// public NLService getServiceInstance(){
// return NLService.this;
// }
// }
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d("Debug: ", "BLE service onStartCommand called")
// // String input = intent.getStringExtra("inputExtra");
// val input = "Text"
// createNotificationChannel()
// val notificationIntent = Intent(this, MainActivity::class.java)
// val pendingIntent = PendingIntent.getActivity(
// this,
// 0, notificationIntent, 0
// )
// val notification = NotificationCompat.Builder(this, CHANNEL_ID)
// .setContentTitle("Oil Check")
// .setContentText(input) //.setSmallIcon(R.drawable.ic_launcher_foreground)
// .setSmallIcon(R.drawable.icon)
// .setContentIntent(pendingIntent)
// .build()
// startForeground(1, notification)
// // NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
//// notificationManager.notify(3, notification);
// try {
// bleController = BLEController.getInstance(applicationContext)
// Log.d("BLE", "bleController instance")
// } catch (e: Exception) {
// Log.d("BLE", "bleController not available")
// }
return START_NOT_STICKY
}
// private fun createNotificationChannel() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val serviceChannel = NotificationChannel(
// CHANNEL_ID,
// "Foreground Service Channel",
// NotificationManager.IMPORTANCE_DEFAULT
// )
// val manager = getSystemService(
// NotificationManager::class.java
// )
// manager.createNotificationChannel(serviceChannel)
// }
// }
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.d("Debug", "NL Notification fired")
// Implement what you want here
if (sbn.packageName.contains("de.blitzer.plus")) {
Log.d(sbn.packageName, "sbn.getTag()")
Log.d("MyNotification", sbn.notification.toString())
// filter for digits
try {
val notification =
sbn.notification.extras.getCharSequence(Notification.EXTRA_TEXT).toString()
// check of unit in m or km
val unitM = "(.*)[\\d][m][\\s](.*)"
val unitKm = "(.*)[\\d][k][m][\\s](.*)"
Log.d("Unit", unitM)
if (notification.matches(unitM.toRegex())) {
Log.d("Notification", "meter")
Log.d("Notification", notification)
// notification in meters
// get digits
val pattern = Pattern.compile("[\\d]+[m][\\s]")
val matcher = pattern.matcher(notification)
while (matcher.find()) {
Log.d("Matcher", "Match found")
val start = matcher.start()
val end = matcher.end()
// Log.d("Start", )
// end -2 (one for blank and one for unit(m))
val digits = notification.substring(start, end - 2)
Log.d("Matcher", digits)
val distance = digits.toInt()
Log.d("Distanz", digits)
try {
if (distance > 500) {
Log.d("Distanz", "groesser 500")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("X")
startService(intent)
// bleController!!.sendData(String("X").toByteArray())
} else if (distance > 300) {
Log.d("Distanz", "groesser 300")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XX")
startService(intent)
} else if (distance > 150) {
Log.d("Distanz", "groesser 150")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XXX")
startService(intent)
} else {
Log.d("Distanz", "kleiner 100")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XXXX")
startService(intent)
}
} catch (e: Exception) {
//
Log.d("DEBUG", "Send Data failed :(")
}
// end while loop after first match
break
}
} else if (notification.matches(unitKm.toRegex())) {
// notification in kilometers
// no need to differ, to much distance
// bleController!!.sendData(String("X").toByteArray())
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("X")
startService(intent)
}
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("nicht gefunden") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("ungenau")){
// bleController.sendData(new String("XXXXX").getBytes());
// }
// else{
// bleController.sendData(new String("XXX").getBytes());
// }
} // old version not working anymore because of update of Blitzer.de
// try {
// if (sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("1.0km") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("1000m")) {
// bleController.sendData(new String("X").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("500m")){
// bleController.sendData(new String("XX").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("300m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("200m")){
// bleController.sendData(new String("XXX").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("100m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("90m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("80m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("70m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("50m")){
// bleController.sendData(new String("XXXX").getBytes());
// }
//// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("nicht gefunden") ||
//// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("ungenau")){
//// bleController.sendData(new String("XXXXX").getBytes());
//// }
//// else{
//// bleController.sendData(new String("XXX").getBytes());
//// }
// }
catch (e: Exception) {
Log.d("DEBUG", "Send notification failed :(")
}
// try {
// bleController.sendData(new String("X").getBytes());
// }
// catch(Exception e){
//
// }
}
// Log.d(sbn.getPackageName(), "packagename");
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// Implement what you want here
this.stopForeground(STOP_FOREGROUND_REMOVE)
}
override fun onDestroy() {
super.onDestroy()
Log.d("BLE:", "Service onDestory called")
this.stopForeground(STOP_FOREGROUND_REMOVE)
stopForeground(true)
// stopSelf();
}
companion object {
const val CHANNEL_ID = "ForegroundServiceChannel"
}
package com.example.oilcheckkotlin
import android.app.Notification
import android.content.Intent
import android.os.IBinder
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import java.util.regex.Pattern
class NLService : NotificationListenerService() {
// override fun onBind(intent: Intent?): IBinder? {
// return super.onBind(intent)
// }
//
// override fun onNotificationPosted(sbn: StatusBarNotification?) {
// // Implement what you want here
// }
//
// override fun onNotificationRemoved(sbn: StatusBarNotification?) {
// // Implement what you want here
// }
//
// private final IBinder mBinder = new LocalBinder();
override fun onBind(intent: Intent): IBinder? {
return super.onBind(intent)
}
//returns the instance of the service
// public class LocalBinder extends Binder{
// public NLService getServiceInstance(){
// return NLService.this;
// }
// }
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
Log.d("Debug: ", "BLE service onStartCommand called")
// // String input = intent.getStringExtra("inputExtra");
// val input = "Text"
// createNotificationChannel()
// val notificationIntent = Intent(this, MainActivity::class.java)
// val pendingIntent = PendingIntent.getActivity(
// this,
// 0, notificationIntent, 0
// )
// val notification = NotificationCompat.Builder(this, CHANNEL_ID)
// .setContentTitle("Oil Check")
// .setContentText(input) //.setSmallIcon(R.drawable.ic_launcher_foreground)
// .setSmallIcon(R.drawable.icon)
// .setContentIntent(pendingIntent)
// .build()
// startForeground(1, notification)
// // NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
//// notificationManager.notify(3, notification);
// try {
// bleController = BLEController.getInstance(applicationContext)
// Log.d("BLE", "bleController instance")
// } catch (e: Exception) {
// Log.d("BLE", "bleController not available")
// }
return START_NOT_STICKY
}
// private fun createNotificationChannel() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val serviceChannel = NotificationChannel(
// CHANNEL_ID,
// "Foreground Service Channel",
// NotificationManager.IMPORTANCE_DEFAULT
// )
// val manager = getSystemService(
// NotificationManager::class.java
// )
// manager.createNotificationChannel(serviceChannel)
// }
// }
override fun onNotificationPosted(sbn: StatusBarNotification) {
Log.d("Debug", "NL Notification fired")
// Implement what you want here
if (sbn.packageName.contains("de.blitzer.plus")) {
Log.d(sbn.packageName, "sbn.getTag()")
Log.d("MyNotification", sbn.notification.toString())
// filter for digits
try {
val notification =
sbn.notification.extras.getCharSequence(Notification.EXTRA_TEXT).toString()
// check of unit in m or km
val unitM = "(.*)[\\d][m][\\s](.*)"
val unitKm = "(.*)[\\d][k][m][\\s](.*)"
Log.d("Unit", unitM)
if (notification.matches(unitM.toRegex())) {
Log.d("Notification", "meter")
Log.d("Notification", notification)
// notification in meters
// get digits
val pattern = Pattern.compile("[\\d]+[m][\\s]")
val matcher = pattern.matcher(notification)
while (matcher.find()) {
Log.d("Matcher", "Match found")
val start = matcher.start()
val end = matcher.end()
// Log.d("Start", )
// end -2 (one for blank and one for unit(m))
val digits = notification.substring(start, end - 2)
Log.d("Matcher", digits)
val distance = digits.toInt()
Log.d("Distanz", digits)
try {
if (distance > 500) {
Log.d("Distanz", "groesser 500")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("X")
startService(intent)
// bleController!!.sendData(String("X").toByteArray())
} else if (distance > 300) {
Log.d("Distanz", "groesser 300")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XX")
startService(intent)
} else if (distance > 150) {
Log.d("Distanz", "groesser 150")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XXX")
startService(intent)
} else {
Log.d("Distanz", "kleiner 100")
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("XXXX")
startService(intent)
}
} catch (e: Exception) {
//
Log.d("DEBUG", "Send Data failed :(")
}
// end while loop after first match
break
}
} else if (notification.matches(unitKm.toRegex())) {
// notification in kilometers
// no need to differ, to much distance
// bleController!!.sendData(String("X").toByteArray())
val intent = Intent(this, BLEConnectionService::class.java)
.setAction("X")
startService(intent)
}
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("nicht gefunden") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("ungenau")){
// bleController.sendData(new String("XXXXX").getBytes());
// }
// else{
// bleController.sendData(new String("XXX").getBytes());
// }
} // old version not working anymore because of update of Blitzer.de
// try {
// if (sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("1.0km") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("1000m")) {
// bleController.sendData(new String("X").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("500m")){
// bleController.sendData(new String("XX").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("300m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("200m")){
// bleController.sendData(new String("XXX").getBytes());
// }
// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("100m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("90m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("80m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("70m") ||
// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("50m")){
// bleController.sendData(new String("XXXX").getBytes());
// }
//// else if(sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("nicht gefunden") ||
//// sbn.getNotification().extras.getCharSequence(Notification.EXTRA_TEXT).toString().contains("ungenau")){
//// bleController.sendData(new String("XXXXX").getBytes());
//// }
//// else{
//// bleController.sendData(new String("XXX").getBytes());
//// }
// }
catch (e: Exception) {
Log.d("DEBUG", "Send notification failed :(")
}
// try {
// bleController.sendData(new String("X").getBytes());
// }
// catch(Exception e){
//
// }
}
// Log.d(sbn.getPackageName(), "packagename");
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// Implement what you want here
this.stopForeground(STOP_FOREGROUND_REMOVE)
}
override fun onDestroy() {
super.onDestroy()
Log.d("BLE:", "Service onDestory called")
this.stopForeground(STOP_FOREGROUND_REMOVE)
stopForeground(true)
// stopSelf();
}
companion object {
const val CHANNEL_ID = "ForegroundServiceChannel"
}
}

View File

@@ -1,32 +1,32 @@
package com.example.oilcheckkotlin
import android.R
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
class NotificationCreator {
private val NOTIFICATION_ID = 1094
private val CHANNEL_ID = "Foreground Service Channel"
private var notification: Notification? = null
fun getNotification(context: Context?, intent: PendingIntent): Notification? {
if (notification == null) {
notification = NotificationCompat.Builder(context!!, CHANNEL_ID)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(com.example.oilcheckkotlin.R.drawable.icon)
.setContentIntent(intent)
.build()
}
return notification
}
fun getNotificationId(): Int {
return NOTIFICATION_ID
}
package com.example.oilcheckkotlin
import android.R
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
class NotificationCreator {
private val NOTIFICATION_ID = 1094
private val CHANNEL_ID = "Foreground Service Channel"
private var notification: Notification? = null
fun getNotification(context: Context?, intent: PendingIntent): Notification? {
if (notification == null) {
notification = NotificationCompat.Builder(context!!, CHANNEL_ID)
.setContentTitle("Oil-Check")
.setContentText("running")
.setSmallIcon(com.example.oilcheckkotlin.R.drawable.icon)
.setContentIntent(intent)
.build()
}
return notification
}
fun getNotificationId(): Int {
return NOTIFICATION_ID
}
}

View File

@@ -6,15 +6,6 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="400dp"
android:layout_height="257dp"

View File

@@ -1,6 +1,6 @@
#Thu Aug 31 20:53:30 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
#Thu Aug 31 20:53:30 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

178
gradlew.bat vendored
View File

@@ -1,89 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega