Skip to content
This repository was archived by the owner on Dec 18, 2022. It is now read-only.

Commit 1706c3b

Browse files
authored
Merge pull request #64 from 05nelsonm/mn/feature/notification-upgrades
Makes ServiceNotification smarter
2 parents ffb0064 + 1a186f3 commit 1706c3b

File tree

5 files changed

+155
-25
lines changed

5 files changed

+155
-25
lines changed

topl-service/src/main/java/io/matthewnelson/topl_service/notification/ServiceNotification.kt

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,12 @@ class ServiceNotification internal constructor(
357357
private var notificationBuilder: NotificationCompat.Builder? = null
358358
private var notificationManager: NotificationManager? = null
359359
private val timeoutLength = 3_000L
360+
private var startTime: Long? = null
360361

361-
internal fun buildNotification(torService: BaseService): NotificationCompat.Builder {
362+
internal fun buildNotification(
363+
torService: BaseService,
364+
setStartTime: Boolean = false
365+
): NotificationCompat.Builder {
362366
val builder = NotificationCompat.Builder(torService.context.applicationContext, channelID)
363367
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
364368
.setContentText(currentContentText)
@@ -373,17 +377,23 @@ class ServiceNotification internal constructor(
373377
.setTimeoutAfter(timeoutLength)
374378
.setVisibility(visibility)
375379

380+
if (startTime == null || setStartTime)
381+
startTime = System.currentTimeMillis()
382+
383+
startTime?.let {
384+
builder.setWhen(it)
385+
}
386+
376387
currentColor?.let {
377388
builder.color = it
378389
}
379390

380391
if (progressBarShown) {
381392
val progress = progressValue
382-
if (progress != null) {
393+
if (progress != null)
383394
builder.setProgress(100, progress, false)
384-
} else {
395+
else
385396
builder.setProgress(100, 0, true)
386-
}
387397
}
388398

389399
if (activityWhenTapped != null)
@@ -480,27 +490,42 @@ class ServiceNotification internal constructor(
480490
internal var inForeground = false
481491
private set
482492

493+
/**
494+
* Sends [TorService] to the Foreground.
495+
*
496+
* @return `true` if sent to Foreground, `false` if no action taken
497+
* */
483498
@Synchronized
484-
internal fun startForeground(torService: BaseService): ServiceNotification {
485-
if (!inForeground) {
499+
internal fun startForeground(torService: BaseService): Boolean {
500+
return if (!inForeground) {
486501
notificationBuilder?.let {
487502
torService.startForeground(notificationID, it.build())
488503
inForeground = true
504+
return true
489505
}
506+
false
507+
} else {
508+
false
490509
}
491-
return serviceNotification
492510
}
493511

512+
/**
513+
* Sends [TorService] to the Background.
514+
*
515+
* @return `true` if sent to Background, `false` if no action taken
516+
* */
494517
@Synchronized
495-
internal fun stopForeground(torService: BaseService): ServiceNotification {
496-
if (inForeground) {
518+
internal fun stopForeground(torService: BaseService): Boolean {
519+
return if (inForeground) {
497520
torService.stopForeground(!showNotification)
498521
inForeground = false
499522
notificationBuilder?.let {
500523
notify(torService, it)
501524
}
525+
true
526+
} else {
527+
false
502528
}
503-
return serviceNotification
504529
}
505530

506531

@@ -514,26 +539,27 @@ class ServiceNotification internal constructor(
514539
@Synchronized
515540
internal fun addActions(torService: BaseService) {
516541
val builder = notificationBuilder ?: return
542+
actionsPresent = true
543+
517544
builder.addAction(
518545
imageNetworkEnabled,
519546
"New Identity",
520547
getActionPendingIntent(torService, ServiceActionName.NEW_ID, 1)
521548
)
522549

523-
if (enableRestartButton)
550+
if (enableRestartButton && TorServiceReceiver.deviceIsLocked != true)
524551
builder.addAction(
525552
imageNetworkEnabled,
526553
"Restart Tor",
527554
getActionPendingIntent(torService, ServiceActionName.RESTART_TOR, 2)
528555
)
529556

530-
if (enableStopButton)
557+
if (enableStopButton && TorServiceReceiver.deviceIsLocked != true)
531558
builder.addAction(
532559
imageNetworkEnabled,
533560
"Stop Tor",
534561
getActionPendingIntent(torService, ServiceActionName.STOP, 3)
535562
)
536-
actionsPresent = true
537563
notify(torService, builder)
538564
}
539565

@@ -554,6 +580,24 @@ class ServiceNotification internal constructor(
554580
)
555581
}
556582

583+
/**
584+
* Refreshes the notification Actions.
585+
*
586+
* @return `true` if actions were present to be refreshed, `false` if actions weren't
587+
* present, thus not needing a refresh
588+
* @see [TorServiceReceiver.deviceIsLocked]
589+
* */
590+
@Synchronized
591+
internal fun refreshActions(torService: BaseService): Boolean {
592+
return if (actionsPresent) {
593+
removeActions(torService)
594+
addActions(torService)
595+
true
596+
} else {
597+
false
598+
}
599+
}
600+
557601
@Synchronized
558602
internal fun removeActions(torService: BaseService) {
559603
actionsPresent = false

topl-service/src/main/java/io/matthewnelson/topl_service/service/BaseService.kt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import android.content.Context
7272
import android.content.Intent
7373
import android.content.SharedPreferences
7474
import androidx.annotation.WorkerThread
75+
import androidx.core.app.NotificationCompat
7576
import io.matthewnelson.topl_core.broadcaster.BroadcastLogger
7677
import io.matthewnelson.topl_core_base.TorConfigFiles
7778
import io.matthewnelson.topl_core_base.TorSettings
@@ -257,6 +258,7 @@ internal abstract class BaseService: Service() {
257258
/// BroadcastReceiver ///
258259
/////////////////////////
259260
abstract fun registerReceiver()
261+
abstract fun setIsDeviceLocked()
260262
abstract fun unregisterReceiver()
261263

262264

@@ -291,16 +293,32 @@ internal abstract class BaseService: Service() {
291293
fun addNotificationActions() {
292294
serviceNotification.addActions(this)
293295
}
296+
fun doesReceiverNeedToListenForLockScreen(): Boolean {
297+
return when {
298+
serviceNotification.visibility == NotificationCompat.VISIBILITY_SECRET -> {
299+
false
300+
}
301+
serviceNotification.enableRestartButton || serviceNotification.enableStopButton -> {
302+
true
303+
}
304+
else -> {
305+
false
306+
}
307+
}
308+
}
309+
open fun refreshNotificationActions(): Boolean {
310+
return serviceNotification.refreshActions(this)
311+
}
294312
fun removeNotification() {
295313
serviceNotification.remove()
296314
}
297315
fun removeNotificationActions() {
298316
serviceNotification.removeActions(this)
299317
}
300-
fun startForegroundService(): ServiceNotification {
318+
open fun startForegroundService(): Boolean {
301319
return serviceNotification.startForeground(this)
302320
}
303-
fun stopForegroundService(): ServiceNotification {
321+
open fun stopForegroundService(): Boolean {
304322
return serviceNotification.stopForeground(this)
305323
}
306324
fun updateNotificationContentText(string: String) {
@@ -357,8 +375,9 @@ internal abstract class BaseService: Service() {
357375

358376

359377
override fun onCreate() {
360-
serviceNotification.buildNotification(this)
378+
serviceNotification.buildNotification(this, setStartTime = true)
361379
registerPrefsListener()
380+
setIsDeviceLocked()
362381
}
363382

364383
override fun onDestroy() {

topl-service/src/main/java/io/matthewnelson/topl_service/service/TorService.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ internal class TorService: BaseService() {
125125
override fun registerReceiver() {
126126
torServiceReceiver.register()
127127
}
128+
override fun setIsDeviceLocked() {
129+
torServiceReceiver.setDeviceIsLocked()
130+
}
128131
override fun unregisterReceiver() {
129132
torServiceReceiver.unregister()
130133
}
@@ -158,6 +161,30 @@ internal class TorService: BaseService() {
158161

159162
// See BaseService
160163

164+
override fun refreshNotificationActions(): Boolean {
165+
val wasRefreshed = super.refreshNotificationActions()
166+
if (wasRefreshed) {
167+
val debugMsg = if (TorServiceReceiver.deviceIsLocked == true)
168+
"Removed Notification Actions"
169+
else
170+
"Added Notification Actions"
171+
broadcastLogger.debug(debugMsg)
172+
}
173+
return wasRefreshed
174+
}
175+
override fun startForegroundService(): Boolean {
176+
val wasStarted = super.startForegroundService()
177+
if (wasStarted)
178+
broadcastLogger.debug("Service sent to Foreground")
179+
return wasStarted
180+
}
181+
override fun stopForegroundService(): Boolean {
182+
val wasStopped = super.stopForegroundService()
183+
if (wasStopped)
184+
broadcastLogger.debug("Service sent to Background")
185+
return wasStopped
186+
}
187+
161188

162189
/////////////////
163190
/// TOPL-Core ///

topl-service/src/main/java/io/matthewnelson/topl_service/service/components/receiver/TorServiceReceiver.kt

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
* */
6767
package io.matthewnelson.topl_service.service.components.receiver
6868

69+
import android.app.KeyguardManager
6970
import android.content.BroadcastReceiver
7071
import android.content.Context
7172
import android.content.Intent
@@ -94,36 +95,56 @@ internal class TorServiceReceiver(private val torService: BaseService): Broadcas
9495
@Volatile
9596
var isRegistered = false
9697
private set
98+
99+
@Volatile
100+
var deviceIsLocked: Boolean? = null
101+
private set
97102
}
98103

99104
private val broadcastLogger = torService.getBroadcastLogger(TorServiceReceiver::class.java)
100105

101106
fun register() {
102-
torService.context.applicationContext.registerReceiver(
103-
this, IntentFilter(SERVICE_INTENT_FILTER)
104-
)
107+
val filter = IntentFilter(SERVICE_INTENT_FILTER)
108+
if (torService.doesReceiverNeedToListenForLockScreen()) {
109+
filter.addAction(Intent.ACTION_SCREEN_OFF)
110+
filter.addAction(Intent.ACTION_SCREEN_ON)
111+
filter.addAction(Intent.ACTION_USER_PRESENT)
112+
}
113+
torService.context.applicationContext.registerReceiver(this, filter)
105114
if (!isRegistered)
106115
broadcastLogger.debug("Has been registered")
107116
isRegistered = true
108117
}
109118

119+
/**
120+
* Sets [deviceIsLocked] to the value sent. If [value] is null, it will check
121+
* KeyguardManager.
122+
* */
123+
fun setDeviceIsLocked(value: Boolean? = null) {
124+
deviceIsLocked = value ?: checkIfDeviceIsLocked()
125+
}
126+
110127
fun unregister() {
111128
if (isRegistered) {
112129
try {
113130
torService.context.applicationContext.unregisterReceiver(this)
114131
isRegistered = false
132+
setDeviceIsLocked()
115133
broadcastLogger.debug("Has been unregistered")
116134
} catch (e: IllegalArgumentException) {
117135
broadcastLogger.exception(e)
118136
}
119137
}
120138
}
121139

140+
private fun checkIfDeviceIsLocked(): Boolean? {
141+
val keyguardManager = torService.context.applicationContext
142+
.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
143+
return keyguardManager?.isKeyguardLocked
144+
}
145+
122146
override fun onReceive(context: Context?, intent: Intent?) {
123147
if (context != null && intent != null) {
124-
// Only accept Intents from this package.
125-
if (context.applicationInfo.dataDir != torService.context.applicationInfo.dataDir) return
126-
127148
when (val serviceAction = intent.getStringExtra(SERVICE_INTENT_FILTER)) {
128149
ServiceActionName.NEW_ID -> {
129150
torService.processServiceAction(ServiceActions.NewId())
@@ -135,9 +156,25 @@ internal class TorServiceReceiver(private val torService: BaseService): Broadcas
135156
torService.processServiceAction(ServiceActions.Stop())
136157
}
137158
else -> {
138-
broadcastLogger.warn(
139-
"This class does not accept $serviceAction as an argument."
140-
)
159+
160+
when (intent.action) {
161+
Intent.ACTION_SCREEN_OFF,
162+
Intent.ACTION_SCREEN_ON,
163+
Intent.ACTION_USER_PRESENT -> {
164+
val locked = checkIfDeviceIsLocked()
165+
if (locked != deviceIsLocked) {
166+
setDeviceIsLocked(locked)
167+
broadcastLogger.debug("Device is locked: $deviceIsLocked")
168+
torService.refreshNotificationActions()
169+
}
170+
}
171+
else -> {
172+
broadcastLogger.warn(
173+
"This class does not accept $serviceAction as an argument."
174+
)
175+
}
176+
}
177+
141178
}
142179
}
143180
}

topl-service/src/test/java/io/matthewnelson/test_helpers/service/TestTorService.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ internal class TestTorService(
123123
override fun registerReceiver() {
124124
torServiceReceiver.register()
125125
}
126+
override fun setIsDeviceLocked() {
127+
torServiceReceiver.setDeviceIsLocked()
128+
}
126129
override fun unregisterReceiver() {
127130
torServiceReceiver.unregister()
128131
}

0 commit comments

Comments
 (0)