Skip to content

Commit d685a7c

Browse files
Merge pull request simondankelmann#147 from simondankelmann/simondankelmann/foregroundservice
Simondankelmann/foregroundservice
2 parents 981cffe + f3f152f commit d685a7c

32 files changed

+741
-464
lines changed

app/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ android {
1616
minSdk = 26
1717
targetSdk = 34
1818
versionCode = 1
19-
versionName = "1.0.5"
19+
versionName = "1.0.6"
2020

2121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2222
}

app/debug/app-debug.apk

7.68 KB
Binary file not shown.

app/debug/output-metadata.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"filters": [],
1313
"attributes": [],
1414
"versionCode": 1,
15-
"versionName": "1.0.5",
15+
"versionName": "1.0.6",
1616
"outputFile": "app-debug.apk"
1717
}
1818
],

app/release/app-release.apk

3.5 KB
Binary file not shown.

app/release/output-metadata.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"filters": [],
1313
"attributes": [],
1414
"versionCode": 1,
15-
"versionName": "1.0.5",
15+
"versionName": "1.0.6",
1616
"outputFile": "app-release.apk"
1717
}
1818
],

app/src/main/AndroidManifest.xml

+7-1
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,22 @@
3636
android:name="android.hardware.bluetooth_le"
3737
android:required="true" />
3838

39+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
40+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
41+
3942
<application
4043
android:allowBackup="true"
4144
android:dataExtractionRules="@xml/data_extraction_rules"
4245
android:fullBackupContent="@xml/backup_rules"
4346
android:icon="@mipmap/ic_launcher"
4447
android:label="@string/app_name"
45-
android:roundIcon="@mipmap/ic_launcher_round"
48+
android:roundIcon="@mipmap/ic_launcher"
4649
android:supportsRtl="true"
4750
android:theme="@style/Theme.BluetoothLESpam.NoActionBar"
4851
tools:targetApi="31">
52+
<service android:name=".Services.AdvertisementForegroundService"></service>
53+
<receiver android:name=".Services.AdvertisementForegroundService$ToggleButtonListener" />
54+
<receiver android:name=".Services.AdvertisementForegroundService$StopButtonListener" />
4955
<activity
5056
android:name=".MainActivity"
5157
android:exported="true"

app/src/main/java/de/simon/dankelmann/bluetoothlespam/AppContext/AppContext.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.app.Activity
44
import android.bluetooth.BluetoothAdapter
55
import android.bluetooth.BluetoothManager
66
import android.content.Context
7+
import android.util.Log
78
import de.simon.dankelmann.bluetoothlespam.Handlers.AdvertisementSetQueueHandler
89
import de.simon.dankelmann.bluetoothlespam.Interfaces.Services.IAdvertisementService
910

@@ -29,7 +30,6 @@ abstract class AppContext {
2930
return false
3031
}
3132

32-
3333
fun setContext(context: Context) {
3434
_context = context
3535
}
@@ -54,6 +54,10 @@ abstract class AppContext {
5454
return _advertisementService
5555
}
5656

57+
fun advertisementServiceIsInitialized(): Boolean {
58+
return this::_advertisementService.isInitialized
59+
}
60+
5761
fun setAdvertisementSetQueueHandler(advertisementSetQueueHandler: AdvertisementSetQueueHandler) {
5862
_advertisementSetQueueHandler = advertisementSetQueueHandler
5963
}
@@ -62,6 +66,10 @@ abstract class AppContext {
6266
return _advertisementSetQueueHandler
6367
}
6468

69+
fun advertisementSetQueueHandlerIsInitialized(): Boolean {
70+
return this::_advertisementSetQueueHandler.isInitialized
71+
}
72+
6573
fun registerPermissionCallback(requestCode: Int, callback:Runnable){
6674

6775
}

app/src/main/java/de/simon/dankelmann/bluetoothlespam/Handlers/AdvertisementSetQueueHandler.kt

