3333// that rely on synchronous behavior, while excluding feature flags that require asynchronous decisions.
3434
3535public class OptimizelyUserContextAndroid extends OptimizelyUserContext {
36+
37+ /**
38+ * Creates an Android user context with basic parameters.
39+ *
40+ * @param optimizely The Optimizely client instance
41+ * @param userId Unique identifier for the user
42+ * @param attributes Map of user attributes for targeting and segmentation
43+ */
3644 public OptimizelyUserContextAndroid (@ NonNull Optimizely optimizely ,
3745 @ NonNull String userId ,
3846 @ NonNull Map <String , ?> attributes ) {
3947 super (optimizely , userId , attributes );
4048 }
4149
50+ /**
51+ * Creates an Android user context with forced decisions and qualified segments.
52+ *
53+ * @param optimizely The Optimizely client instance
54+ * @param userId Unique identifier for the user
55+ * @param attributes Map of user attributes for targeting and segmentation
56+ * @param forcedDecisionsMap Map of forced decisions to override normal flag evaluation
57+ * @param qualifiedSegments List of audience segments the user qualifies for
58+ */
4259 public OptimizelyUserContextAndroid (@ NonNull Optimizely optimizely ,
4360 @ NonNull String userId ,
4461 @ NonNull Map <String , ?> attributes ,
@@ -47,6 +64,17 @@ public OptimizelyUserContextAndroid(@NonNull Optimizely optimizely,
4764 super (optimizely , userId , attributes , forcedDecisionsMap , qualifiedSegments );
4865 }
4966
67+ /**
68+ * Creates an Android user context with all available parameters including analytics control.
69+ *
70+ * @param optimizely The Optimizely client instance
71+ * @param userId Unique identifier for the user
72+ * @param attributes Map of user attributes for targeting and segmentation
73+ * @param forcedDecisionsMap Map of forced decisions to override normal flag evaluation
74+ * @param qualifiedSegments List of audience segments the user qualifies for
75+ * @param shouldIdentifyUser Whether to send user identification events for analytics
76+ */
77+
5078 public OptimizelyUserContextAndroid (@ NonNull Optimizely optimizely ,
5179 @ NonNull String userId ,
5280 @ NonNull Map <String , ?> attributes ,
@@ -59,7 +87,7 @@ public OptimizelyUserContextAndroid(@NonNull Optimizely optimizely,
5987 /**
6088 * Returns a decision result ({@link OptimizelyDecision}) for a given flag key and a user context, which contains all data required to deliver the flag.
6189 * <ul>
62- * <li>If the SDK finds an error, it’ ll return a decision with <b>null</b> for <b>variationKey</b>. The decision will include an error message in <b>reasons</b>.
90+ * <li>If the SDK finds an error, it' ll return a decision with <b>null</b> for <b>variationKey</b>. The decision will include an error message in <b>reasons</b>.
6391 * </ul>
6492 * <p>
6593 * Note: This API is specifically designed for synchronous decision-making only.
@@ -72,7 +100,7 @@ public OptimizelyUserContextAndroid(@NonNull Optimizely optimizely,
72100 @ Override
73101 public OptimizelyDecision decide (@ NonNull String key ,
74102 @ NonNull List <OptimizelyDecideOption > options ) {
75- return decideSync (key , options );
103+ return coreDecideSync (key , options );
76104 }
77105
78106 /**
@@ -87,7 +115,7 @@ public OptimizelyDecision decide(@NonNull String key,
87115 */
88116 @ Override
89117 public OptimizelyDecision decide (@ NonNull String key ) {
90- return decide (key , Collections .emptyList ());
118+ return coreDecideSync (key , Collections .emptyList ());
91119 }
92120
93121 /**
@@ -107,7 +135,7 @@ public OptimizelyDecision decide(@NonNull String key) {
107135 @ Override
108136 public Map <String , OptimizelyDecision > decideForKeys (@ NonNull List <String > keys ,
109137 @ NonNull List <OptimizelyDecideOption > options ) {
110- return decideForKeysSync (keys , options );
138+ return coreDecideForKeysSync (keys , options );
111139 }
112140
113141 /**
@@ -122,7 +150,7 @@ public Map<String, OptimizelyDecision> decideForKeys(@NonNull List<String> keys,
122150 */
123151 @ Override
124152 public Map <String , OptimizelyDecision > decideForKeys (@ NonNull List <String > keys ) {
125- return decideForKeys (keys , Collections .emptyList ());
153+ return coreDecideForKeysSync (keys , Collections .emptyList ());
126154 }
127155
128156 /**
@@ -137,7 +165,7 @@ public Map<String, OptimizelyDecision> decideForKeys(@NonNull List<String> keys)
137165 */
138166 @ Override
139167 public Map <String , OptimizelyDecision > decideAll (@ NonNull List <OptimizelyDecideOption > options ) {
140- return decideAllSync (options );
168+ return coreDecideAllSync (options );
141169 }
142170
143171 /**
@@ -151,7 +179,7 @@ public Map<String, OptimizelyDecision> decideAll(@NonNull List<OptimizelyDecideO
151179 */
152180 @ Override
153181 public Map <String , OptimizelyDecision > decideAll () {
154- return decideAll (Collections .emptyList ());
182+ return coreDecideAllSync (Collections .emptyList ());
155183 }
156184
157185 // ===========================================
@@ -168,7 +196,7 @@ public Map<String, OptimizelyDecision> decideAll() {
168196 public void decideAsync (@ NonNull String key ,
169197 @ NonNull List <OptimizelyDecideOption > options ,
170198 @ NonNull OptimizelyDecisionCallback callback ) {
171- super . decideAsync (key , options , callback );
199+ coreDecideAsync (key , options , callback );
172200 }
173201
174202 /**
@@ -178,7 +206,7 @@ public void decideAsync(@NonNull String key,
178206 * @param callback A callback to invoke when the decision is available.
179207 */
180208 public void decideAsync (@ NonNull String key , @ NonNull OptimizelyDecisionCallback callback ) {
181- decideAsync (key , Collections .emptyList (), callback );
209+ coreDecideAsync (key , Collections .emptyList (), callback );
182210 }
183211
184212 /**
@@ -191,7 +219,7 @@ public void decideAsync(@NonNull String key, @NonNull OptimizelyDecisionCallback
191219 public void decideForKeysAsync (@ NonNull List <String > keys ,
192220 @ NonNull List <OptimizelyDecideOption > options ,
193221 @ NonNull OptimizelyDecisionsCallback callback ) {
194- super . decideForKeysAsync (keys , options , callback );
222+ coreDecideForKeysAsync (keys , options , callback );
195223 }
196224
197225 /**
@@ -201,7 +229,7 @@ public void decideForKeysAsync(@NonNull List<String> keys,
201229 * @param callback A callback to invoke when decisions are available.
202230 */
203231 public void decideForKeysAsync (@ NonNull List <String > keys , @ NonNull OptimizelyDecisionsCallback callback ) {
204- decideForKeysAsync (keys , Collections .emptyList (), callback );
232+ coreDecideForKeysAsync (keys , Collections .emptyList (), callback );
205233 }
206234
207235 /**
@@ -212,7 +240,7 @@ public void decideForKeysAsync(@NonNull List<String> keys, @NonNull OptimizelyDe
212240 */
213241 public void decideAllAsync (@ NonNull List <OptimizelyDecideOption > options ,
214242 @ NonNull OptimizelyDecisionsCallback callback ) {
215- super . decideAllAsync (options , callback );
243+ coreDecideAllAsync (options , callback );
216244 }
217245
218246 /**
@@ -221,16 +249,26 @@ public void decideAllAsync(@NonNull List<OptimizelyDecideOption> options,
221249 * @param callback A callback to invoke when decisions are available.
222250 */
223251 public void decideAllAsync (@ NonNull OptimizelyDecisionsCallback callback ) {
224- decideAllAsync (Collections .emptyList (), callback );
252+ coreDecideAllAsync (Collections .emptyList (), callback );
225253 }
226254
227255 // ===========================================
228256 // Async Methods (Android-specific) with blocking calls to synchronous methods
229257 // ===========================================
230258
231- public OptimizelyDecision decideAsync (@ Nonnull String key ,
232- @ Nonnull List <OptimizelyDecideOption > options ) {
233- return super .decide (key , options );
259+ /**
260+ * Returns a decision result ({@link OptimizelyDecision}) for a given flag key and a user context, which contains all data required to deliver the flag.
261+ * <p>
262+ * Note: Despite the "Async" name, this method performs blocking synchronous decision-making.
263+ * For true asynchronous decision-making with callbacks, use the callback-based decideAsync() methods.
264+ * </p>
265+ * @param key A flag key for which a decision will be made.
266+ * @param options A list of options for decision-making.
267+ * @return A decision result.
268+ */
269+ public OptimizelyDecision decideAsync (@ NonNull String key ,
270+ @ NonNull List <OptimizelyDecideOption > options ) {
271+ return coreDecide (key , options );
234272 }
235273
236274 /**
@@ -239,8 +277,8 @@ public OptimizelyDecision decideAsync(@Nonnull String key,
239277 * @param key A flag key for which a decision will be made.
240278 * @return A decision result.
241279 */
242- public OptimizelyDecision decideAsync (@ Nonnull String key ) {
243- return decideAsync (key , Collections .emptyList ());
280+ public OptimizelyDecision decideAsync (@ NonNull String key ) {
281+ return coreDecide (key , Collections .emptyList ());
244282 }
245283
246284 /**
@@ -253,9 +291,9 @@ public OptimizelyDecision decideAsync(@Nonnull String key) {
253291 * @param options A list of options for decision-making.
254292 * @return All decision results mapped by flag keys.
255293 */
256- public Map <String , OptimizelyDecision > decideForKeysAsync (@ Nonnull List <String > keys ,
257- @ Nonnull List <OptimizelyDecideOption > options ) {
258- return super . decideForKeys (keys , options );
294+ public Map <String , OptimizelyDecision > decideForKeysAsync (@ NonNull List <String > keys ,
295+ @ NonNull List <OptimizelyDecideOption > options ) {
296+ return coreDecideForKeys (keys , options );
259297 }
260298
261299 /**
@@ -264,8 +302,8 @@ public Map<String, OptimizelyDecision> decideForKeysAsync(@Nonnull List<String>
264302 * @param keys A list of flag keys for which decisions will be made.
265303 * @return All decision results mapped by flag keys.
266304 */
267- public Map <String , OptimizelyDecision > decideForKeysAsync (@ Nonnull List <String > keys ) {
268- return decideForKeysAsync (keys , Collections .emptyList ());
305+ public Map <String , OptimizelyDecision > decideForKeysAsync (@ NonNull List <String > keys ) {
306+ return coreDecideForKeys (keys , Collections .emptyList ());
269307 }
270308
271309 /**
@@ -274,8 +312,8 @@ public Map<String, OptimizelyDecision> decideForKeysAsync(@Nonnull List<String>
274312 * @param options A list of options for decision-making.
275313 * @return All decision results mapped by flag keys.
276314 */
277- public Map <String , OptimizelyDecision > decideAllAsync (@ Nonnull List <OptimizelyDecideOption > options ) {
278- return super . decideAll (options );
315+ public Map <String , OptimizelyDecision > decideAllAsync (@ NonNull List <OptimizelyDecideOption > options ) {
316+ return coreDecideAll (options );
279317 }
280318
281319 /**
@@ -284,25 +322,56 @@ public Map<String, OptimizelyDecision> decideAllAsync(@Nonnull List<OptimizelyDe
284322 * @return A dictionary of all decision results, mapped by flag keys.
285323 */
286324 public Map <String , OptimizelyDecision > decideAllAsync () {
287- return decideAllAsync (Collections .emptyList ());
325+ return coreDecideAll (Collections .emptyList ());
288326 }
289327
290328 // ===========================================
291- // Override methods for testability
292- // These methods enable Mockito spies to intercept calls that would
293- // otherwise go directly to super.method() and be unverifiable
329+ // Core Methods - All super calls centralized here for testability
294330 // ===========================================
295331
296- public OptimizelyDecision decideSync (@ NonNull String key , @ NonNull List <OptimizelyDecideOption > options ) {
332+ /**
333+ * Core delegation methods that encapsulate all parent class method calls.
334+ * These protected methods can be overridden in test subclasses to mock parent behavior
335+ * without affecting production code or requiring complex dependency injection.
336+ *
337+ * Pattern: Each public API method delegates to its corresponding core method,
338+ * which then calls the appropriate super method from OptimizelyUserContext.
339+ */
340+
341+ OptimizelyDecision coreDecideSync (@ NonNull String key , @ NonNull List <OptimizelyDecideOption > options ) {
297342 return super .decideSync (key , options );
298343 }
299344
300- public Map <String , OptimizelyDecision > decideForKeysSync (@ NonNull List <String > keys , @ NonNull List <OptimizelyDecideOption > options ) {
345+ Map <String , OptimizelyDecision > coreDecideForKeysSync (@ NonNull List <String > keys , @ NonNull List <OptimizelyDecideOption > options ) {
301346 return super .decideForKeysSync (keys , options );
302347 }
303348
304- public Map <String , OptimizelyDecision > decideAllSync (@ NonNull List <OptimizelyDecideOption > options ) {
349+ Map <String , OptimizelyDecision > coreDecideAllSync (@ NonNull List <OptimizelyDecideOption > options ) {
305350 return super .decideAllSync (options );
306351 }
307352
353+ void coreDecideAsync (@ NonNull String key , @ NonNull List <OptimizelyDecideOption > options , @ NonNull OptimizelyDecisionCallback callback ) {
354+ super .decideAsync (key , options , callback );
355+ }
356+
357+ void coreDecideForKeysAsync (@ NonNull List <String > keys , @ NonNull List <OptimizelyDecideOption > options , @ NonNull OptimizelyDecisionsCallback callback ) {
358+ super .decideForKeysAsync (keys , options , callback );
359+ }
360+
361+ void coreDecideAllAsync (@ NonNull List <OptimizelyDecideOption > options , @ NonNull OptimizelyDecisionsCallback callback ) {
362+ super .decideAllAsync (options , callback );
363+ }
364+
365+ OptimizelyDecision coreDecide (@ NonNull String key , @ NonNull List <OptimizelyDecideOption > options ) {
366+ return super .decide (key , options );
367+ }
368+
369+ Map <String , OptimizelyDecision > coreDecideForKeys (@ NonNull List <String > keys , @ NonNull List <OptimizelyDecideOption > options ) {
370+ return super .decideForKeys (keys , options );
371+ }
372+
373+ Map <String , OptimizelyDecision > coreDecideAll (@ NonNull List <OptimizelyDecideOption > options ) {
374+ return super .decideAll (options );
375+ }
376+
308377}
0 commit comments