Skip to content

Commit 52d813d

Browse files
committed
refactor: [SDK-5088] read the kill switch through the feature manager
The detector scanned the raw fetched flag list because the kill switch key had no catalog entry. Now that it has one, DeviceGestureDetector takes IFeatureManager and asks it for SDK_DEVICE_GESTURE_DISABLED like every other flag, which also drops the hand-rolled case handling. The switch still reads present-means-off, and absent still means on.
1 parent 51df457 commit 52d813d

2 files changed

Lines changed: 15 additions & 13 deletions

File tree

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/gesture/DeviceGestureDetector.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import com.onesignal.common.threading.suspendifyOnMain
99
import com.onesignal.core.internal.application.IApplicationLifecycleHandler
1010
import com.onesignal.core.internal.application.IApplicationService
1111
import com.onesignal.core.internal.config.ConfigModelStore
12+
import com.onesignal.core.internal.features.IFeatureManager
1213
import com.onesignal.core.internal.startup.IStartableService
1314
import com.onesignal.debug.internal.logging.Logging
15+
import com.onesignal.features.FeatureFlag
1416
import com.onesignal.logger.IObservabilityEventRecorder
1517
import com.onesignal.logger.ObservabilityEvent
1618

@@ -26,18 +28,16 @@ import com.onesignal.logger.ObservabilityEvent
2628
* fires when an activity declaring orientation in `configChanges` rotates. The window is the
2729
* only rate rule; six cycles inside it takes sustained five-second round trips.
2830
*
29-
* Adding [KILL_SWITCH_KEY] to the app's enabled feature keys disables the gesture. Absent
30-
* means enabled, so a device that has never fetched flags still has it. Reads the raw
31-
* [com.onesignal.core.internal.config.ConfigModel.sdkRemoteFeatureFlags] list because
32-
* [com.onesignal.core.internal.features.IFeatureManager] only resolves keys the KMP catalog
33-
* registers.
31+
* [FeatureFlag.SDK_DEVICE_GESTURE_DISABLED] turns the gesture off. Absent means enabled, so a
32+
* device that has never fetched flags still has it.
3433
*
3534
* Every recognised gesture also records [ObservabilityEvent.DEVICE_GESTURE], with its outcome
3635
* and the copied ID, so the gesture's usage can be measured.
3736
*/
3837
internal class DeviceGestureDetector(
3938
private val applicationService: IApplicationService,
4039
private val configModelStore: ConfigModelStore,
40+
private val featureManager: IFeatureManager,
4141
private val eventRecorder: IObservabilityEventRecorder,
4242
) : IStartableService,
4343
IApplicationLifecycleHandler {
@@ -112,7 +112,7 @@ internal class DeviceGestureDetector(
112112
// Not recorded either: nothing about the device may ship before consent.
113113
config.consentRequired == true && config.consentGiven != true ->
114114
Logging.debug("DeviceGestureDetector: gesture detected but privacy consent is not granted")
115-
config.sdkRemoteFeatureFlags.any { it.equals(KILL_SWITCH_KEY, ignoreCase = true) } -> {
115+
featureManager.isEnabled(FeatureFlag.SDK_DEVICE_GESTURE_DISABLED) -> {
116116
Logging.debug("DeviceGestureDetector: gesture detected but disabled remotely")
117117
recordGesture(GestureResult.DISABLED)
118118
}
@@ -167,7 +167,6 @@ internal class DeviceGestureDetector(
167167
/** Shortest background phase a human can produce; anything faster is synthetic. */
168168
internal const val MIN_BACKGROUND_DWELL_MS = 250L
169169

170-
internal const val KILL_SWITCH_KEY = "sdk_device_gesture_disabled"
171170
private const val CLIP_LABEL = "OneSignal subscription ID"
172171
private const val CLIP_PREFIX = "os: "
173172
internal const val NO_SUBSCRIPTION_CLIP_TEXT = CLIP_PREFIX + "no subscription ID yet"

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/gesture/DeviceGestureDetectorTests.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import androidx.test.core.app.ApplicationProvider
88
import br.com.colman.kotest.android.extensions.robolectric.RobolectricTest
99
import com.onesignal.core.internal.application.IApplicationLifecycleHandler
1010
import com.onesignal.core.internal.application.IApplicationService
11+
import com.onesignal.core.internal.features.IFeatureManager
12+
import com.onesignal.features.FeatureFlag
1113
import com.onesignal.logger.ILogTelemetry
1214
import com.onesignal.logger.IObservabilityEventRecorder
1315
import com.onesignal.logger.ObservabilityEvent
@@ -57,7 +59,7 @@ private class RecorderSpy : IObservabilityEventRecorder {
5759
*/
5860
private class Harness(
5961
subscriptionId: String? = SUBSCRIPTION_ID,
60-
remoteFlags: List<String> = emptyList(),
62+
killSwitchOn: Boolean = false,
6163
consentRequired: Boolean? = null,
6264
consentGiven: Boolean? = null,
6365
fireOnSubscribe: Boolean = false,
@@ -84,11 +86,13 @@ private class Harness(
8486
val configModelStore =
8587
MockHelper.configModelStore {
8688
it.pushSubscriptionId = subscriptionId
87-
it.sdkRemoteFeatureFlags = remoteFlags
8889
it.consentRequired = consentRequired
8990
it.consentGiven = consentGiven
9091
}
91-
detector = DeviceGestureDetector(applicationService, configModelStore, recorder)
92+
// Strict mock: only the kill switch flag is answered, so asking for anything else fails the test.
93+
val featureManager = mockk<IFeatureManager>()
94+
every { featureManager.isEnabled(FeatureFlag.SDK_DEVICE_GESTURE_DISABLED) } returns killSwitchOn
95+
detector = DeviceGestureDetector(applicationService, configModelStore, featureManager, recorder)
9296
detector.monotonicMillis = { nowMs }
9397
detector.start()
9498
}
@@ -187,8 +191,7 @@ class DeviceGestureDetectorTests : FunSpec({
187191
}
188192

189193
test("the remote kill switch suppresses the copy") {
190-
// Server casing is preserved in the stored list, so match case-insensitively.
191-
val harness = Harness(remoteFlags = listOf("SDK_Device_Gesture_Disabled"))
194+
val harness = Harness(killSwitchOn = true)
192195

193196
repeat(6) { harness.cycle() }
194197
awaitIO()
@@ -285,7 +288,7 @@ class DeviceGestureDetectorTests : FunSpec({
285288
}
286289

287290
test("the remote kill switch records a disabled result without an ID") {
288-
val harness = Harness(remoteFlags = listOf(DeviceGestureDetector.KILL_SWITCH_KEY))
291+
val harness = Harness(killSwitchOn = true)
289292

290293
repeat(6) { harness.cycle() }
291294
awaitIO()

0 commit comments

Comments
 (0)