mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
Stop nearby notes while app is backgrounded
This commit is contained in:
parent
6fad768a3d
commit
416dc989e8
@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
*
|
*
|
||||||
* Merely rendering the mesh timeline must not open a building-precision Nostr
|
* Merely rendering the mesh timeline must not open a building-precision Nostr
|
||||||
* subscription. A subscription is eligible only after an explicit reveal and
|
* subscription. A subscription is eligible only after an explicit reveal and
|
||||||
* while at least one nearby-notes surface is active.
|
* while the app is foregrounded and at least one nearby-notes surface is active.
|
||||||
*/
|
*/
|
||||||
@MainThread
|
@MainThread
|
||||||
class NearbyNotesController internal constructor(
|
class NearbyNotesController internal constructor(
|
||||||
@ -25,6 +25,7 @@ class NearbyNotesController internal constructor(
|
|||||||
private var activeHolders = 0
|
private var activeHolders = 0
|
||||||
private var locationEnabled = false
|
private var locationEnabled = false
|
||||||
private var locationAuthorized = false
|
private var locationAuthorized = false
|
||||||
|
private var appForeground = false
|
||||||
private var buildingGeohash: String? = null
|
private var buildingGeohash: String? = null
|
||||||
private var subscribedGeohash: String? = null
|
private var subscribedGeohash: String? = null
|
||||||
|
|
||||||
@ -50,6 +51,12 @@ class NearbyNotesController internal constructor(
|
|||||||
reconcileSubscription()
|
reconcileSubscription()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Closes the live subscription whenever the process leaves the foreground. */
|
||||||
|
fun updateAppForeground(isForeground: Boolean) {
|
||||||
|
appForeground = isForeground
|
||||||
|
reconcileSubscription()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the privacy-sensitive inputs independently of view activation.
|
* Updates the privacy-sensitive inputs independently of view activation.
|
||||||
* Permission revocation, location disable, or loss of the building cell
|
* Permission revocation, location disable, or loss of the building cell
|
||||||
@ -78,6 +85,7 @@ class NearbyNotesController internal constructor(
|
|||||||
private fun reconcileSubscription() {
|
private fun reconcileSubscription() {
|
||||||
val target = buildingGeohash.takeIf {
|
val target = buildingGeohash.takeIf {
|
||||||
activeHolders > 0 &&
|
activeHolders > 0 &&
|
||||||
|
appForeground &&
|
||||||
_revealed.value &&
|
_revealed.value &&
|
||||||
locationEnabled &&
|
locationEnabled &&
|
||||||
locationAuthorized
|
locationAuthorized
|
||||||
|
|||||||
@ -29,6 +29,10 @@ import androidx.compose.ui.semantics.contentDescription
|
|||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.bitchat.android.R
|
import com.bitchat.android.R
|
||||||
import com.bitchat.android.geohash.ChannelID
|
import com.bitchat.android.geohash.ChannelID
|
||||||
@ -117,6 +121,30 @@ fun ChatScreen(viewModel: ChatViewModel) {
|
|||||||
selectedPrivatePeer == null &&
|
selectedPrivatePeer == null &&
|
||||||
privateChatSheetPeer == null
|
privateChatSheetPeer == null
|
||||||
|
|
||||||
|
val processLifecycleOwner = remember { ProcessLifecycleOwner.get() }
|
||||||
|
DisposableEffect(processLifecycleOwner, nearbyNotesController) {
|
||||||
|
val lifecycle = processLifecycleOwner.lifecycle
|
||||||
|
val observer = object : DefaultLifecycleObserver {
|
||||||
|
override fun onStart(owner: LifecycleOwner) {
|
||||||
|
nearbyNotesController.updateAppForeground(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop(owner: LifecycleOwner) {
|
||||||
|
nearbyNotesController.updateAppForeground(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle.addObserver(observer)
|
||||||
|
nearbyNotesController.updateAppForeground(
|
||||||
|
lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED),
|
||||||
|
)
|
||||||
|
|
||||||
|
onDispose {
|
||||||
|
lifecycle.removeObserver(observer)
|
||||||
|
nearbyNotesController.updateAppForeground(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DisposableEffect(
|
DisposableEffect(
|
||||||
isMeshTimeline,
|
isMeshTimeline,
|
||||||
locationEnabled,
|
locationEnabled,
|
||||||
|
|||||||
@ -16,9 +16,13 @@ class NearbyNotesControllerTest {
|
|||||||
unsubscribe = { unsubscribeCount += 1 },
|
unsubscribe = { unsubscribeCount += 1 },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun foregroundController() = controller().also {
|
||||||
|
it.updateAppForeground(true)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `active mesh timeline does not subscribe before explicit reveal`() {
|
fun `active mesh timeline does not subscribe before explicit reveal`() {
|
||||||
val controller = controller()
|
val controller = foregroundController()
|
||||||
|
|
||||||
controller.updateAvailability(
|
controller.updateAvailability(
|
||||||
locationEnabled = true,
|
locationEnabled = true,
|
||||||
@ -38,7 +42,7 @@ class NearbyNotesControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `reveal remains dormant until a nearby notes surface is active`() {
|
fun `reveal remains dormant until a nearby notes surface is active`() {
|
||||||
val controller = controller()
|
val controller = foregroundController()
|
||||||
controller.updateAvailability(true, true, "u4pruydq")
|
controller.updateAvailability(true, true, "u4pruydq")
|
||||||
|
|
||||||
controller.reveal()
|
controller.reveal()
|
||||||
@ -52,7 +56,7 @@ class NearbyNotesControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `last deactivate unsubscribes exactly once`() {
|
fun `last deactivate unsubscribes exactly once`() {
|
||||||
val controller = controller()
|
val controller = foregroundController()
|
||||||
controller.updateAvailability(true, true, "u4pruydq")
|
controller.updateAvailability(true, true, "u4pruydq")
|
||||||
controller.reveal()
|
controller.reveal()
|
||||||
controller.activate()
|
controller.activate()
|
||||||
@ -67,9 +71,28 @@ class NearbyNotesControllerTest {
|
|||||||
assertEquals(1, unsubscribeCount)
|
assertEquals(1, unsubscribeCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `backgrounding closes the subscription and foregrounding restores it`() {
|
||||||
|
val controller = foregroundController()
|
||||||
|
controller.updateAvailability(true, true, "u4pruydq")
|
||||||
|
controller.activate()
|
||||||
|
controller.reveal()
|
||||||
|
|
||||||
|
controller.updateAppForeground(false)
|
||||||
|
|
||||||
|
assertEquals(1, unsubscribeCount)
|
||||||
|
assertTrue(controller.revealed.value)
|
||||||
|
|
||||||
|
controller.updateAppForeground(false)
|
||||||
|
assertEquals(1, unsubscribeCount)
|
||||||
|
|
||||||
|
controller.updateAppForeground(true)
|
||||||
|
assertEquals(listOf("u4pruydq", "u4pruydq"), subscriptions)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `disable and permission revocation close the live subscription`() {
|
fun `disable and permission revocation close the live subscription`() {
|
||||||
val controller = controller()
|
val controller = foregroundController()
|
||||||
controller.updateAvailability(true, true, "u4pruydq")
|
controller.updateAvailability(true, true, "u4pruydq")
|
||||||
controller.activate()
|
controller.activate()
|
||||||
controller.reveal()
|
controller.reveal()
|
||||||
@ -91,6 +114,7 @@ class NearbyNotesControllerTest {
|
|||||||
subscribe = { events += "subscribe:$it" },
|
subscribe = { events += "subscribe:$it" },
|
||||||
unsubscribe = { events += "unsubscribe" },
|
unsubscribe = { events += "unsubscribe" },
|
||||||
)
|
)
|
||||||
|
controller.updateAppForeground(true)
|
||||||
controller.updateAvailability(true, true, "u4pruydq")
|
controller.updateAvailability(true, true, "u4pruydq")
|
||||||
controller.activate()
|
controller.activate()
|
||||||
controller.reveal()
|
controller.reveal()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user