Skip to content

Commit 8f99f8e

Browse files
WIP: Bug 2037747 - Add per-feature update notifications to the Android Nimbus client
1 parent 8976165 commit 8f99f8e

1 file changed

Lines changed: 81 additions & 8 deletions

File tree

  • components/nimbus/android/src/main/java/org/mozilla/experiments/nimbus

components/nimbus/android/src/main/java/org/mozilla/experiments/nimbus/Nimbus.kt

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,65 @@ open class Nimbus(
179179
}
180180
}
181181

182+
public val updates = object {
183+
private val lock = ReentrantLock()
184+
private val callbackMap: MutableMap<String, MutableSet<() -> Unit>> = mutableMapOf()
185+
186+
@AnyThread
187+
public fun register(featureId: String, callback: () -> Unit) {
188+
lock.runBlock {
189+
callbackMap
190+
.getOrPut(featureId, arrayListOf)
191+
.add(callback)
192+
}
193+
}
194+
195+
@AnyThread
196+
public fun unregister(featureId: String, callback: () -> Unit) {
197+
lock.runBlock {
198+
callbackMap.get(featureId)?.run { remove(callback) }
199+
}
200+
}
201+
202+
@AnyThread
203+
public fun notifyChanged(events: List<EnrollmentChangeEvent>) {
204+
if (events.isEmpty()) {
205+
return
206+
}
207+
208+
val featureIds: MutableSet<String> = mutableSetOf()
209+
210+
for (event in events) {
211+
for (featureId in event.featureIds) {
212+
featureIds.add(featureId)
213+
}
214+
}
215+
216+
notifyFeatures(featureIds)
217+
}
218+
219+
@AnyThread
220+
public fun notifyFeatures(featureIds: Set<String>) {
221+
val toUpdate = arrayListOf()
222+
223+
lock.runBlock {
224+
for (featureId in featureIds) {
225+
callbackMap.get(featureId)?.also { callbacks ->
226+
for (callback of callbacks) {
227+
toUpdate.add(callback)
228+
}
229+
}
230+
}
231+
}
232+
233+
scope.launch(Dispatchers.Main) {
234+
for (callback of toUpdate) {
235+
callback()
236+
}
237+
}
238+
}
239+
}
240+
182241
init {
183242
NullVariables.instance.setContext(context)
184243

@@ -279,7 +338,7 @@ open class Nimbus(
279338
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
280339
internal fun initializeOnThisThread() = withCatchAll("initialize") {
281340
nimbusClient.initialize()
282-
postEnrolmentCalculation()
341+
postEnrolmentCalculation(true)
283342
}
284343

285344
override fun fetchExperiments() {
@@ -344,7 +403,8 @@ open class Nimbus(
344403
NimbusHealth.applyPendingExperimentsTime.accumulateSingleSample(time)
345404
recordExperimentTelemetryEvents(events!!)
346405
// Get the experiments to record in telemetry
347-
postEnrolmentCalculation()
406+
postEnrolmentCalculation(false)
407+
updates.notifyChanged(events!!)
348408
} catch (e: NimbusException.InvalidExperimentFormat) {
349409
reportError("Invalid experiment format", e)
350410
}
@@ -379,11 +439,22 @@ open class Nimbus(
379439
}
380440

381441
@WorkerThread
382-
private fun postEnrolmentCalculation() {
383-
nimbusClient.getActiveExperiments().let {
384-
recordExperimentTelemetry(it)
442+
private fun postEnrolmentCalculation(initial: Bool) {
443+
nimbusClient.getActiveExperiments().also { experiments ->
444+
recordExperimentTelemetry(experiments)
385445
updateObserver { observer ->
386-
observer.onUpdatesApplied(it)
446+
observer.onUpdatesApplied(experiments)
447+
}
448+
449+
if (initial) {
450+
val featureIds = mutableSetOf()
451+
for (experiment in experiments) {
452+
for (featureId in experiment.featureIds) {
453+
featureIds.add(featureId)
454+
}
455+
}
456+
457+
updates.notifyFeatures(featureIds)
387458
}
388459
}
389460
}
@@ -431,7 +502,8 @@ open class Nimbus(
431502
val enrolmentChanges = nimbusClient.setExperimentParticipation(active)
432503
if (enrolmentChanges.isNotEmpty()) {
433504
recordExperimentTelemetryEvents(enrolmentChanges)
434-
postEnrolmentCalculation()
505+
postEnrolmentCalculation(false)
506+
updates.notifyChanged(enrolmentChanges)
435507
}
436508
}
437509

@@ -442,7 +514,8 @@ open class Nimbus(
442514
val enrolmentChanges = nimbusClient.setRolloutParticipation(active)
443515
if (enrolmentChanges.isNotEmpty()) {
444516
recordExperimentTelemetryEvents(enrolmentChanges)
445-
postEnrolmentCalculation()
517+
postEnrolmentCalculation(false)
518+
updates.notifyChanged(enrolmentChanges)
446519
}
447520
}
448521

0 commit comments

Comments
 (0)