Skip to content

Commit 186c0c8

Browse files
close some url connections and streams. add connectivity change to te… (#133)
* close some url connections and streams. add connectivity change to test-app manifest. add a few more exception handlers. * changed reschedulers to wake on wifi state change : connecting * fixup docs and cleanup * cleanup from mike's comments * update changelog
1 parent e4f2802 commit 186c0c8

File tree

20 files changed

+272
-60
lines changed

20 files changed

+272
-60
lines changed

CHANGELOG.md

+23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
11
# Optimizely Android X SDK Changelog
2+
### 1.4.0-alpha-RC1
3+
July 26, 2017
4+
5+
- Release candidate for 1.4.0
6+
7+
*Bug Fixes*
8+
9+
- Better javadocs.
10+
- Cleanup any resource leaks.
11+
- Better exception handling to avoid any crashes.
12+
- Fix proguard rules
13+
- Fix logger issue
14+
- Allow EventRescheduler to work with wifi change intent filter (you don't have to include that intent filter).
15+
16+
*Breaking Changes*
17+
18+
- Must include intent filter for EventRescheduler and DatafileRescheduler in the application manifest if the developer wants to use them (see the test-app manifest for an example).
19+
- Pass context into OptimizelyManager.Builder.
20+
- UserProfileService added.
21+
- Background processes are not running by default.
22+
- Various handlers (EventHandler, DatafileHandler, ErrorHandler) can be overridden.
23+
24+
225
### 1.4.0-alpha
326
July 11, 2017
427

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class OptimizelyClient {
4747
private final Logger logger;
4848

4949
@Nullable private Optimizely optimizely;
50-
@Nullable private Map<String, String> defaultAttributes;
50+
@NonNull private Map<String, String> defaultAttributes;
5151

5252
OptimizelyClient(@Nullable Optimizely optimizely, @NonNull Logger logger) {
5353
this.optimizely = optimizely;
@@ -86,7 +86,7 @@ protected void setDefaultAttributes(@NonNull Map<String, String> attrs) {
8686
* @return a new map of both the default attributes and attributes passed in.
8787
*/
8888
private Map<String, String> getAllAttributes(@NonNull Map<String, String> attrs) {
89-
Map<String,String> combinedMap = new HashMap<String,String>(defaultAttributes);
89+
Map<String,String> combinedMap = new HashMap<>(defaultAttributes);
9090

9191
// this essentially overrides defaultAttributes if the attrs passed in have the same key.
9292
combinedMap.putAll(attrs);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static Map<String, String> buildDefaultAttributesMap(Context context, Logger log
7070
}
7171

7272

73-
Map<String, String> attrMap = new HashMap<String, String>();
73+
Map<String, String> attrMap = new HashMap<>();
7474

7575
attrMap.put(DEVICE_MODEL_KEY, androidDeviceModel);
7676
attrMap.put(SDK_VERSION_KEY, androidSdkVersionName);

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ public class OptimizelyManager {
5858
LoggerFactory.getLogger(OptimizelyClient.class));
5959

6060
@NonNull private DatafileHandler datafileHandler;
61-
@NonNull private final long datafileDownloadInterval;
62-
@NonNull private final long eventDispatchInterval;
61+
private final long datafileDownloadInterval;
62+
private final long eventDispatchInterval;
6363
@Nullable private EventHandler eventHandler = null;
6464
@NonNull private ErrorHandler errorHandler;
6565
@NonNull private Logger logger;
@@ -323,6 +323,7 @@ public String getProjectId() {
323323
return projectId;
324324
}
325325

326+
@NonNull
326327
public DatafileHandler getDatafileHandler() {
327328
return datafileHandler;
328329
}
@@ -390,6 +391,7 @@ private OptimizelyClient buildOptimizely(@NonNull Context context, @NonNull Stri
390391
return new OptimizelyClient(optimizely, LoggerFactory.getLogger(OptimizelyClient.class));
391392
}
392393

394+
@NonNull
393395
@VisibleForTesting
394396
public UserProfileService getUserProfileService() {
395397
return userProfileService;

datafile-handler/src/main/AndroidManifest.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
</service>
3030
<!--
3131
Add these lines to your manifest if you want the services to schedule themselves again after a boot
32-
or package replace.
32+
or package replace. Without these lines in your application manifest, the DatafileRescheduler will not be used.
33+
See {link test_app} AndroidManifest.xml as an example.
3334
3435
<receiver
3536
android:name="DatafileRescheduler"

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/BackgroundWatchersCache.java

+40
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.optimizely.ab.android.datafile_handler;
1818

19+
import android.content.Context;
1920
import android.support.annotation.NonNull;
2021
import android.support.annotation.Nullable;
2122

@@ -31,17 +32,33 @@
3132

3233
/**
3334
* Caches a json dict that saves state about which project IDs have background watching enabled.
35+
* This is used by the rescheduler to determine if backgrounding was on for a project id. If backgrounding is on,
36+
* then when the device is restarted or the app is reinstalled, the rescheduler will kick in and reschedule the datafile background
37+
* download. In order to use this the rescheduler needs to be included in the application manifest.
38+
* Calling {@link DatafileHandler#stopBackgroundUpdates(Context, String)} sets this background cache to false.
3439
*/
3540
class BackgroundWatchersCache {
3641
static final String BACKGROUND_WATCHERS_FILE_NAME = "optly-background-watchers.json";
3742
@NonNull private final Cache cache;
3843
@NonNull private final Logger logger;
3944

45+
/**
46+
* Create BackgroundWatchersCache Object.
47+
*
48+
* @param cache object for caching project id and whether watched or not.
49+
* @param logger the logger to log errors and warnings.
50+
*/
4051
BackgroundWatchersCache(@NonNull Cache cache, @NonNull Logger logger) {
4152
this.cache = cache;
4253
this.logger = logger;
4354
}
4455

56+
/**
57+
* Set the watching flag for the proejct id.
58+
* @param projectId project id to set watching.
59+
* @param watching flag to signify if the project is running in the background.
60+
* @return boolean indicating whether the set succeed or not
61+
*/
4562
boolean setIsWatching(@NonNull String projectId, boolean watching) {
4663
if (projectId.isEmpty()) {
4764
logger.error("Passed in an empty string for projectId");
@@ -61,6 +78,11 @@ boolean setIsWatching(@NonNull String projectId, boolean watching) {
6178
return false;
6279
}
6380

81+
/**
82+
* Return if the project is set to be watched in the background or not.
83+
* @param projectId project id to test
84+
* @return true if it has backgrounding, false if not.
85+
*/
6486
boolean isWatching(@NonNull String projectId) {
6587
if (projectId.isEmpty()) {
6688
logger.error("Passed in an empty string for projectId");
@@ -81,6 +103,10 @@ boolean isWatching(@NonNull String projectId) {
81103
return false;
82104
}
83105

106+
/**
107+
* Get a list of all project ids that are being watched for backgrounding.
108+
* @return a list of project ids
109+
*/
84110
List<String> getWatchingProjectIds() {
85111
List<String> projectIds = new ArrayList<>();
86112
try {
@@ -101,6 +127,11 @@ List<String> getWatchingProjectIds() {
101127
return projectIds;
102128
}
103129

130+
/**
131+
* Load the JSONObject from cache
132+
* @return JSONObject if successful. JSONObject can be empty
133+
* @throws JSONException if there was a problem parsing the JSON
134+
*/
104135
@Nullable
105136
private JSONObject load() throws JSONException {
106137
String backGroundWatchersFile = cache.load(BACKGROUND_WATCHERS_FILE_NAME);
@@ -112,10 +143,19 @@ private JSONObject load() throws JSONException {
112143
return new JSONObject(backGroundWatchersFile);
113144
}
114145

146+
/**
147+
* Delete the background watchers cache file.
148+
* @return true if successful and false if it failed.
149+
*/
115150
protected boolean delete() {
116151
return cache.delete(BACKGROUND_WATCHERS_FILE_NAME);
117152
}
118153

154+
/**
155+
* Save the JSON string to the background cache file.
156+
* @param backgroundWatchersJson JSON string containing projectid and whether watched or not.
157+
* @return true if successful.
158+
*/
119159
private boolean save(String backgroundWatchersJson) {
120160
logger.info("Saving background watchers file {}.", BACKGROUND_WATCHERS_FILE_NAME);
121161
boolean saved = cache.save(BACKGROUND_WATCHERS_FILE_NAME, backgroundWatchersJson);

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DatafileCache.java

+28-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.slf4j.Logger;
2828

2929
/**
30-
* Abstracts the actual data "file" {@link java.io.File}.
30+
* Abstracts the actual data "file" {@link java.io.File}. to a cached file
3131
*/
3232
public class DatafileCache {
3333

@@ -37,25 +37,47 @@ public class DatafileCache {
3737
@NonNull private final String filename;
3838
@NonNull private final Logger logger;
3939

40+
/**
41+
* Create a DatafileCache Object
42+
* @param projectId project id for cache
43+
* @param cache shared generic file based {link Cache}
44+
* @param logger logger to use
45+
*/
4046
public DatafileCache(@NonNull String projectId, @NonNull Cache cache, @NonNull Logger logger) {
4147
this.cache = cache;
4248
this.filename = String.format(FILENAME, projectId);
4349
this.logger = logger;
4450
}
4551

52+
/**
53+
* Delete the datafile cache
54+
* @return true if successful
55+
*/
4656
public boolean delete() {
4757
return cache.delete(filename);
4858
}
4959

60+
/**
61+
* Check to see if the datafile cache exists
62+
* @return true if it exists
63+
*/
5064
public boolean exists() {
5165
return cache.exists(filename);
5266
}
5367

68+
/**
69+
* Return the filename to the datafile cache
70+
* @return filename for datafile cache
71+
*/
5472
@VisibleForTesting
5573
public String getFileName() {
5674
return filename;
5775
}
5876

77+
/**
78+
* Loads the datafile from cache into a JSONObject
79+
* @return JSONObject if exists or nulll if it doesn't or there was a problem
80+
*/
5981
@Nullable
6082
public JSONObject load() {
6183
String datafile = cache.load(filename);
@@ -71,6 +93,11 @@ public JSONObject load() {
7193
}
7294
}
7395

96+
/**
97+
* Save a datafile to cache.
98+
* @param dataFile to write to cache
99+
* @return true if successful.
100+
*/
74101
public boolean save(String dataFile) {
75102
return cache.save(filename, dataFile);
76103
}

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DatafileClient.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public class DatafileClient {
3535
@NonNull private final Client client;
3636
@NonNull private final Logger logger;
3737

38+
/**
39+
* Create a DatafileClient Object.
40+
* @param client Shared {@link Client} object
41+
* @param logger logger for logging.
42+
*/
3843
public DatafileClient(@NonNull Client client, @NonNull Logger logger) {
3944
this.client = client;
4045
this.logger = logger;
@@ -89,7 +94,12 @@ public String execute() {
8994
return null;
9095
} finally {
9196
if (urlConnection != null) {
92-
urlConnection.disconnect();
97+
try {
98+
urlConnection.disconnect();
99+
}
100+
catch (Exception e) {
101+
logger.error("Error closing connection", e);
102+
}
93103
}
94104
}
95105
}

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DatafileRescheduler.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,22 @@
3131
/**
3232
* Broadcast Receiver that handles app upgrade and phone restart broadcasts in order
3333
* to reschedule {@link DatafileService}
34+
* In order to use this class you must include the declaration in your AndroidManifest.xml.
35+
* <pre>
36+
* {@code
37+
* <receiver
38+
* android:name="DatafileRescheduler"
39+
* android:enabled="true"
40+
* android:exported="false">
41+
* <intent-filter>
42+
* <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
43+
* <action android:name="android.intent.action.BOOT_COMPLETED" />
44+
* </intent-filter>
45+
* </receiver>
46+
* }
47+
* </pre>
3448
*
35-
* @hide
49+
* as well as set the download interval for datafile download in the Optimizely builder.
3650
*/
3751
public class DatafileRescheduler extends BroadcastReceiver {
3852
Logger logger = LoggerFactory.getLogger(DatafileRescheduler.class);

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DatafileService.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535

3636
/**
3737
* Service that handles loading the datafile from cache or downloads it from the CDN
38-
*
39-
* @hide
38+
* These services will only be used if you are using our {@link DefaultDatafileHandler}.
39+
* You can chose to implement your own handler and use all or part of this package.
4040
*/
4141
public class DatafileService extends Service {
4242
/**

datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DatafileServiceConnection.java

+21-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
import java.util.concurrent.Executors;
3434

35+
/**
36+
* The DatafileServiceConnection is used to bind to a DatafileService. The DatafileService does that actual download.
37+
* The Service Connection kicks off the service after being connected. The connection is unbound after a successful download.
38+
*/
3539
public class DatafileServiceConnection implements ServiceConnection {
3640

3741
@NonNull private final Context context;
@@ -40,14 +44,21 @@ public class DatafileServiceConnection implements ServiceConnection {
4044

4145
private boolean bound = false;
4246

47+
/**
48+
* Create a datafile service connection object.
49+
* @param projectId project id for service
50+
* @param context current application context.
51+
* @param listener listener to call after service download has completed.
52+
*/
4353
public DatafileServiceConnection(@NonNull String projectId, @NonNull Context context, @NonNull DatafileLoadedListener listener) {
4454
this.projectId = projectId;
4555
this.context = context;
4656
this.listener = listener;
4757
}
4858

4959
/**
50-
* @hide
60+
* Get the bound {@link DatafileService} and set it up for download.
61+
*
5162
* @see ServiceConnection#onServiceConnected(ComponentName, IBinder)
5263
*/
5364
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
@@ -84,7 +95,7 @@ public void onServiceConnected(ComponentName className,
8495
}
8596

8697
/**
87-
* @hide
98+
* Call stop on the listener after the service has been disconnected.
8899
* @see ServiceConnection#onServiceDisconnected(ComponentName)
89100
*/
90101
@Override
@@ -93,10 +104,18 @@ public void onServiceDisconnected(ComponentName arg0) {
93104
listener.onStop(context);
94105
}
95106

107+
/**
108+
* Is the service bound?
109+
* @return true if it is bound.
110+
*/
96111
public boolean isBound() {
97112
return bound;
98113
}
99114

115+
/**
116+
* Set whether the service is bound or not.
117+
* @param bound boolean flag.
118+
*/
100119
public void setBound(Boolean bound) {
101120
this.bound = bound;
102121
}

0 commit comments

Comments
 (0)