Skip to content

Commit 3c6bdce

Browse files
experimenter-github-app[bot]Experimenter CircleCI Bot
andauthored
chore(nimbus): Update External Configs (#15106)
SUMMARY: FAILURES: fenix at main (65f89c383b216d3b4f210657c9af12a32048fb67) version None Traceback (most recent call last): File "/experimenter/manifesttool/fetch.py", line 128, in fetch_fml_app fetch_targeting_files( ~~~~~~~~~~~~~~~~~~~~~^ manifest_dir / app_config.slug / f"v{version}", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... ref, ^^^^ ) ^ File "/experimenter/manifesttool/fetch.py", line 48, in fetch_targeting_files github_api.fetch_file( ~~~~~~~~~~~~~~~~~~~~~^ app_config.repo.name, ^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... save_path / Path(targeting_files_path[0]).name, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/experimenter/manifesttool/github_api.py", line 148, in fetch_file download.to_path(url, download_path) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^ File "/experimenter/manifesttool/download.py", line 11, in to_path with download_path.open("wb") as f: ~~~~~~~~~~~~~~~~~~^^^^^^ File "/usr/local/lib/python3.13/pathlib/_local.py", line 537, in open return io.open(self, mode, buffering, encoding, errors, newline) ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: '/experimenter/experimenter/features/manifests/fenix/vNone/RecordedNimbusContext.kt' firefox_ios at main (910723aef887ba5808d6726adf3310b486dd668e) version None Traceback (most recent call last): File "/experimenter/manifesttool/fetch.py", line 128, in fetch_fml_app fetch_targeting_files( ~~~~~~~~~~~~~~~~~~~~~^ manifest_dir / app_config.slug / f"v{version}", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... ref, ^^^^ ) ^ File "/experimenter/manifesttool/fetch.py", line 48, in fetch_targeting_files github_api.fetch_file( ~~~~~~~~~~~~~~~~~~~~~^ app_config.repo.name, ^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... save_path / Path(targeting_files_path[0]).name, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/experimenter/manifesttool/github_api.py", line 148, in fetch_file download.to_path(url, download_path) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^ File "/experimenter/manifesttool/download.py", line 11, in to_path with download_path.open("wb") as f: ~~~~~~~~~~~~~~~~~~^^^^^^ File "/usr/local/lib/python3.13/pathlib/_local.py", line 537, in open return io.open(self, mode, buffering, encoding, errors, newline) ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: '/experimenter/experimenter/features/manifests/ios/vNone/RecordedNimbusContext.swift' firefox_desktop at main (65f89c383b216d3b4f210657c9af12a32048fb67) version None Traceback (most recent call last): File "/experimenter/manifesttool/fetch.py", line 197, in fetch_legacy_app fetch_targeting_files( ~~~~~~~~~~~~~~~~~~~~~^ manifest_dir / app_config.slug / f"v{version}", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... ref, ^^^^ ) ^ File "/experimenter/manifesttool/fetch.py", line 48, in fetch_targeting_files github_api.fetch_file( ~~~~~~~~~~~~~~~~~~~~~^ app_config.repo.name, ^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... save_path / Path(targeting_files_path[0]).name, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/experimenter/manifesttool/github_api.py", line 148, in fetch_file download.to_path(url, download_path) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^ File "/experimenter/manifesttool/download.py", line 11, in to_path with download_path.open("wb") as f: ~~~~~~~~~~~~~~~~~~^^^^^^ File "/usr/local/lib/python3.13/pathlib/_local.py", line 537, in open return io.open(self, mode, buffering, encoding, errors, newline) ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: '/experimenter/experimenter/features/manifests/firefox-desktop/vNone/TargetingContextRecorder.sys.mjs' firefox_desktop at esr115 (df307a4853c0d2a6bfeab5a2e2dbaaa77c31c9e4) version 115.35.0 Traceback (most recent call last): File "/experimenter/manifesttool/fetch.py", line 197, in fetch_legacy_app fetch_targeting_files( ~~~~~~~~~~~~~~~~~~~~~^ manifest_dir / app_config.slug / f"v{version}", ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... ref, ^^^^ ) ^ File "/experimenter/manifesttool/fetch.py", line 48, in fetch_targeting_files github_api.fetch_file( ~~~~~~~~~~~~~~~~~~~~~^ app_config.repo.name, ^^^^^^^^^^^^^^^^^^^^^ ...<2 lines>... save_path / Path(targeting_files_path[0]).name, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "/experimenter/manifesttool/github_api.py", line 141, in fetch_file rsp.raise_for_status() ~~~~~~~~~~~~~~~~~~~~^^ File "/usr/local/lib/python3.13/site-packages/requests/models.py", line 1028, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://api.github.com/repos/mozilla-firefox/firefox/contents/toolkit/components/nimbus/lib/TargetingContextRecorder.sys.mjs?ref=df307a4853c0d2a6bfeab5a2e2dbaaa77c31c9e4 SUCCESS: fenix at main (65f89c383b216d3b4f210657c9af12a32048fb67) version 151.0.0 fenix at beta (d75cc5e34258d2b65a9d2b89bfe05fa7329e5df3) version 150.0.0 monitor_cirrus at main (d577ac636f50cd1acd534761eeb3b196c61591a5) version None firefox_accounts_cirrus at main (a92db8c4db4baeaf3409181fd724974986a3744f) version None firefox_desktop at main (65f89c383b216d3b4f210657c9af12a32048fb67) version 151.0.0 firefox_desktop at beta (d75cc5e34258d2b65a9d2b89bfe05fa7329e5df3) version 150.0.0 subplat_cirrus at main (a92db8c4db4baeaf3409181fd724974986a3744f) version None CACHED: fenix at release (8f58f40bb8909a3a14d5fe5f627118d048bc413f) version 149.0.2 (cached) firefox_ios at release/v145.0 (12d7a6f994b7ea6391dba6d8ca0717b1699ecd47) version 145.0.1 (cached) firefox_ios at release/v145.1 (93b2bd09e2bc2687c09630a27a6c6618e8db0e42) version 145.1.1 (cached) firefox_ios at release/v145.2 (f9df5f162a0db305be03b5a4f5161cb21e34ce02) version 145.2.1 (cached) firefox_ios at release/v145.3 (fb7cf83d4392e1a072788c0c3ff876f859d75884) version 145.3.1 (cached) firefox_ios at release/v146.0 (a88e7f1ba821342fffffc14da5096474e62780a4) version 146.0.1 (cached) firefox_ios at release/v146.1 (ea643ef53e70c48ca25bb674f894945e55220d03) version 146.1.1 (cached) firefox_ios at release/v147.0 (b4245fd8bf7e102c01055a1c4b418afa48093429) version 147.0.1 (cached) firefox_ios at release/v147.1 (a220c06a8c6c3bb57c19049d903d6a37396df085) version 147.1.1 (cached) firefox_ios at release/v147.2 (306eb1b46e5c1672ef7c8901cca054ff46b4ae82) version 147.2.2 (cached) firefox_ios at release/v147.3 (9c2728a4bba87405151a16d0a63eccf3c1f29163) version 147.3.1 (cached) firefox_ios at release/v147.4 (95fef469924d431d1a00ce04647eecccbf213812) version 147.4.1 (cached) firefox_ios at release/v147.5 (bf74916de8790bdc7c88531e15ab17d6ec56b04f) version 147.5.1 (cached) firefox_ios at release/v148.0 (090b4555b4c20a97bbfc85fbf02440bcfd406610) version 148.0.1 (cached) firefox_ios at release/v148.1 (96b1d7dd87685b82b8e2a0c165fc60c3b4d9cc8f) version 148.1.1 (cached) firefox_ios at release/v148.2 (71f2e2c632ea875b85dcaec25b0aa4fa3519ba97) version 148.2.1 (cached) firefox_ios at release/v148.3 (0edc073a6f3b69d0883f64c4310be2a6aa30ecc5) version 148.3.1 (cached) firefox_ios at release/v149.0 (a679ff252ca3a82c36c1ef5291a4d1d936034c31) version 149.0.1 (cached) firefox_ios at release/v149.1 (93f6fc2bcd799f74753248ea94938f2a0e1f7cf7) version 149.1.1 (cached) firefox_ios at release/v149.2 (bbf01266055948c34e58ab25d6c77d73d8592acc) version 149.2.0 (cached) firefox_ios at firefox-v149.1 (56fa93d90f435d10977e675aac4d679f1d256e3a) version 149.1.0 (cached) firefox_ios at firefox-v149.0 (9db4bd51a49cfef1593cd30d07d314b21cc639a1) version 149.0.0 (cached) firefox_ios at firefox-v148.3 (1b5be10df86c50e67cea5cc55d6e9dbe66921da9) version 148.3.0 (cached) firefox_ios at firefox-v148.2 (f1efef1c856662666006ed563686ed39c4e0cade) version 148.2.0 (cached) firefox_ios at firefox-v148.1 (981a01118303b8707b432e1d73040e8fd1c9cf8a) version 148.1.0 (cached) firefox_ios at firefox-v148.0 (beacfdda9beb2af76455521594ebfe2fb5b53824) version 148.0.0 (cached) firefox_ios at firefox-v147.5 (419dce5232746280706aeb1a777f95b3d76f84ff) version 147.5.0 (cached) firefox_ios at firefox-v147.4 (1fe8bc1836b4326ec15207c61b1363fe83f53a92) version 147.4.0 (cached) firefox_ios at firefox-v147.3 (33730a472dd94e2638307078cf2ffd124d12db21) version 147.3.0 (cached) firefox_ios at firefox-v147.2 (1931e0204698064de1e292ea873b617cf44b1244) version 147.2.0 (cached) firefox_ios at firefox-v147.1 (9e21c0bc53bb598ded45b478077a3b2bd17266db) version 147.1.0 (cached) firefox_ios at firefox-v147.0 (f46e2b4822278910a63f8aaf0ad753ce6504f9b4) version 147.0.0 (cached) firefox_ios at firefox-v146.1 (dacd8c4bd43b9f1cfea462460e56f4a0445428ab) version 146.1.0 (cached) firefox_ios at firefox-v146.0 (dcd0b14ecc104ff1dd413c5d694a9f24b5b50712) version 146.0.0 (cached) firefox_ios at firefox-v145.3 (966c9be1a09d3606bba6346bb5cda7e67774bf34) version 145.3.0 (cached) firefox_ios at firefox-v145.2 (60529545c78b22e25592a7a86213ab8970357ee5) version 145.2.0 (cached) firefox_ios at firefox-v145.1 (6d4a66eb019f7d823b8936d2dde61e4aa2ac17ad) version 145.1.0 (cached) firefox_ios at firefox-v145.0 (8e1108614b88fa7825f9df2d0aa862da198005fc) version 145.0.0 (cached) firefox_ios at main (910723aef887ba5808d6726adf3310b486dd668e) version 149.3.0 (cached) firefox_desktop at release (8f58f40bb8909a3a14d5fe5f627118d048bc413f) version 149.0.2 (cached) firefox_desktop at esr128 (ed38f9209e39bd7ad247c81a7c20c99c874e0a62) version 128.14.1 (cached) firefox_desktop at esr140 (19cb7fc541ee5d1a634efea7d81fd3af8d815896) version 140.10.0 (cached) Circle CI Task: https://circleci.com/gh/mozilla/experimenter/459214 Co-authored-by: Experimenter CircleCI Bot <experimenter-ci-bot@mozilla.com>
1 parent 82ccf5c commit 3c6bdce

File tree

4 files changed

+706
-4
lines changed

4 files changed

+706
-4
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
beta: 297827132187bc82045c2d67eac75b2b7d3a76c3
2-
main: 9a3317a65545e83f4e32b94fdf1f6860342423ef
1+
beta: d75cc5e34258d2b65a9d2b89bfe05fa7329e5df3
2+
main: 65f89c383b216d3b4f210657c9af12a32048fb67
33
release: 8f58f40bb8909a3a14d5fe5f627118d048bc413f
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package org.mozilla.fenix.experiments
6+
7+
import android.content.Context
8+
import android.os.Build
9+
import androidx.annotation.VisibleForTesting
10+
import mozilla.components.support.locale.LocaleManager
11+
import mozilla.components.support.locale.LocaleManager.getSystemDefault
12+
import mozilla.components.support.utils.ext.packageManagerCompatHelper
13+
import org.json.JSONArray
14+
import org.json.JSONObject
15+
import org.mozilla.experiments.nimbus.NIMBUS_DATA_DIR
16+
import org.mozilla.experiments.nimbus.NimbusDeviceInfo
17+
import org.mozilla.experiments.nimbus.internal.JsonObject
18+
import org.mozilla.experiments.nimbus.internal.RecordedContext
19+
import org.mozilla.experiments.nimbus.internal.getCalculatedAttributes
20+
import org.mozilla.fenix.GleanMetrics.NimbusSystem
21+
import org.mozilla.fenix.GleanMetrics.Pings
22+
import org.mozilla.fenix.ext.settings
23+
import org.mozilla.fenix.home.pocket.ContentRecommendationsFeatureHelper
24+
import org.mozilla.fenix.termsofuse.experimentation.TermsOfUseAdvancedTargetingHelper
25+
import org.mozilla.fenix.termsofuse.experimentation.utils.DefaultTermsOfUseDataProvider
26+
import org.mozilla.fenix.utils.Settings
27+
import java.io.File
28+
29+
/**
30+
* The following constants are string constants of the keys that appear in the [EVENT_QUERIES] map.
31+
*/
32+
const val DAYS_OPENED_IN_LAST_28 = "days_opened_in_last_28"
33+
34+
/**
35+
* [EVENT_QUERIES] is a map of keys to Nimbus SDK EventStore queries.
36+
*/
37+
private val EVENT_QUERIES = mapOf(
38+
DAYS_OPENED_IN_LAST_28 to "'events.app_opened'|eventCountNonZero('Days', 28, 0)",
39+
)
40+
41+
/**
42+
* The RecordedNimbusContext class inherits from an internal Nimbus interface that provides methods
43+
* for obtaining a JSON value for the object and recording the object's value to Glean. Its JSON
44+
* value is loaded into the Nimbus targeting context.
45+
*
46+
* The value recorded to Glean is used to automate population sizing. Any additions to this object
47+
* require a new data review for the `nimbus_system.recorded_nimbus_context` metric.
48+
*/
49+
@Suppress("complexity:LongParameterList")
50+
class RecordedNimbusContext(
51+
val isFirstRun: Boolean,
52+
private val eventQueries: Map<String, String> = mapOf(),
53+
private var eventQueryValues: Map<String, Double> = mapOf(),
54+
val utmSource: String,
55+
val utmMedium: String,
56+
val utmCampaign: String,
57+
val utmTerm: String,
58+
val utmContent: String,
59+
val androidSdkVersion: String = Build.VERSION.SDK_INT.toString(),
60+
val appVersion: String?,
61+
val locale: String,
62+
val daysSinceInstall: Int?,
63+
val daysSinceUpdate: Int?,
64+
val language: String?,
65+
val region: String?,
66+
val deviceManufacturer: String = Build.MANUFACTURER,
67+
val deviceModel: String = Build.MODEL,
68+
val userAcceptedTou: Boolean,
69+
val noShortcutsOrStoriesOptOuts: Boolean,
70+
val addonIds: List<String>,
71+
val touPoints: Int?,
72+
) : RecordedContext {
73+
/**
74+
* [getEventQueries] is called by the Nimbus SDK Rust code to retrieve the map of event
75+
* queries. The are then executed against the Nimbus SDK's EventStore to retrieve their values.
76+
*
77+
* @return Map<String, String>
78+
*/
79+
override fun getEventQueries(): Map<String, String> {
80+
return eventQueries
81+
}
82+
83+
/**
84+
* [record] is called when experiment enrollments are evolved. It should apply the
85+
* [RecordedNimbusContext]'s values to a [NimbusSystem.RecordedNimbusContextObject] instance,
86+
* and use that instance to record the values to Glean.
87+
*/
88+
override fun record() {
89+
val eventQueryValuesObject = NimbusSystem.RecordedNimbusContextObjectItemEventQueryValuesObject(
90+
daysOpenedInLast28 = eventQueryValues[DAYS_OPENED_IN_LAST_28]?.toInt(),
91+
)
92+
NimbusSystem.recordedNimbusContext.set(
93+
NimbusSystem.RecordedNimbusContextObject(
94+
isFirstRun = isFirstRun,
95+
eventQueryValues = eventQueryValuesObject,
96+
installReferrerResponseUtmSource = utmSource,
97+
installReferrerResponseUtmMedium = utmMedium,
98+
installReferrerResponseUtmCampaign = utmCampaign,
99+
installReferrerResponseUtmTerm = utmTerm,
100+
installReferrerResponseUtmContent = utmContent,
101+
androidSdkVersion = androidSdkVersion,
102+
appVersion = appVersion,
103+
locale = locale,
104+
daysSinceInstall = daysSinceInstall,
105+
daysSinceUpdate = daysSinceUpdate,
106+
language = language,
107+
region = region,
108+
deviceManufacturer = deviceManufacturer,
109+
deviceModel = deviceModel,
110+
userAcceptedTou = userAcceptedTou,
111+
noShortcutsOrStoriesOptOuts = noShortcutsOrStoriesOptOuts,
112+
addonIds = NimbusSystem.RecordedNimbusContextObjectAddonIds(addonIds.toMutableList()),
113+
touPoints = touPoints,
114+
),
115+
)
116+
Pings.nimbus.submit()
117+
}
118+
119+
/**
120+
* [setEventQueryValues] is called by the Nimbus SDK Rust code after the event queries have been
121+
* executed. The [eventQueryValues] should be written back to the Kotlin object.
122+
*
123+
* @param [eventQueryValues] The values for each query after they have been executed in the
124+
* Nimbus SDK Rust environment.
125+
*/
126+
override fun setEventQueryValues(eventQueryValues: Map<String, Double>) {
127+
this.eventQueryValues = eventQueryValues
128+
}
129+
130+
/**
131+
* [toJson] is called by the Nimbus SDK Rust code after the event queries have been executed,
132+
* and before experiment enrollments have been evolved. The value returned from this method
133+
* will be applied directly to the Nimbus targeting context, and its keys/values take
134+
* precedence over those in the main Nimbus targeting context.
135+
*
136+
* @return JSONObject
137+
*/
138+
override fun toJson(): JsonObject {
139+
val obj = JSONObject(
140+
mapOf(
141+
"is_first_run" to isFirstRun,
142+
"events" to JSONObject(eventQueryValues),
143+
"install_referrer_response_utm_source" to utmSource,
144+
"install_referrer_response_utm_medium" to utmMedium,
145+
"install_referrer_response_utm_campaign" to utmCampaign,
146+
"install_referrer_response_utm_term" to utmTerm,
147+
"install_referrer_response_utm_content" to utmContent,
148+
"android_sdk_version" to androidSdkVersion,
149+
"app_version" to appVersion,
150+
"locale" to locale,
151+
"days_since_install" to daysSinceInstall,
152+
"days_since_update" to daysSinceUpdate,
153+
"language" to language,
154+
"region" to region,
155+
"device_manufacturer" to deviceManufacturer,
156+
"device_model" to deviceModel,
157+
"user_accepted_tou" to userAcceptedTou,
158+
"no_shortcuts_or_stories_opt_outs" to noShortcutsOrStoriesOptOuts,
159+
"addon_ids" to JSONArray(addonIds),
160+
"tou_points" to touPoints,
161+
),
162+
)
163+
return obj
164+
}
165+
166+
/**
167+
* Companion object for RecordedNimbusContext
168+
*/
169+
companion object {
170+
171+
/**
172+
* Creates a RecordedNimbusContext instance, populated with the application-defined
173+
* eventQueries
174+
*
175+
* @return RecordedNimbusContext
176+
*/
177+
fun create(
178+
context: Context,
179+
isFirstRun: Boolean,
180+
): RecordedNimbusContext {
181+
val settings = context.settings()
182+
val langTag = LocaleManager.getCurrentLocale(context)
183+
?.toLanguageTag() ?: getSystemDefault().toLanguageTag()
184+
val termsOfUseAdvancedTargetingHelper = TermsOfUseAdvancedTargetingHelper(
185+
DefaultTermsOfUseDataProvider(settings),
186+
langTag,
187+
)
188+
189+
val packageInfo =
190+
context.packageManagerCompatHelper.getPackageInfoCompat(context.packageName, 0)
191+
val deviceInfo = NimbusDeviceInfo.default()
192+
val db = File(context.applicationInfo.dataDir, NIMBUS_DATA_DIR)
193+
val calculatedAttributes = getCalculatedAttributes(
194+
packageInfo.firstInstallTime,
195+
db.path,
196+
deviceInfo.localeTag,
197+
)
198+
199+
return RecordedNimbusContext(
200+
isFirstRun = isFirstRun,
201+
eventQueries = EVENT_QUERIES,
202+
utmSource = settings.utmSource,
203+
utmMedium = settings.utmMedium,
204+
utmCampaign = settings.utmCampaign,
205+
utmTerm = settings.utmTerm,
206+
utmContent = settings.utmContent,
207+
appVersion = packageInfo.versionName,
208+
locale = deviceInfo.localeTag,
209+
daysSinceInstall = calculatedAttributes.daysSinceInstall,
210+
daysSinceUpdate = calculatedAttributes.daysSinceUpdate,
211+
language = calculatedAttributes.language,
212+
region = calculatedAttributes.region,
213+
userAcceptedTou = settings.hasAcceptedTermsOfService,
214+
noShortcutsOrStoriesOptOuts = settings.noShortcutsOrStoriesOptOuts(context),
215+
addonIds = getFormattedAddons(settings),
216+
touPoints = termsOfUseAdvancedTargetingHelper.getTouPoints(),
217+
)
218+
}
219+
220+
@VisibleForTesting
221+
internal fun getFormattedAddons(settings: Settings): List<String> =
222+
settings.installedAddonsList.split(",").map { it.trim() }
223+
224+
/**
225+
* Checks whether an eligible user has opted out of any sponsored top sites or stories.
226+
*
227+
* @return `true` if the user has opted out of any sponsored top sites or stories,
228+
* `false` otherwise.
229+
*/
230+
private fun Settings.noShortcutsOrStoriesOptOuts(context: Context) =
231+
!optedOutOfSponsoredTopSites() && !optedOutOfSponsoredStories(context)
232+
233+
/**
234+
* Checks whether an eligible user has opted out of the sponsored top sites feature.
235+
*
236+
* This is not entirely self evident from the API descriptions, please note:
237+
* [Settings.showContileFeature] indicates whether the sponsored shortcuts are shown.
238+
* [Settings.showTopSitesFeature] indicates whether the feature should be shown at all.
239+
*/
240+
private fun Settings.optedOutOfSponsoredTopSites() =
241+
!showContileFeature || !showTopSitesFeature
242+
243+
private fun Settings.optedOutOfSponsoredStories(context: Context) =
244+
isEligibleForStories(context) && (!showPocketSponsoredStories || !showPocketRecommendationsFeature)
245+
246+
private fun isEligibleForStories(context: Context): Boolean =
247+
ContentRecommendationsFeatureHelper.isContentRecommendationsFeatureEnabled(context)
248+
249+
/**
250+
* Creates a RecordedNimbusContext instance for test purposes
251+
*
252+
* @return RecordedNimbusContext
253+
*/
254+
@VisibleForTesting
255+
internal fun createForTest(
256+
isFirstRun: Boolean = false,
257+
eventQueries: Map<String, String> = EVENT_QUERIES,
258+
eventQueryValues: Map<String, Double> = mapOf(),
259+
addonIds: List<String> = emptyList(),
260+
): RecordedNimbusContext {
261+
return RecordedNimbusContext(
262+
isFirstRun = isFirstRun,
263+
eventQueries = eventQueries,
264+
eventQueryValues = eventQueryValues,
265+
utmSource = "",
266+
utmMedium = "",
267+
utmCampaign = "",
268+
utmTerm = "",
269+
utmContent = "",
270+
appVersion = "",
271+
locale = "",
272+
daysSinceInstall = 5,
273+
daysSinceUpdate = 0,
274+
language = "en",
275+
region = "US",
276+
userAcceptedTou = true,
277+
noShortcutsOrStoriesOptOuts = true,
278+
addonIds = addonIds,
279+
touPoints = 3,
280+
)
281+
}
282+
}
283+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
beta: 297827132187bc82045c2d67eac75b2b7d3a76c3
1+
beta: d75cc5e34258d2b65a9d2b89bfe05fa7329e5df3
22
esr115: e332f5355ae1dacba648a84c60a4434ae475bb04
33
esr128: ed38f9209e39bd7ad247c81a7c20c99c874e0a62
44
esr140: 19cb7fc541ee5d1a634efea7d81fd3af8d815896
5-
main: 9a3317a65545e83f4e32b94fdf1f6860342423ef
5+
main: 65f89c383b216d3b4f210657c9af12a32048fb67
66
release: 8f58f40bb8909a3a14d5fe5f627118d048bc413f

0 commit comments

Comments
 (0)