react-native-flic2 2.0.0-alpha.39 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +733 -13
- package/android/src/main/AndroidManifest.xml +23 -0
- package/android/src/main/java/com/flic2/ActivityUtil.kt +29 -0
- package/android/src/main/java/com/flic2/Flic2ButtonListener.kt +6 -10
- package/android/src/main/java/com/flic2/Flic2Module.kt +61 -37
- package/android/src/main/java/com/flic2/Flic2Service.kt +197 -24
- package/ios/Flic2.h +0 -1
- package/ios/Flic2.mm +211 -183
- package/lib/module/NativeFlic2.js +26 -0
- package/lib/module/NativeFlic2.js.map +1 -1
- package/lib/module/index.bak.js +161 -0
- package/lib/module/index.bak.js.map +1 -0
- package/lib/module/index.js +256 -76
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/typedEventEmitter.js +39 -0
- package/lib/module/lib/typedEventEmitter.js.map +1 -0
- package/lib/typescript/src/NativeFlic2.d.ts +30 -11
- package/lib/typescript/src/NativeFlic2.d.ts.map +1 -1
- package/lib/typescript/src/index.bak.d.ts +1 -0
- package/lib/typescript/src/index.bak.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +198 -80
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/lib/typedEventEmitter.d.ts +15 -0
- package/lib/typescript/src/lib/typedEventEmitter.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/NativeFlic2.ts +32 -19
- package/src/index.bak.tsx +159 -0
- package/src/index.ts +382 -0
- package/src/lib/typedEventEmitter.ts +63 -0
- package/src/index.tsx +0 -159
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<!-- Foreground service permission -->
|
|
16
16
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
17
17
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
|
|
18
|
+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
18
19
|
|
|
19
20
|
<application>
|
|
20
21
|
<service
|
|
@@ -22,6 +23,28 @@
|
|
|
22
23
|
android:enabled="true"
|
|
23
24
|
android:exported="false"
|
|
24
25
|
android:foregroundServiceType="connectedDevice" />
|
|
26
|
+
|
|
27
|
+
<receiver
|
|
28
|
+
android:name=".Flic2Service$BootUpReceiver"
|
|
29
|
+
android:enabled="true"
|
|
30
|
+
android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
|
|
31
|
+
android:exported="false">
|
|
32
|
+
<intent-filter>
|
|
33
|
+
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
34
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
35
|
+
</intent-filter>
|
|
36
|
+
</receiver>
|
|
37
|
+
|
|
38
|
+
<receiver
|
|
39
|
+
android:name=".Flic2Service$UpdateReceiver"
|
|
40
|
+
android:enabled="true"
|
|
41
|
+
android:exported="false">
|
|
42
|
+
<intent-filter>
|
|
43
|
+
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
|
44
|
+
<data
|
|
45
|
+
android:scheme="package" />
|
|
46
|
+
</intent-filter>
|
|
47
|
+
</receiver>
|
|
25
48
|
</application>
|
|
26
49
|
|
|
27
50
|
</manifest>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
package com.flic2
|
|
2
|
+
|
|
3
|
+
import android.app.ActivityManager
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.os.Build
|
|
7
|
+
|
|
8
|
+
object ActivityUtil {
|
|
9
|
+
private const val TAG = "ActivityUtil"
|
|
10
|
+
|
|
11
|
+
fun isServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
|
|
12
|
+
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
|
13
|
+
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
|
|
14
|
+
if (serviceClass.name == service.service.className) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fun startForegroundService(context: Context, intent: Intent) {
|
|
22
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
23
|
+
context.startForegroundService(intent)
|
|
24
|
+
} else {
|
|
25
|
+
context.startService(intent)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -51,6 +51,8 @@ class Flic2ButtonEventListener(
|
|
|
51
51
|
})
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
// Android library calls ALL applicable callback methods, causing duplicate events.
|
|
55
|
+
// Only onButtonSingleOrDoubleClickOrHold should emit events to match iOS behavior.
|
|
54
56
|
override fun onButtonClickOrHold(
|
|
55
57
|
button: Flic2Button,
|
|
56
58
|
wasQueued: Boolean,
|
|
@@ -59,13 +61,11 @@ class Flic2ButtonEventListener(
|
|
|
59
61
|
isClick: Boolean,
|
|
60
62
|
isHold: Boolean
|
|
61
63
|
) {
|
|
62
|
-
|
|
63
|
-
emitEvent(createButtonEvent(button, event).apply {
|
|
64
|
-
putBoolean("queued", wasQueued)
|
|
65
|
-
putDouble("age", System.currentTimeMillis() - timestamp.toDouble())
|
|
66
|
-
})
|
|
64
|
+
// Intentionally empty - events are handled by onButtonSingleOrDoubleClickOrHold
|
|
67
65
|
}
|
|
68
66
|
|
|
67
|
+
// Android library calls ALL applicable callback methods, causing duplicate events.
|
|
68
|
+
// Only onButtonSingleOrDoubleClickOrHold should emit events to match iOS behavior.
|
|
69
69
|
override fun onButtonSingleOrDoubleClick(
|
|
70
70
|
button: Flic2Button,
|
|
71
71
|
wasQueued: Boolean,
|
|
@@ -74,11 +74,7 @@ class Flic2ButtonEventListener(
|
|
|
74
74
|
isSingleClick: Boolean,
|
|
75
75
|
isDoubleClick: Boolean
|
|
76
76
|
) {
|
|
77
|
-
|
|
78
|
-
emitEvent(createButtonEvent(button, event).apply {
|
|
79
|
-
putBoolean("queued", wasQueued)
|
|
80
|
-
putDouble("age", System.currentTimeMillis() - timestamp.toDouble())
|
|
81
|
-
})
|
|
77
|
+
// Intentionally empty - events are handled by onButtonSingleOrDoubleClickOrHold
|
|
82
78
|
}
|
|
83
79
|
|
|
84
80
|
override fun onButtonSingleOrDoubleClickOrHold(
|
|
@@ -57,6 +57,8 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
57
57
|
manager.buttons.forEach { button ->
|
|
58
58
|
setupButtonListener(button)
|
|
59
59
|
}
|
|
60
|
+
// Update foreground service state based on button count
|
|
61
|
+
updateForegroundServiceState(manager.buttons.size)
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
// Resolve the initialize promise if pending
|
|
@@ -95,20 +97,6 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
// Example method - keep for reference
|
|
99
|
-
override fun multiply(a: Double, b: Double): Double {
|
|
100
|
-
val result = a * b
|
|
101
|
-
|
|
102
|
-
val eventData = Arguments.createMap().apply {
|
|
103
|
-
putDouble("a", a)
|
|
104
|
-
putDouble("b", b)
|
|
105
|
-
putDouble("result", result)
|
|
106
|
-
}
|
|
107
|
-
emitOnMultiply(eventData)
|
|
108
|
-
|
|
109
|
-
return result
|
|
110
|
-
}
|
|
111
|
-
|
|
112
100
|
// MARK: - Manager Methods
|
|
113
101
|
|
|
114
102
|
override fun initialize(background: Boolean, promise: Promise) {
|
|
@@ -118,11 +106,11 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
118
106
|
|
|
119
107
|
val intent = Intent(reactApplicationContext, Flic2Service::class.java)
|
|
120
108
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
109
|
+
// Check if service is already running
|
|
110
|
+
val isRunning = ActivityUtil.isServiceRunning(reactApplicationContext, Flic2Service::class.java)
|
|
111
|
+
if (!isRunning) {
|
|
112
|
+
// Start service
|
|
113
|
+
ActivityUtil.startForegroundService(reactApplicationContext, intent)
|
|
126
114
|
}
|
|
127
115
|
|
|
128
116
|
// Bind to service - promise will be resolved in onServiceConnected
|
|
@@ -172,46 +160,42 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
172
160
|
|
|
173
161
|
Log.d(TAG, "Starting scan")
|
|
174
162
|
|
|
163
|
+
// Emit started event (matches iOS)
|
|
164
|
+
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
165
|
+
putString("event", "started")
|
|
166
|
+
putString("eventName", "started")
|
|
167
|
+
})
|
|
168
|
+
|
|
175
169
|
manager.startScan(object : Flic2ScanCallback {
|
|
176
170
|
override fun onDiscoveredAlreadyPairedButton(button: Flic2Button) {
|
|
177
171
|
Log.d(TAG, "Discovered already paired button")
|
|
178
|
-
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
179
|
-
putInt("event", 0)
|
|
180
|
-
putString("eventName", "discovered")
|
|
181
|
-
})
|
|
182
172
|
}
|
|
183
173
|
|
|
184
174
|
override fun onDiscovered(bdAddr: String) {
|
|
185
175
|
Log.d(TAG, "Discovered button: $bdAddr")
|
|
186
|
-
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
187
|
-
putInt("event", 0)
|
|
188
|
-
putString("eventName", "discovered")
|
|
189
|
-
})
|
|
190
176
|
}
|
|
191
177
|
|
|
192
178
|
override fun onConnected() {
|
|
193
179
|
Log.d(TAG, "Button connected during scan")
|
|
194
|
-
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
195
|
-
putInt("event", 1)
|
|
196
|
-
putString("eventName", "connected")
|
|
197
|
-
})
|
|
198
180
|
}
|
|
199
181
|
|
|
200
182
|
override fun onComplete(result: Int, subCode: Int, button: Flic2Button?) {
|
|
201
183
|
Log.d(TAG, "Scan complete: result=$result, button=${button?.uuid}")
|
|
202
184
|
|
|
203
|
-
|
|
204
|
-
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
205
|
-
putInt("event", 2)
|
|
206
|
-
putString("eventName", "verified")
|
|
207
|
-
})
|
|
185
|
+
val resultCode = mapScanResultToCode(result)
|
|
208
186
|
|
|
187
|
+
if (result == Flic2ScanCallback.RESULT_SUCCESS && button != null) {
|
|
209
188
|
// Auto-connect (trigger mode not available in Android v1.1.0+)
|
|
210
189
|
button.connect()
|
|
211
190
|
|
|
212
191
|
setupButtonListener(button)
|
|
213
192
|
|
|
214
|
-
//
|
|
193
|
+
// Update foreground service state after adding button
|
|
194
|
+
flic2Service?.getManager()?.let { manager ->
|
|
195
|
+
updateForegroundServiceState(manager.buttons.size)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Emit discovered event as button event (like iOS)
|
|
215
199
|
emitOnButtonEvent(Arguments.createMap().apply {
|
|
216
200
|
putString("uuid", button.uuid)
|
|
217
201
|
putString("event", "discovered")
|
|
@@ -221,6 +205,13 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
221
205
|
val errorCode = Flic2Converter.scanResultToString(result)
|
|
222
206
|
Log.e(TAG, "Scan failed with error code: $errorCode")
|
|
223
207
|
}
|
|
208
|
+
|
|
209
|
+
// Emit scan completion with result code
|
|
210
|
+
emitOnScanStatusChange(Arguments.createMap().apply {
|
|
211
|
+
putString("event", "completion")
|
|
212
|
+
putString("eventName", "completion")
|
|
213
|
+
putInt("result", resultCode)
|
|
214
|
+
})
|
|
224
215
|
}
|
|
225
216
|
})
|
|
226
217
|
|
|
@@ -275,6 +266,9 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
275
266
|
// Forget button
|
|
276
267
|
manager.forgetButton(button)
|
|
277
268
|
|
|
269
|
+
// Update foreground service state after removing button
|
|
270
|
+
updateForegroundServiceState(manager.buttons.size)
|
|
271
|
+
|
|
278
272
|
promise.resolve(Arguments.createMap().apply {
|
|
279
273
|
putBoolean("success", true)
|
|
280
274
|
putString("message", "Button forgotten")
|
|
@@ -430,6 +424,9 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
430
424
|
manager.forgetButton(button)
|
|
431
425
|
}
|
|
432
426
|
|
|
427
|
+
// Update foreground service state after removing all buttons
|
|
428
|
+
updateForegroundServiceState(manager.buttons.size)
|
|
429
|
+
|
|
433
430
|
promise.resolve(Arguments.createMap().apply {
|
|
434
431
|
putBoolean("success", true)
|
|
435
432
|
putString("message", "All buttons forgotten")
|
|
@@ -477,4 +474,31 @@ class Flic2Module(reactContext: ReactApplicationContext) :
|
|
|
477
474
|
// Store listener reference
|
|
478
475
|
buttonListeners[button.uuid] = listener
|
|
479
476
|
}
|
|
477
|
+
|
|
478
|
+
private fun updateForegroundServiceState(buttonCount: Int) {
|
|
479
|
+
if (buttonCount > 0) {
|
|
480
|
+
// Start foreground service when buttons exist
|
|
481
|
+
flic2Service?.startForegroundService()
|
|
482
|
+
} else {
|
|
483
|
+
// Stop foreground service when no buttons
|
|
484
|
+
flic2Service?.stopForegroundService()
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private fun mapScanResultToCode(result: Int): Int {
|
|
489
|
+
// Map Android library's 9 result codes (0-8) to TypeScript enum codes (0-21) matching iOS
|
|
490
|
+
// Android library only provides these constants, so we map them to the closest equivalent
|
|
491
|
+
return when (result) {
|
|
492
|
+
Flic2ScanCallback.RESULT_SUCCESS -> 0 // SUCCESS
|
|
493
|
+
Flic2ScanCallback.RESULT_FAILED_ALREADY_RUNNING -> 1 // ALREADY_RUNNING
|
|
494
|
+
Flic2ScanCallback.RESULT_FAILED_BLUETOOTH_OFF -> 2 // BLUETOOTH_NOT_ACTIVATED
|
|
495
|
+
Flic2ScanCallback.RESULT_FAILED_SCAN_ERROR -> 3 // UNKNOWN
|
|
496
|
+
Flic2ScanCallback.RESULT_FAILED_NO_NEW_BUTTONS_FOUND -> 4 // NO_PUBLIC_BUTTON_DISCOVERED
|
|
497
|
+
Flic2ScanCallback.RESULT_FAILED_BUTTON_ALREADY_CONNECTED_TO_OTHER_DEVICE -> 5 // ALREADY_CONNECTED_TO_ANOTHER_DEVICE
|
|
498
|
+
Flic2ScanCallback.RESULT_FAILED_CONNECT_TIMED_OUT -> 6 // CONNECTION_TIMEOUT
|
|
499
|
+
Flic2ScanCallback.RESULT_FAILED_VERIFY_TIMED_OUT -> 7 // INVALID_VERIFIER
|
|
500
|
+
Flic2ScanCallback.RESULT_SYSTEM_PAIRING_DIALOG_NOT_ACCEPTED -> 9 // BLE_PAIRING_FAILED_USER_CANCELED
|
|
501
|
+
else -> 3 // UNKNOWN (for any unexpected codes)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
480
504
|
}
|
|
@@ -5,7 +5,10 @@ import android.app.NotificationChannel
|
|
|
5
5
|
import android.app.NotificationManager
|
|
6
6
|
import android.app.PendingIntent
|
|
7
7
|
import android.app.Service
|
|
8
|
+
import android.content.BroadcastReceiver
|
|
9
|
+
import android.content.Context
|
|
8
10
|
import android.content.Intent
|
|
11
|
+
import android.content.pm.PackageManager
|
|
9
12
|
import android.os.Binder
|
|
10
13
|
import android.os.Build
|
|
11
14
|
import android.os.Handler
|
|
@@ -19,12 +22,22 @@ class Flic2Service : Service() {
|
|
|
19
22
|
|
|
20
23
|
private val binder = Flic2ServiceBinder()
|
|
21
24
|
private var manager: Flic2Manager? = null
|
|
25
|
+
private var isServiceStarted = false
|
|
26
|
+
private var notification: Notification? = null
|
|
22
27
|
|
|
23
28
|
companion object {
|
|
24
29
|
private const val TAG = "Flic2Service"
|
|
25
|
-
private const val
|
|
26
|
-
private const val
|
|
27
|
-
|
|
30
|
+
private const val DEFAULT_NOTIFICATION_ID = 123321
|
|
31
|
+
private const val DEFAULT_CHANNEL_ID = "Notification_Channel_Flic2Service"
|
|
32
|
+
|
|
33
|
+
// Metadata keys for notification configuration
|
|
34
|
+
private const val KEY_CHANNEL_NAME = "nl.xguard.flic2.notification_channel_name"
|
|
35
|
+
private const val KEY_CHANNEL_DESCRIPTION = "nl.xguard.flic2.notification_channel_description"
|
|
36
|
+
private const val NOTIFICATION_TITLE_KEY = "nl.xguard.flic2.notification_title"
|
|
37
|
+
private const val NOTIFICATION_TEXT_KEY = "nl.xguard.flic2.notification_text"
|
|
38
|
+
private const val NOTIFICATION_ICON_KEY = "nl.xguard.flic2.notification_icon"
|
|
39
|
+
private const val NOTIFICATION_ID_KEY = "nl.xguard.flic2.notification_id"
|
|
40
|
+
private const val CHANNEL_ID_KEY = "nl.xguard.flic2.notification_channel_id"
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
inner class Flic2ServiceBinder : Binder() {
|
|
@@ -47,31 +60,25 @@ class Flic2Service : Service() {
|
|
|
47
60
|
} catch (e: Exception) {
|
|
48
61
|
Log.e(TAG, "Failed to initialize Flic2Manager", e)
|
|
49
62
|
}
|
|
63
|
+
|
|
64
|
+
// Create notification channel and notification in onCreate
|
|
65
|
+
createNotificationChannel()
|
|
66
|
+
notification = createNotification()
|
|
50
67
|
}
|
|
51
68
|
|
|
52
69
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
53
70
|
Log.d(TAG, "Service onStartCommand")
|
|
54
71
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
CHANNEL_ID,
|
|
59
|
-
CHANNEL_NAME,
|
|
60
|
-
NotificationManager.IMPORTANCE_LOW
|
|
61
|
-
).apply {
|
|
62
|
-
description = "Keeps Flic2 buttons connected in the background"
|
|
63
|
-
setShowBadge(false)
|
|
72
|
+
if (intent != null) {
|
|
73
|
+
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
|
|
74
|
+
Log.d(TAG, "onStartCommand: ACTION_BOOT_COMPLETED")
|
|
64
75
|
}
|
|
65
|
-
|
|
66
|
-
val notificationManager = getSystemService(NotificationManager::class.java)
|
|
67
|
-
notificationManager.createNotificationChannel(channel)
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
startForeground(NOTIFICATION_ID, notification)
|
|
78
|
+
// Start foreground service if notification is ready
|
|
79
|
+
if (notification != null) {
|
|
80
|
+
startForegroundService()
|
|
81
|
+
}
|
|
75
82
|
|
|
76
83
|
return START_STICKY
|
|
77
84
|
}
|
|
@@ -90,6 +97,45 @@ class Flic2Service : Service() {
|
|
|
90
97
|
|
|
91
98
|
fun isManagerInitialized(): Boolean = manager != null
|
|
92
99
|
|
|
100
|
+
fun startForegroundService() {
|
|
101
|
+
if (!isServiceStarted && notification != null) {
|
|
102
|
+
isServiceStarted = true
|
|
103
|
+
try {
|
|
104
|
+
val notificationId = getNotificationId()
|
|
105
|
+
startForeground(notificationId, notification)
|
|
106
|
+
} catch (e: Exception) {
|
|
107
|
+
Log.w(TAG, "startForegroundService() exception", e)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fun stopForegroundService() {
|
|
113
|
+
if (isServiceStarted) {
|
|
114
|
+
isServiceStarted = false
|
|
115
|
+
stopForeground(true)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private fun createNotificationChannel() {
|
|
120
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
121
|
+
val channelId = getChannelId()
|
|
122
|
+
val channelName = getChannelName()
|
|
123
|
+
val channelDescription = getChannelDescription()
|
|
124
|
+
|
|
125
|
+
val channel = NotificationChannel(
|
|
126
|
+
channelId,
|
|
127
|
+
channelName,
|
|
128
|
+
NotificationManager.IMPORTANCE_LOW
|
|
129
|
+
).apply {
|
|
130
|
+
description = channelDescription
|
|
131
|
+
setShowBadge(false)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
val notificationManager = getSystemService(NotificationManager::class.java)
|
|
135
|
+
notificationManager.createNotificationChannel(channel)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
93
139
|
private fun createNotification(): Notification {
|
|
94
140
|
val notificationIntent = Intent(this, Flic2Service::class.java)
|
|
95
141
|
val pendingIntent = PendingIntent.getActivity(
|
|
@@ -99,14 +145,141 @@ class Flic2Service : Service() {
|
|
|
99
145
|
PendingIntent.FLAG_IMMUTABLE
|
|
100
146
|
)
|
|
101
147
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
148
|
+
val channelId = getChannelId()
|
|
149
|
+
val title = getNotificationTitle()
|
|
150
|
+
val text = getNotificationText()
|
|
151
|
+
val icon = getNotificationIcon()
|
|
152
|
+
|
|
153
|
+
return NotificationCompat.Builder(this, channelId)
|
|
154
|
+
.setContentTitle(title)
|
|
155
|
+
.setContentText(text)
|
|
156
|
+
.setSmallIcon(icon)
|
|
106
157
|
.setContentIntent(pendingIntent)
|
|
107
158
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
108
159
|
.setOngoing(true)
|
|
109
160
|
.build()
|
|
110
161
|
}
|
|
162
|
+
|
|
163
|
+
private fun getNotificationId(): Int {
|
|
164
|
+
return try {
|
|
165
|
+
val metadata = applicationContext.packageManager
|
|
166
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
167
|
+
.metaData
|
|
168
|
+
metadata?.getInt(NOTIFICATION_ID_KEY, DEFAULT_NOTIFICATION_ID) ?: DEFAULT_NOTIFICATION_ID
|
|
169
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
170
|
+
Log.w(TAG, "getNotificationId() NameNotFoundException", e)
|
|
171
|
+
DEFAULT_NOTIFICATION_ID
|
|
172
|
+
} catch (e: Exception) {
|
|
173
|
+
Log.w(TAG, "getNotificationId() exception", e)
|
|
174
|
+
DEFAULT_NOTIFICATION_ID
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private fun getChannelId(): String {
|
|
179
|
+
return try {
|
|
180
|
+
val metadata = applicationContext.packageManager
|
|
181
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
182
|
+
.metaData
|
|
183
|
+
metadata?.getString(CHANNEL_ID_KEY) ?: DEFAULT_CHANNEL_ID
|
|
184
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
185
|
+
Log.w(TAG, "getChannelId() NameNotFoundException", e)
|
|
186
|
+
DEFAULT_CHANNEL_ID
|
|
187
|
+
} catch (e: Exception) {
|
|
188
|
+
Log.w(TAG, "getChannelId() exception", e)
|
|
189
|
+
DEFAULT_CHANNEL_ID
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private fun getChannelName(): String {
|
|
194
|
+
return try {
|
|
195
|
+
val metadata = applicationContext.packageManager
|
|
196
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
197
|
+
.metaData
|
|
198
|
+
metadata?.getString(KEY_CHANNEL_NAME) ?: "Flic2Channel"
|
|
199
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
200
|
+
Log.w(TAG, "getChannelName() NameNotFoundException", e)
|
|
201
|
+
"Flic2Channel"
|
|
202
|
+
} catch (e: Exception) {
|
|
203
|
+
Log.w(TAG, "getChannelName() exception", e)
|
|
204
|
+
"Flic2Channel"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private fun getChannelDescription(): String {
|
|
209
|
+
return try {
|
|
210
|
+
val metadata = applicationContext.packageManager
|
|
211
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
212
|
+
.metaData
|
|
213
|
+
metadata?.getString(KEY_CHANNEL_DESCRIPTION) ?: "Flic2Channel"
|
|
214
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
215
|
+
Log.w(TAG, "getChannelDescription() NameNotFoundException", e)
|
|
216
|
+
"Flic2Channel"
|
|
217
|
+
} catch (e: Exception) {
|
|
218
|
+
Log.w(TAG, "getChannelDescription() exception", e)
|
|
219
|
+
"Flic2Channel"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private fun getNotificationTitle(): String {
|
|
224
|
+
return try {
|
|
225
|
+
val metadata = applicationContext.packageManager
|
|
226
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
227
|
+
.metaData
|
|
228
|
+
metadata?.getString(NOTIFICATION_TITLE_KEY) ?: "Flic 2"
|
|
229
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
230
|
+
Log.w(TAG, "getNotificationTitle() NameNotFoundException", e)
|
|
231
|
+
"Flic 2"
|
|
232
|
+
} catch (e: Exception) {
|
|
233
|
+
Log.w(TAG, "getNotificationTitle() exception", e)
|
|
234
|
+
"Flic 2"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private fun getNotificationText(): String {
|
|
239
|
+
return try {
|
|
240
|
+
val metadata = applicationContext.packageManager
|
|
241
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
242
|
+
.metaData
|
|
243
|
+
metadata?.getString(NOTIFICATION_TEXT_KEY) ?: "Flic 2 service is running"
|
|
244
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
245
|
+
Log.w(TAG, "getNotificationText() NameNotFoundException", e)
|
|
246
|
+
"Flic 2 service is running"
|
|
247
|
+
} catch (e: Exception) {
|
|
248
|
+
Log.w(TAG, "getNotificationText() exception", e)
|
|
249
|
+
"Flic 2 service is running"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private fun getNotificationIcon(): Int {
|
|
254
|
+
return try {
|
|
255
|
+
val metadata = applicationContext.packageManager
|
|
256
|
+
.getApplicationInfo(applicationContext.packageName, PackageManager.GET_META_DATA)
|
|
257
|
+
.metaData
|
|
258
|
+
val icon = metadata?.getInt(NOTIFICATION_ICON_KEY, 0) ?: 0
|
|
259
|
+
if (icon != 0) icon else android.R.drawable.ic_dialog_info
|
|
260
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
261
|
+
Log.w(TAG, "getNotificationIcon() NameNotFoundException", e)
|
|
262
|
+
android.R.drawable.ic_dialog_info
|
|
263
|
+
} catch (e: Exception) {
|
|
264
|
+
Log.w(TAG, "getNotificationIcon() exception", e)
|
|
265
|
+
android.R.drawable.ic_dialog_info
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// BootUpReceiver for handling device boot
|
|
270
|
+
class BootUpReceiver : BroadcastReceiver() {
|
|
271
|
+
override fun onReceive(context: Context, intent: Intent) {
|
|
272
|
+
Log.d(TAG, "BootUpReceiver()")
|
|
273
|
+
// The Application class's onCreate has already been called at this point, which is what we want
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// UpdateReceiver for handling app updates
|
|
278
|
+
class UpdateReceiver : BroadcastReceiver() {
|
|
279
|
+
override fun onReceive(context: Context, intent: Intent) {
|
|
280
|
+
Log.d(TAG, "UpdateReceiver()")
|
|
281
|
+
// The Application class's onCreate has already been called at this point, which is what we want
|
|
282
|
+
}
|
|
283
|
+
}
|
|
111
284
|
}
|
|
112
285
|
|