1"use strict";(self.webpackChunkexperimenter_docs=self.webpackChunkexperimenter_docs||[]).push([[8924],{4137:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function a(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=a(e,["components","mdxType","originalType","parentName"]),c=p(n),d=i,g=c["".concat(s,".").concat(d)]||c[d]||m[d]||o;return n?r.createElement(g,l(l({ref:t},u),{},{components:n})):r.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,l=new Array(o);l[0]=d;var a={};for(var s in t)hasOwnProperty.call(t,s)&&(a[s]=t[s]);a.originalType=e,a[c]="string"==typeof e?e:i,l[1]=a;for(var p=2;p<o;p++)l[p]=n[p];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},1089:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>a,toc:()=>p});var r=n(7462),i=(n(7294),n(4137));const o={id:"getting-started-mobile-required-ui",title:"Required UI",slug:"/platform-guides/android/mobile-ui"},l=void 0,a={unversionedId:"platform-guides/android/getting-started-mobile-required-ui",id:"platform-guides/android/getting-started-mobile-required-ui",title:"Required UI",description:"Required user interface components for apps integrating with the Nimbus SDK.",source:"@site/docs/platform-guides/android/mobile-ui.md",sourceDirName:"platform-guides/android",slug:"/platform-guides/android/mobile-ui",permalink:"/platform-guides/android/mobile-ui",draft:!1,editUrl:"https://github.com/mozilla/experimenter-docs/edit/main/docs/platform-guides/android/mobile-ui.md",tags:[],version:"current",frontMatter:{id:"getting-started-mobile-required-ui",title:"Required UI",slug:"/platform-guides/android/mobile-ui"},sidebar:"sidebar",previous:{title:"Microsurveys",permalink:"/platform-guides/android/microsurveys"},next:{title:"Custom Targeting",permalink:"/platform-guides/android/custom-targeting"}},s={},p=[{value:"User Interface Requirements",id:"user-interface-requirements",level:2},{value:"Opt-Out/Opt-In Controls",id:"opt-outopt-in-controls",level:2},{value:"Resetting Telemetry Identifiers",id:"resetting-telemetry-identifiers",level:2},{value:"QA Tooling",id:"qa-tooling",level:2},{value:"Preview Collection",id:"preview-collection",level:3},{value:"Manual Opt-In of Experiments",id:"manual-opt-in-of-experiments",level:3}],u={toc:p},c="wrapper";function m({components:e,...t}){return(0,i.kt)(c,(0,r.Z)({},u,t,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Required user interface components for apps integrating with the Nimbus SDK."),(0,i.kt)("h2",{id:"user-interface-requirements"},"User Interface Requirements"),(0,i.kt)("p",null,"Currently Nimbus provides no user-interface components of its own, though provides API to connect to existing settings screens."),(0,i.kt)("h2",{id:"opt-outopt-in-controls"},"Opt-Out/Opt-In Controls"),(0,i.kt)("p",null,"The settings page should include a ",(0,i.kt)("inlineCode",{parentName:"p"},"Studies")," toggle, which allows users to opt-in or opt-out of experiments. The example from Firefox for iOS is shown:"),(0,i.kt)("img",{src:"/img/firefox-ios/studies-toggle.png",width:"300px"}),(0,i.kt)("p",null,"Experiment participation and rollout participation are controlled separately:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-kotlin"},"// Controls opt-in/out for experiments (not rollouts)\nnimbus.experimentParticipation = flag\n\n// Controls opt-in/out for rollouts (not experiments)\nnimbus.rolloutParticipation = flag\n")),(0,i.kt)("p",null,"When set to ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),", the user will be opted out of all active enrollments of that type and will not be enrolled in new ones. Toggling the ",(0,i.kt)("inlineCode",{parentName:"p"},"Studies")," flag should set ",(0,i.kt)("inlineCode",{parentName:"p"},"experimentParticipation"),"."),(0,i.kt)("h2",{id:"resetting-telemetry-identifiers"},"Resetting Telemetry Identifiers"),(0,i.kt)("p",null,"During experiment enrollment, telemetry is generated
1which can connect the user to the experiment enrollment."),(0,i.kt)("p",null,"When the user opts-in or opts-out of telemetry collection, the toggle should call:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-kotlin"},"nimbus.resetTelemetryIdentifiers()\n")),(0,i.kt)("p",null,"This disqualifies existing enrollments. and breaks any connection with experiment enrollment and the enrollment telemetry."),(0,i.kt)("h2",{id:"qa-tooling"},"QA Tooling"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"The following are nice-to-haves, obviated by the use of the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/mozilla/application-services/tree/main/components/support/nimbus-cli"},(0,i.kt)("inlineCode",{parentName:"a"},"nimbus-cli")),".")),(0,i.kt)("h3",{id:"preview-collection"},"Preview Collection"),(0,i.kt)("p",null,"To allow testing of experiments before they are published, the client should allow configuring the Nimbus startup to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"preview-collection"),"."),(0,i.kt)("img",{src:"/img/fenix/preview-collection.png",width:"300px"}),(0,i.kt)("p",null,"The above shows a non-user visible settings screen in Fenix. The toggle sets a ",(0,i.kt)("inlineCode",{parentName:"p"},"Defaults"),"/",(0,i.kt)("inlineCode",{parentName:"p"},"SharedPreferences")," flag which is ",(0,i.kt)("a",{parentName:"p",href:"/platform-guides/android/integration#using-the-experiments-preview-collection"},"read at startup to configure ",(0,i.kt)("inlineCode",{parentName:"a"},"Nimbus")," startup"),"."),(0,i.kt)("p",null,"The preview collection is loaded on the next restart, and available to the app on the restart after that."),(0,i.kt)("h3",{id:"manual-opt-in-of-experiments"},"Manual Opt-In of Experiments"),(0,i.kt)("p",null,"To allow the manual opt-in of a particular branch, the app must provide a screen to list all available experiments:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-kotlin"},"val experiments: List<AvailableExperiment> = nimbus.getAvailableExperiments()\n")),(0,i.kt)("img",{src:"/img/fenix/experiments-screen.png",width:"300px"}),(0,i.kt)("img",{src:"/img/fenix/experiments-screen-branches.png",width:"300px"}),(0,i.kt)("p",null,"To get the list of branches from an available experiment; you can get the branch slug that the client is enrolled in with ",(0,i.kt)("inlineCode",{parentName:"p"},"getExperimentBranch"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-kotlin"},"val branches = experiment.branches\nval branchSlugs: List<String> = branches.map { it.slug }\nval enrolledBranchSlug = nimbus.getExperimentBranch(experiment.slug)\n")),(0,i.kt)("p",null,"You can opt-in and out of a given experiment."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-kotlin"},"// opt in to a particular branch\nval newBranchSlug = branchSlugs.get(0)\nif (enrolledBranchSlug != newBranchSlug) {\n nimbus.optIn(experiment.slug, newBranchSlug)\n} else {\n nimbus.optOut(experiment.slug)\n}\n")))}m.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.