+78-15
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,32 @@ import de.simon.dankelmann.bluetoothlespam.Enums.AdvertisementQueueMode
99
import de.simon.dankelmann.bluetoothlespam.Enums.TxPowerLevel
1010
import de.simon.dankelmann.bluetoothlespam.Helpers.QueueHandlerHelpers
1111
import de.simon.dankelmann.bluetoothlespam.Interfaces.Callbacks.IAdvertisementServiceCallback
12+
import de.simon.dankelmann.bluetoothlespam.Interfaces.Callbacks.IAdvertisementSetQueueHandlerCallback
1213
import de.simon.dankelmann.bluetoothlespam.Interfaces.Services.IAdvertisementService
1314
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSet
1415
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSetCollection
1516
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSetList
17+
import de.simon.dankelmann.bluetoothlespam.Services.AdvertisementForegroundService
1618
import kotlin.random.Random
1719

18-
class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
20+
class AdvertisementSetQueueHandler :IAdvertisementServiceCallback{
1921

2022
// private
2123
private var _logTag = "AdvertisementSetQueuHandler"
2224
private var _advertisementService:IAdvertisementService? = null
2325
private var _advertisementSetCollection:AdvertisementSetCollection = AdvertisementSetCollection()
2426
private var _interval:Long = 1000
2527
private var _advertisementServiceCallbacks:MutableList<IAdvertisementServiceCallback> = mutableListOf()
28+
private var _advertisementQueueHandlerCallbacks:MutableList<IAdvertisementSetQueueHandlerCallback> = mutableListOf()
29+
2630
private var _active = false
2731
private var _advertisementQueueMode: AdvertisementQueueMode = AdvertisementQueueMode.ADVERTISEMENT_QUEUE_MODE_LINEAR
2832

2933
private var _currentAdvertisementSet: AdvertisementSet? = null
3034
private var _currentAdvertisementSetListIndex = 0
3135
private var _currentAdvertisementSetIndex = 0
3236

37+
3338
init{
3439
_advertisementService = AppContext.getAdvertisementService()
3540
if(_advertisementService != null){
@@ -69,7 +74,9 @@ class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
6974
}
7075

7176
fun setAdvertisementSetCollection(advertisementSetCollection: AdvertisementSetCollection){
72-
_advertisementSetCollection = advertisementSetCollection
77+
if(_advertisementSetCollection != advertisementSetCollection){
78+
_advertisementSetCollection = advertisementSetCollection
79+
}
7380

7481
// Reset indices
7582
_currentAdvertisementSet= null
@@ -109,6 +116,17 @@ class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
109116
}
110117
}
111118

119+
fun addAdvertisementQueueHandlerCallback(callback: IAdvertisementSetQueueHandlerCallback){
120+
if(!_advertisementQueueHandlerCallbacks.contains(callback)){
121+
_advertisementQueueHandlerCallbacks.add(callback)
122+
}
123+
}
124+
fun removeAdvertisementQueueHandlerCallback(callback: IAdvertisementSetQueueHandlerCallback){
125+
if(_advertisementQueueHandlerCallbacks.contains(callback)){
126+
_advertisementQueueHandlerCallbacks.remove(callback)
127+
}
128+
}
129+
112130
fun setIntervalSeconds(seconds:Int){
113131
_interval = (seconds * 1000).toLong()
114132
}
@@ -119,19 +137,48 @@ class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
119137
}
120138
}
121139

