46
46
import com .optimizely .ab .event .internal .payload .Event ;
47
47
import com .optimizely .ab .android .user_experiment_record .AndroidUserExperimentRecord ;
48
48
49
+ import org .json .JSONObject ;
49
50
import org .slf4j .Logger ;
50
51
import org .slf4j .LoggerFactory ;
51
52
@@ -117,6 +118,91 @@ void setOptimizelyStartListener(@Nullable OptimizelyStartListener optimizelyStar
117
118
this .optimizelyStartListener = optimizelyStartListener ;
118
119
}
119
120
121
+ /**
122
+ * Initialize Optimizely Synchronously
123
+ * <p>
124
+ * Instantiates and returns an {@link OptimizelyClient} instance. Will also cache the instance
125
+ * for future lookups via getClient
126
+ * @param context any {@link Context} instance
127
+ * @param datafile the datafile
128
+ * @return an {@link OptimizelyClient} instance
129
+ */
130
+ public OptimizelyClient initialize (@ NonNull Context context , @ NonNull String datafile ) {
131
+ if (!isAndroidVersionSupported ()) {
132
+ return optimizelyClient ;
133
+ }
134
+
135
+ AndroidUserExperimentRecord userExperimentRecord =
136
+ (AndroidUserExperimentRecord ) AndroidUserExperimentRecord .newInstance (getProjectId (), context );
137
+ // The User Experiment Record is started on the main thread on an asynchronous start.
138
+ // Starting simply creates the file if it doesn't exist so it's not
139
+ // terribly expensive. Blocking the UI thread prevents touch input...
140
+ userExperimentRecord .start ();
141
+ try {
142
+ optimizelyClient = buildOptimizely (context , datafile , userExperimentRecord );
143
+ } catch (ConfigParseException e ) {
144
+ logger .error ("Unable to parse compiled data file" , e );
145
+ }
146
+
147
+
148
+ // After instantiating the OptimizelyClient, we will begin the datafile sync so that next time
149
+ // the user can instantiate with the latest datafile
150
+ final Intent intent = new Intent (context .getApplicationContext (), DataFileService .class );
151
+ if (dataFileServiceConnection == null ) {
152
+ this .dataFileServiceConnection = new DataFileServiceConnection (this );
153
+ context .getApplicationContext ().bindService (intent , dataFileServiceConnection , Context .BIND_AUTO_CREATE );
154
+ }
155
+
156
+ return optimizelyClient ;
157
+ }
158
+
159
+ /**
160
+ * Initialize Optimizely Synchronously
161
+ * <p>
162
+ * Instantiates and returns an {@link OptimizelyClient} instance. Will also cache the instance
163
+ * for future lookups via getClient. The datafile should be stored in res/raw.
164
+ *
165
+ * @param context any {@link Context} instance
166
+ * @param dataFileRes the R id that the data file is located under.
167
+ * @return an {@link OptimizelyClient} instance
168
+ */
169
+ @ NonNull
170
+ public OptimizelyClient initialize (@ NonNull Context context , @ RawRes int dataFileRes ) {
171
+ try {
172
+ String datafile = loadRawResource (context , dataFileRes );
173
+ return initialize (context , datafile );
174
+ } catch (IOException e ) {
175
+ logger .error ("Unable to load compiled data file" , e );
176
+ }
177
+
178
+ // return dummy client if not able to initialize a valid one
179
+ return optimizelyClient ;
180
+ }
181
+
182
+ /**
183
+ * Initialize Optimizely Synchronously
184
+ * <p>
185
+ * Instantiates and returns an {@link OptimizelyClient} instance using the datafile cached on disk
186
+ * if not available then it will return a dummy instance.
187
+ * @param context any {@link Context} instance
188
+ * @return an {@link OptimizelyClient} instance
189
+ */
190
+ public OptimizelyClient initialize (@ NonNull Context context ) {
191
+ DataFileCache dataFileCache = new DataFileCache (
192
+ projectId ,
193
+ new Cache (context , LoggerFactory .getLogger (Cache .class )),
194
+ LoggerFactory .getLogger (DataFileCache .class )
195
+ );
196
+
197
+ JSONObject datafile = dataFileCache .load ();
198
+ if (datafile != null ) {
199
+ return initialize (context , datafile .toString ());
200
+ }
201
+
202
+ // return dummy client if not able to initialize a valid one
203
+ return optimizelyClient ;
204
+ }
205
+
120
206
/**
121
207
* Starts Optimizely asynchronously
122
208
* <p>
@@ -130,30 +216,32 @@ void setOptimizelyStartListener(@Nullable OptimizelyStartListener optimizelyStar
130
216
* @param optimizelyStartListener callback that {@link OptimizelyClient} instances are sent to.
131
217
*/
132
218
@ TargetApi (Build .VERSION_CODES .ICE_CREAM_SANDWICH )
133
- public void start (@ NonNull Activity activity , @ NonNull OptimizelyStartListener optimizelyStartListener ) {
219
+ public void initialize (@ NonNull Activity activity , @ NonNull OptimizelyStartListener optimizelyStartListener ) {
134
220
if (!isAndroidVersionSupported ()) {
135
221
return ;
136
222
}
137
223
activity .getApplication ().registerActivityLifecycleCallbacks (new OptlyActivityLifecycleCallbacks (this ));
138
- start (activity .getApplication (), optimizelyStartListener );
224
+ initialize (activity .getApplicationContext (), optimizelyStartListener );
139
225
}
140
226
141
227
/**
142
228
* @param context any type of context instance
143
229
* @param optimizelyStartListener callback that {@link OptimizelyClient} instances are sent to.
144
- * @see #start (Activity, OptimizelyStartListener)
230
+ * @see #initialize (Activity, OptimizelyStartListener)
145
231
* <p>
146
232
* This method does the same thing except it can be used with a generic {@link Context}.
147
233
* When using this method be sure to call {@link #stop(Context)} to unbind {@link DataFileService}.
148
234
*/
149
- public void start (@ NonNull Context context , @ NonNull OptimizelyStartListener optimizelyStartListener ) {
235
+ public void initialize (@ NonNull Context context , @ NonNull OptimizelyStartListener optimizelyStartListener ) {
150
236
if (!isAndroidVersionSupported ()) {
151
237
return ;
152
238
}
153
239
this .optimizelyStartListener = optimizelyStartListener ;
154
- this .dataFileServiceConnection = new DataFileServiceConnection (this );
155
240
final Intent intent = new Intent (context .getApplicationContext (), DataFileService .class );
156
- context .getApplicationContext ().bindService (intent , dataFileServiceConnection , Context .BIND_AUTO_CREATE );
241
+ if (dataFileServiceConnection == null ) {
242
+ this .dataFileServiceConnection = new DataFileServiceConnection (this );
243
+ context .getApplicationContext ().bindService (intent , dataFileServiceConnection , Context .BIND_AUTO_CREATE );
244
+ }
157
245
}
158
246
159
247
@ TargetApi (Build .VERSION_CODES .ICE_CREAM_SANDWICH )
@@ -165,7 +253,7 @@ void stop(@NonNull Activity activity, @NonNull OptlyActivityLifecycleCallbacks o
165
253
/**
166
254
* Unbinds {@link DataFileService}
167
255
* <p>
168
- * Calling this is not necessary if using {@link #start (Activity, OptimizelyStartListener)} which
256
+ * Calling this is not necessary if using {@link #initialize (Activity, OptimizelyStartListener)} which
169
257
* handles unbinding implicitly.
170
258
*
171
259
* @param context any {@link Context} instance
@@ -185,12 +273,11 @@ public void stop(@NonNull Context context) {
185
273
/**
186
274
* Gets a cached Optimizely instance
187
275
* <p>
188
- * If {@link #start (Activity, OptimizelyStartListener)} or {@link #start (Context, OptimizelyStartListener)}
276
+ * If {@link #initialize (Activity, OptimizelyStartListener)} or {@link #initialize (Context, OptimizelyStartListener)}
189
277
* has not been called yet the returned {@link OptimizelyClient} instance will be a dummy instance
190
278
* that logs warnings in order to prevent {@link NullPointerException}.
191
279
* <p>
192
- * If {@link #getOptimizely(Context, int)} was used the built {@link OptimizelyClient} instance
193
- * will be updated. Using {@link #start(Activity, OptimizelyStartListener)} or {@link #start(Context, OptimizelyStartListener)}
280
+ * Using {@link #initialize(Activity, OptimizelyStartListener)} or {@link #initialize(Context, OptimizelyStartListener)}
194
281
* will update the cached instance with a new {@link OptimizelyClient} built from a cached local
195
282
* datafile on disk or a remote datafile on the CDN.
196
283
*
@@ -202,41 +289,6 @@ public OptimizelyClient getOptimizely() {
202
289
return optimizelyClient ;
203
290
}
204
291
205
- /**
206
- * Create an instance of {@link OptimizelyClient} from a compiled in datafile
207
- * <p>
208
- * After using this method successfully {@link #getOptimizely()} will contain a
209
- * cached instance built from the compiled in datafile. The datafile should be
210
- * stored in res/raw.
211
- *
212
- * @param context any {@link Context} instance
213
- * @param dataFileRes the R id that the data file is located under.
214
- * @return an {@link OptimizelyClient} instance
215
- */
216
- @ NonNull
217
- public OptimizelyClient getOptimizely (@ NonNull Context context , @ RawRes int dataFileRes ) {
218
- if (!isAndroidVersionSupported ()) {
219
- return optimizelyClient ;
220
- }
221
-
222
- AndroidUserExperimentRecord userExperimentRecord =
223
- (AndroidUserExperimentRecord ) AndroidUserExperimentRecord .newInstance (getProjectId (), context );
224
- // Blocking File I/O is necessary here in order to provide a synchronous API
225
- // The User Experiment Record is started off the of the main thread when starting
226
- // asynchronously. Starting simply creates the file if it doesn't exist so it's not
227
- // terribly expensive. Blocking the UI the thread prevents touch input...
228
- userExperimentRecord .start ();
229
- try {
230
- optimizelyClient = buildOptimizely (context , loadRawResource (context , dataFileRes ), userExperimentRecord );
231
- } catch (ConfigParseException e ) {
232
- logger .error ("Unable to parse compiled data file" , e );
233
- } catch (IOException e ) {
234
- logger .error ("Unable to load compiled data file" , e );
235
- }
236
-
237
- return optimizelyClient ;
238
- }
239
-
240
292
private String loadRawResource (Context context , @ RawRes int rawRes ) throws IOException {
241
293
Resources res = context .getResources ();
242
294
InputStream in = res .openRawResource (rawRes );
@@ -249,6 +301,21 @@ private String loadRawResource(Context context, @RawRes int rawRes) throws IOExc
249
301
}
250
302
}
251
303
304
+ /**
305
+ * Check if the datafile is cached on the disk
306
+ * @param context any {@link Context} instance
307
+ * @return True if the datafile is cached on the disk
308
+ */
309
+ public boolean isDatafileCached (Context context ) {
310
+ DataFileCache dataFileCache = new DataFileCache (
311
+ projectId ,
312
+ new Cache (context , LoggerFactory .getLogger (Cache .class )),
313
+ LoggerFactory .getLogger (DataFileCache .class )
314
+ );
315
+
316
+ return dataFileCache .exists ();
317
+ }
318
+
252
319
@ NonNull
253
320
String getProjectId () {
254
321
return projectId ;
0 commit comments