Skip to content

Commit 826f8c5

Browse files
committed
clean up android user context
1 parent 6a87840 commit 826f8c5

File tree

2 files changed

+156
-180
lines changed

2 files changed

+156
-180
lines changed

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyUserContextAndroid.java

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,29 @@
3333
// that rely on synchronous behavior, while excluding feature flags that require asynchronous decisions.
3434

3535
public 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, itll 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

Comments
 (0)