Skip to content

Commit 790e1de

Browse files
thomaszurkan-optimizelytwzurkanjaeopt
authored
fix: convert jobscheduler to work manager (#360)
* checkin replacement of intents with work manager * disable some tests * ready for review * cleanup and prepare for merge * Update datafile-handler/build.gradle Co-authored-by: Jae Kim <[email protected]> * Update datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DefaultDatafileHandler.java Co-authored-by: Jae Kim <[email protected]> * Update datafile-handler/src/main/java/com/optimizely/ab/android/datafile_handler/DefaultDatafileHandler.java Co-authored-by: Jae Kim <[email protected]> * update from comments * fix typo from auto-merge Co-authored-by: Tom Zurkan <[email protected]> Co-authored-by: Jae Kim <[email protected]>
1 parent 760fdaa commit 790e1de

File tree

31 files changed

+471
-281
lines changed

31 files changed

+471
-281
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2016, Optimizely, Inc. and contributors *
2+
* Copyright 2016-2021, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -16,13 +16,14 @@
1616

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

19-
import java.util.HashMap;
20-
import java.util.Map;
2119
import android.content.Context;
2220
import android.content.pm.PackageInfo;
2321

2422
import org.slf4j.Logger;
2523

24+
import java.util.HashMap;
25+
import java.util.Map;
26+
2627
/**
2728
* Class to encapsulate default attributes that will be added to attributes passed in
2829
* by the OptimizelyClient.
@@ -45,15 +46,15 @@ public class OptimizelyDefaultAttributes {
4546
static Map<String, String> buildDefaultAttributesMap(Context context, Logger logger) {
4647
String androidDeviceModel = android.os.Build.MODEL;
4748
String androidOSVersion = android.os.Build.VERSION.RELEASE;
48-
int androidSdkVersion = 0;
49+
String androidSdkVersion = "";
4950
String androidSdkVersionName = "";
5051
String androidAppVersionName = "";
5152
int androidAppVersion = 0;
5253

5354
// In case there is some problem with accessing the BuildConfig file....
5455
try {
55-
androidSdkVersion = BuildConfig.VERSION_CODE;
56-
androidSdkVersionName = BuildConfig.VERSION_NAME;
56+
androidSdkVersion = BuildConfig.CLIENT_VERSION;
57+
androidSdkVersionName = BuildConfig.LIBRARY_PACKAGE_NAME;
5758
}
5859
catch (Exception e) {
5960
logger.warn("Error getting BuildConfig version code and version name");

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ buildscript {
3535
google()
3636
}
3737
dependencies {
38-
classpath 'com.android.tools.build:gradle:4.0.1'
38+
classpath 'com.android.tools.build:gradle:4.1.2'
3939
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
4040

4141
// NOTE: Do not place your application dependencies here; they belong
@@ -71,6 +71,7 @@ ext {
7171
gson_ver = "2.8.6"
7272
group_id = "com.optimizely.ab"
7373
androidx_test = "1.1.1"
74+
work_runtime = "2.5.0"
7475
}
7576

7677
task clean(type: Delete) {

datafile-handler/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ android {
5656
dependencies {
5757
api project(':shared')
5858
implementation "androidx.annotation:annotation:$annotations_ver"
59+
implementation "androidx.work:work-runtime:$work_runtime"
5960

6061
compileOnly "com.noveogroup.android:android-logger:$android_logger_ver"
6162

@@ -131,4 +132,3 @@ android.libraryVariants.all { variant ->
131132
project.artifacts.add("archives", tasks["${variant.name}SourcesJar"]);
132133
}
133134

134-

datafile-handler/src/androidTest/java/com/optimizely/ab/android/datafile_handler/DatafileLoaderTest.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
@RunWith(AndroidJUnit4.class)
6262
public class DatafileLoaderTest {
6363

64-
private DatafileService datafileService;
6564
private DatafileCache datafileCache;
6665
private DatafileClient datafileClient;
6766
private Client client;
@@ -71,15 +70,12 @@ public class DatafileLoaderTest {
7170

7271
@Before
7372
public void setup() {
74-
datafileService = mock(DatafileService.class);
7573
logger = mock(Logger.class);
7674
final Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
7775
datafileCache = new DatafileCache("1", new Cache(targetContext, logger), logger);
7876
client = mock(Client.class);
7977
datafileClient = new DatafileClient(client, logger);
8078
datafileLoadedListener = mock(DatafileLoadedListener.class);
81-
when(datafileService.getApplicationContext()).thenReturn(targetContext);
82-
when(datafileService.isBound()).thenReturn(true);
8379
}
8480

8581
@After
@@ -91,7 +87,7 @@ public void tearDown() {
9187
public void loadFromCDNWhenNoCachedFile() throws MalformedURLException, JSONException {
9288
final ExecutorService executor = Executors.newSingleThreadExecutor();
9389
DatafileLoader datafileLoader =
94-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
90+
new DatafileLoader(context, datafileClient, datafileCache, logger);
9591

9692
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("{}");
9793

@@ -112,7 +108,7 @@ public void loadFromCDNWhenNoCachedFile() throws MalformedURLException, JSONExce
112108
public void loadWhenCacheFileExistsAndCDNNotModified() {
113109
final ExecutorService executor = Executors.newSingleThreadExecutor();
114110
DatafileLoader datafileLoader =
115-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
111+
new DatafileLoader(context, datafileClient, datafileCache, logger);
116112
datafileCache.save("{}");
117113

118114
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("");
@@ -134,7 +130,7 @@ public void loadWhenCacheFileExistsAndCDNNotModified() {
134130
public void noCacheAndLoadFromCDNFails() {
135131
final ExecutorService executor = Executors.newSingleThreadExecutor();
136132
DatafileLoader datafileLoader =
137-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
133+
new DatafileLoader(context, datafileClient, datafileCache, logger);
138134

139135
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn(null);
140136

@@ -156,7 +152,7 @@ public void warningsAreLogged() throws IOException {
156152
Cache cache = mock(Cache.class);
157153
datafileCache = new DatafileCache("warningsAreLogged", cache, logger);
158154
DatafileLoader datafileLoader =
159-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
155+
new DatafileLoader(context, datafileClient, datafileCache, logger);
160156

161157
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("{}");
162158
when(cache.exists(datafileCache.getFileName())).thenReturn(true);
@@ -181,17 +177,22 @@ public void debugLogged() throws IOException {
181177
Cache cache = mock(Cache.class);
182178
datafileCache = new DatafileCache("debugLogged", cache, logger);
183179
DatafileLoader datafileLoader =
184-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
180+
new DatafileLoader(context, datafileClient, datafileCache, logger);
185181

186182
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("{}");
187183
when(cache.save(datafileCache.getFileName(), "{}")).thenReturn(true);
188184
when(cache.exists(datafileCache.getFileName())).thenReturn(true);
189185
when(cache.load(datafileCache.getFileName())).thenReturn("{}");
190186

191187
datafileLoader.getDatafile("debugLogged", datafileLoadedListener);
188+
try {
189+
Thread.sleep(100);
190+
} catch (InterruptedException e) {
191+
e.printStackTrace();
192+
}
192193
datafileLoader.getDatafile("debugLogged", datafileLoadedListener);
193194
try {
194-
executor.awaitTermination(5, TimeUnit.SECONDS);
195+
executor.awaitTermination(1, TimeUnit.SECONDS);
195196
} catch (InterruptedException e) {
196197
fail();
197198
}
@@ -207,7 +208,7 @@ public void downloadAllowedNoCache() throws IOException {
207208
Cache cache = mock(Cache.class);
208209
datafileCache = new DatafileCache("downloadAllowedNoCache", cache, logger);
209210
DatafileLoader datafileLoader =
210-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
211+
new DatafileLoader(context, datafileClient, datafileCache, logger);
211212

212213
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("{}");
213214
when(cache.save(datafileCache.getFileName(), "{}")).thenReturn(false);
@@ -233,7 +234,7 @@ public void debugLoggedMultiThreaded() throws IOException {
233234
Cache cache = mock(Cache.class);
234235
datafileCache = new DatafileCache("debugLoggedMultiThreaded", cache, logger);
235236
DatafileLoader datafileLoader =
236-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
237+
new DatafileLoader(context, datafileClient, datafileCache, logger);
237238

238239
when(client.execute(any(Client.Request.class), anyInt(), anyInt())).thenReturn("{}");
239240
when(cache.exists(datafileCache.getFileName())).thenReturn(true);
@@ -257,8 +258,7 @@ public void debugLoggedMultiThreaded() throws IOException {
257258
fail();
258259
}
259260

260-
verify(logger, atLeast(1)).debug("Last download happened under 1 minute ago. Throttled to be at least 1 minute apart.");
261-
verify(datafileLoadedListener, atMost(4)).onDatafileLoaded("{}");
261+
verify(datafileLoadedListener, atMost(5)).onDatafileLoaded("{}");
262262
verify(datafileLoadedListener, atLeast(1)).onDatafileLoaded("{}");
263263
}
264264

@@ -289,7 +289,7 @@ public void allowDoubleDownload() throws IOException {
289289
Cache cache = mock(Cache.class);
290290
datafileCache = new DatafileCache("allowDoubleDownload", cache, logger);
291291
DatafileLoader datafileLoader =
292-
new DatafileLoader(datafileService, datafileClient, datafileCache, executor, logger);
292+
new DatafileLoader(context, datafileClient, datafileCache, logger);
293293

294294
// set download time to 1 second
295295
setTestDownloadFrequency(datafileLoader, 1000L);

datafile-handler/src/androidTest/java/com/optimizely/ab/android/datafile_handler/DatafileReschedulerTest.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.content.Context;
2121
import android.content.Intent;
2222
import android.os.Build;
23+
2324
import androidx.test.platform.app.InstrumentationRegistry;
2425

2526
import com.optimizely.ab.android.shared.Cache;
@@ -34,7 +35,6 @@
3435
import org.slf4j.Logger;
3536

3637
import static junit.framework.Assert.assertEquals;
37-
import static junit.framework.Assert.assertNull;
3838
import static org.mockito.Matchers.any;
3939
import static org.mockito.Mockito.mock;
4040
import static org.mockito.Mockito.times;
@@ -99,8 +99,7 @@ public void dispatchingOneWithoutEnvironment() {
9999
backgroundWatchersCache.setIsWatching(new DatafileConfig("1", null), true);
100100
Logger logger = mock(Logger.class);
101101
DatafileRescheduler.Dispatcher dispatcher = new DatafileRescheduler.Dispatcher(mockContext, backgroundWatchersCache, logger);
102-
Intent intent = new Intent(mockContext, DatafileService.class);
103-
dispatcher.dispatch(intent);
102+
dispatcher.dispatch();
104103
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
105104
verify(mockContext).startService(captor.capture());
106105
assertEquals(new DatafileConfig("1", null).toJSONString(), captor.getValue().getStringExtra(DatafileService.EXTRA_DATAFILE_CONFIG));
@@ -116,8 +115,7 @@ public void dispatchingOneWithEnvironment() {
116115
backgroundWatchersCache.setIsWatching(new DatafileConfig("1", "2"), true);
117116
Logger logger = mock(Logger.class);
118117
DatafileRescheduler.Dispatcher dispatcher = new DatafileRescheduler.Dispatcher(mockContext, backgroundWatchersCache, logger);
119-
Intent intent = new Intent(mockContext, DatafileService.class);
120-
dispatcher.dispatch(intent);
118+
dispatcher.dispatch();
121119
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
122120
verify(mockContext).startService(captor.capture());
123121
assertEquals(new DatafileConfig("1", "2").toJSONString(), captor.getValue().getStringExtra(DatafileService.EXTRA_DATAFILE_CONFIG));
@@ -135,8 +133,7 @@ public void dispatchingManyWithoutEnvironment() {
135133
backgroundWatchersCache.setIsWatching(new DatafileConfig("3", null), true);
136134
Logger logger = mock(Logger.class);
137135
DatafileRescheduler.Dispatcher dispatcher = new DatafileRescheduler.Dispatcher(mockContext, backgroundWatchersCache, logger);
138-
Intent intent = new Intent(mockContext, DatafileService.class);
139-
dispatcher.dispatch(intent);
136+
dispatcher.dispatch();
140137
verify(mockContext, times(3)).startService(any(Intent.class));
141138
cache.delete(BackgroundWatchersCache.BACKGROUND_WATCHERS_FILE_NAME);
142139
}
@@ -151,8 +148,7 @@ public void dispatchingManyWithEnvironment() {
151148
backgroundWatchersCache.setIsWatching(new DatafileConfig("3", "1"), true);
152149
Logger logger = mock(Logger.class);
153150
DatafileRescheduler.Dispatcher dispatcher = new DatafileRescheduler.Dispatcher(mockContext, backgroundWatchersCache, logger);
154-
Intent intent = new Intent(mockContext, DatafileService.class);
155-
dispatcher.dispatch(intent);
151+
dispatcher.dispatch();
156152
verify(mockContext, times(3)).startService(any(Intent.class));
157153
cache.delete(BackgroundWatchersCache.BACKGROUND_WATCHERS_FILE_NAME);
158154
}

datafile-handler/src/androidTest/java/com/optimizely/ab/android/datafile_handler/DatafileServiceTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
*/
5858
// TODO These tests will pass individually but they fail when run as group
5959
// Known bug https://code.google.com/p/android/issues/detail?id=180396
60+
@Ignore
6061
public class DatafileServiceTest {
6162

6263
private ExecutorService executor;
@@ -72,6 +73,7 @@ public void setup() {
7273

7374
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
7475
@Test
76+
@Ignore
7577
public void testBinding() throws TimeoutException {
7678
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
7779
Intent intent = new Intent(context, DatafileService.class);
@@ -91,8 +93,7 @@ public void testBinding() throws TimeoutException {
9193

9294

9395
DatafileService datafileService = ((DatafileService.LocalBinder) binder).getService();
94-
DatafileLoader datafileLoader = new DatafileLoader(datafileService, datafileClient, datafileCache,
95-
Executors.newSingleThreadExecutor(), mock(Logger.class));
96+
DatafileLoader datafileLoader = new DatafileLoader(targetContext, datafileClient, datafileCache, mock(Logger.class));
9697
datafileService.getDatafile("1", datafileLoader, datafileLoadedListener);
9798

9899
assertTrue(datafileService.isBound());
@@ -120,6 +121,7 @@ public void testValidStart() throws TimeoutException {
120121

121122
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
122123
@Test
124+
@Ignore
123125
public void testNullIntentStart() throws TimeoutException {
124126
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
125127
Intent intent = new Intent(context, DatafileService.class);
@@ -139,6 +141,7 @@ public void testNullIntentStart() throws TimeoutException {
139141

140142
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
141143
@Test
144+
@Ignore
142145
public void testNoProjectIdIntentStart() throws TimeoutException {
143146
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
144147
Intent intent = new Intent(context, DatafileService.class);
@@ -158,6 +161,7 @@ public void testNoProjectIdIntentStart() throws TimeoutException {
158161

159162
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
160163
@Test
164+
@Ignore
161165
public void testUnbind() throws TimeoutException {
162166
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
163167
Intent intent = new Intent(context, DatafileService.class);

datafile-handler/src/main/AndroidManifest.xml

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,14 @@
2222

2323
<uses-permission android:name="android.permission.INTERNET"/>
2424
<application>
25-
<service
26-
android:name=".DatafileService"
25+
<receiver
26+
android:name="DatafileRescheduler"
2727
android:enabled="true"
2828
android:exported="false">
29-
</service>
30-
<!--
31-
Add these lines to your manifest if you want the services to schedule themselves again after a boot
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.
34-
35-
<receiver
36-
android:name="DatafileRescheduler"
37-
android:enabled="true"
38-
android:exported="false">
39-
<intent-filter>
40-
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
41-
<action android:name="android.intent.action.BOOT_COMPLETED" />
42-
</intent-filter>
43-
</receiver>
44-
-->
29+
<intent-filter>
30+
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
31+
<action android:name="android.intent.action.BOOT_COMPLETED" />
32+
</intent-filter>
33+
</receiver>
4534
</application>
4635
</manifest>

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
* Makes requests to the Optly CDN to get the datafile
3131
*/
3232
public class DatafileClient {
33+
// easy way to set the connection timeout
34+
public static int CONNECTION_TIMEOUT = 5 * 1000;
3335
// the numerical base for the exponential backoff
3436
public static final int REQUEST_BACKOFF_TIMEOUT = 2;
3537
// power the number of retries
@@ -78,7 +80,7 @@ public String execute() {
7880

7981
client.setIfModifiedSince(urlConnection);
8082

81-
urlConnection.setConnectTimeout(5 * 1000);
83+
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
8284
urlConnection.connect();
8385

8486
int status = urlConnection.getResponseCode();
@@ -108,6 +110,6 @@ public String execute() {
108110
}
109111
};
110112

111-
return client.execute(request, 2, 3);
113+
return client.execute(request, REQUEST_BACKOFF_TIMEOUT, REQUEST_RETRIES_POWER);
112114
}
113115
}

0 commit comments

Comments
 (0)