122-
fun activate(){
123-
_active = true
124-
if(_currentAdvertisementSet != null){
125-
handleAdvertisementSet(_currentAdvertisementSet!!)
126-
} else {
127-
advertiseNextAdvertisementSet()
140+
fun activate(startService: Boolean = true){
141+
if(!_active){
142+
_active = true
143+
144+
if(startService){
145+
AdvertisementForegroundService.startService(AppContext.getContext(), "Foreground Service is running...")
146+
}
147+
148+
_advertisementQueueHandlerCallbacks.forEach { it ->
149+
try {
150+
it.onQueueHandlerActivated()
151+
} catch (e:Exception){
152+
Log.e(_logTag, "Error while executing AdvertisementQueueHandlerCallback onQueueHandlerActivated")
153+
}
154+
}
155+
156+
if(_currentAdvertisementSet != null){
157+
handleAdvertisementSet(_currentAdvertisementSet!!)
158+
} else {
159+
advertiseNextAdvertisementSet()
160+
}
128161
}
129162
}
130163

131-
fun deactivate(){
164+
fun deactivate(stopService: Boolean = false){
132165
_active = false
133-
if(_advertisementService != null){
134-
_advertisementService!!.stopAdvertisement()
166+
167+
if(AppContext.getAdvertisementService() != null){
168+
AppContext.getAdvertisementService().stopAdvertisement()
169+
}
170+
171+
if(stopService){
172+
Log.d(_logTag, "Stopping Foreground Service")
173+
AdvertisementForegroundService.stopService(AppContext.getActivity())
174+
}
175+
176+
_advertisementQueueHandlerCallbacks.forEach { it ->
177+
try {
178+
it.onQueueHandlerDeactivated()
179+
} catch (e:Exception){
180+
Log.e(_logTag, "Error while executing AdvertisementQueueHandlerCallback onQueueHandlerDeactivated")
181+
}
135182
}
136183
}
137184

@@ -287,13 +334,21 @@ class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
287334
// Callback Implementation, just pass to own Listeners
288335
override fun onAdvertisementSetStart(advertisementSet: AdvertisementSet?) {
289336
_advertisementServiceCallbacks.map {
290-
it.onAdvertisementSetStart(advertisementSet)
337+
try {
338+
it.onAdvertisementSetStart(advertisementSet)
339+
} catch (e:Exception){
340+
Log.e(_logTag, "Error in: onAdvertisementSetStart ${e.message}")
341+
}
291342
}
292343
}
293344

294345
override fun onAdvertisementSetStop(advertisementSet: AdvertisementSet?) {
295346
_advertisementServiceCallbacks.map {
296-
it.onAdvertisementSetStop(advertisementSet)
347+
try {
348+
it.onAdvertisementSetStop(advertisementSet)
349+
} catch (e:Exception){
350+
Log.e(_logTag, "Error in: onAdvertisementSetStop ${e.message}")
351+
}
297352
}
298353

299354
if(_advertisementService != null && !_advertisementService!!.isLegacyService()){
@@ -304,14 +359,22 @@ class AdvertisementSetQueueHandler :IAdvertisementServiceCallback {
304359
override fun onAdvertisementSetSucceeded(advertisementSet: AdvertisementSet?) {
305360
runLocalCallback(true)
306361
_advertisementServiceCallbacks.map {
307-
it.onAdvertisementSetSucceeded(advertisementSet)
362+
try {
363+
it.onAdvertisementSetSucceeded(advertisementSet)
364+
} catch (e:Exception){
365+
Log.e(_logTag, "Error in: onAdvertisementSetSucceeded ${e.message}")
366+
}
308367
}
309368
}
310369

311370
override fun onAdvertisementSetFailed(advertisementSet: AdvertisementSet?, advertisementError: AdvertisementError) {
312371
runLocalCallback(false)
313372
_advertisementServiceCallbacks.map {
314-
it.onAdvertisementSetFailed(advertisementSet, advertisementError)
373+
try {
374+
it.onAdvertisementSetFailed(advertisementSet, advertisementError)
375+
} catch (e:Exception){
376+
Log.e(_logTag, "Error in: onAdvertisementSetFailed ${e.message}")
377+
}
315378
}
316379
}
317380
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package de.simon.dankelmann.bluetoothlespam.Interfaces.Callbacks
2+
3+
import de.simon.dankelmann.bluetoothlespam.Models.AdvertisementSet
4+
5+
interface IAdvertisementSetQueueHandlerCallback {
6+
fun onQueueHandlerActivated()
7+
fun onQueueHandlerDeactivated()
8+
}

0 commit comments

Comments
 (0)