@ammarahmed/react-native-background-fetch 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarnignore +7 -0
- package/LICENSE +21 -0
- package/README.md +502 -0
- package/RNBackgroundFetch.podspec +25 -0
- package/android/build.gradle +40 -0
- package/android/proguard-rules.pro +2 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/com/transistorsoft/rnbackgroundfetch/HeadlessTask.java +119 -0
- package/android/src/main/java/com/transistorsoft/rnbackgroundfetch/RNBackgroundFetchModule.java +185 -0
- package/android/src/main/java/com/transistorsoft/rnbackgroundfetch/RNBackgroundFetchPackage.java +29 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BGTask.java +305 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BackgroundFetch.java +297 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BackgroundFetchConfig.java +362 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/BootReceiver.java +24 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/FetchAlarmReceiver.java +40 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/FetchJobService.java +106 -0
- package/android/src/main/java/com/transistorsoft/tsbackgroundfetch/LifecycleManager.java +225 -0
- package/app.plugin.js +1 -0
- package/index.d.ts +185 -0
- package/index.js +119 -0
- package/ios/RNBackgroundFetch/RNBackgroundFetch+AppDelegate.m +22 -0
- package/ios/RNBackgroundFetch/RNBackgroundFetch.h +18 -0
- package/ios/RNBackgroundFetch/RNBackgroundFetch.m +167 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/Info.plist +57 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_armv7/TSBackgroundFetch.framework/Headers/TSBackgroundFetch.h +47 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_armv7/TSBackgroundFetch.framework/Info.plist +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_armv7/TSBackgroundFetch.framework/Modules/module.modulemap +6 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_armv7/TSBackgroundFetch.framework/TSBackgroundFetch +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/Headers/TSBackgroundFetch.h +47 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/Info.plist +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/Modules/module.modulemap +6 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/TSBackgroundFetch +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/_CodeSignature/CodeDirectory +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/_CodeSignature/CodeRequirements +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/_CodeSignature/CodeResources +132 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_i386_x86_64-simulator/TSBackgroundFetch.framework/_CodeSignature/CodeSignature +0 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_x86_64-maccatalyst/TSBackgroundFetch.framework/Headers/TSBackgroundFetch.h +47 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_x86_64-maccatalyst/TSBackgroundFetch.framework/Modules/module.modulemap +6 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_x86_64-maccatalyst/TSBackgroundFetch.framework/Resources/Info.plist +52 -0
- package/ios/RNBackgroundFetch/TSBackgroundFetch.xcframework/ios-arm64_x86_64-maccatalyst/TSBackgroundFetch.framework/TSBackgroundFetch +0 -0
- package/ios/RNBackgroundFetch.xcodeproj/project.pbxproj +310 -0
- package/ios/RNBackgroundFetch.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/RNBackgroundFetch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/RNBackgroundFetch.xcodeproj/project.xcworkspace/xcuserdata/chris.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/package.json +32 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
package com.transistorsoft.tsbackgroundfetch;
|
|
2
|
+
|
|
3
|
+
import android.annotation.TargetApi;
|
|
4
|
+
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.os.Build;
|
|
7
|
+
import android.os.Handler;
|
|
8
|
+
import android.os.Looper;
|
|
9
|
+
|
|
10
|
+
import android.util.Log;
|
|
11
|
+
|
|
12
|
+
import java.util.HashMap;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
import java.util.Map;
|
|
15
|
+
import java.util.concurrent.ExecutorService;
|
|
16
|
+
import java.util.concurrent.Executors;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Created by chris on 2018-01-11.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
public class BackgroundFetch {
|
|
23
|
+
public static final String TAG = "TSBackgroundFetch";
|
|
24
|
+
|
|
25
|
+
public static final String ACTION_CONFIGURE = "configure";
|
|
26
|
+
public static final String ACTION_START = "start";
|
|
27
|
+
public static final String ACTION_STOP = "stop";
|
|
28
|
+
public static final String ACTION_FINISH = "finish";
|
|
29
|
+
public static final String ACTION_STATUS = "status";
|
|
30
|
+
public static final String ACTION_FORCE_RELOAD = TAG + "-forceReload";
|
|
31
|
+
|
|
32
|
+
public static final String EVENT_FETCH = ".event.BACKGROUND_FETCH";
|
|
33
|
+
|
|
34
|
+
public static final int STATUS_AVAILABLE = 2;
|
|
35
|
+
|
|
36
|
+
private static BackgroundFetch mInstance = null;
|
|
37
|
+
|
|
38
|
+
private static ExecutorService sThreadPool;
|
|
39
|
+
|
|
40
|
+
private static Handler uiHandler;
|
|
41
|
+
|
|
42
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
43
|
+
public static Handler getUiHandler() {
|
|
44
|
+
if (uiHandler == null) {
|
|
45
|
+
uiHandler = new Handler(Looper.getMainLooper());
|
|
46
|
+
}
|
|
47
|
+
return uiHandler;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
51
|
+
public static ExecutorService getThreadPool() {
|
|
52
|
+
if (sThreadPool == null) {
|
|
53
|
+
sThreadPool = Executors.newCachedThreadPool();
|
|
54
|
+
}
|
|
55
|
+
return sThreadPool;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
59
|
+
public static BackgroundFetch getInstance(Context context) {
|
|
60
|
+
if (mInstance == null) {
|
|
61
|
+
mInstance = getInstanceSynchronized(context.getApplicationContext());
|
|
62
|
+
}
|
|
63
|
+
return mInstance;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private static synchronized BackgroundFetch getInstanceSynchronized(Context context) {
|
|
67
|
+
if (mInstance == null) mInstance = new BackgroundFetch(context.getApplicationContext());
|
|
68
|
+
return mInstance;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private Context mContext;
|
|
72
|
+
private BackgroundFetch.Callback mFetchCallback;
|
|
73
|
+
|
|
74
|
+
private final Map<String, BackgroundFetchConfig> mConfig = new HashMap<>();
|
|
75
|
+
|
|
76
|
+
private BackgroundFetch(Context context) {
|
|
77
|
+
mContext = context;
|
|
78
|
+
// Start Lifecycle Observer to be notified when app enters background.
|
|
79
|
+
getUiHandler().post(LifecycleManager.getInstance());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@SuppressWarnings({"unused"})
|
|
83
|
+
public void configure(BackgroundFetchConfig config, BackgroundFetch.Callback callback) {
|
|
84
|
+
Log.d(TAG, "- " + ACTION_CONFIGURE);
|
|
85
|
+
mFetchCallback = callback;
|
|
86
|
+
|
|
87
|
+
synchronized (mConfig) {
|
|
88
|
+
if (mConfig.containsKey(config.getTaskId())) {
|
|
89
|
+
// Developer called `.configure` again. Re-configure the plugin by re-scheduling the fetch task.
|
|
90
|
+
BackgroundFetchConfig existing = mConfig.get(config.getTaskId());
|
|
91
|
+
Log.d(TAG, "Re-configured existing task");
|
|
92
|
+
BGTask.reschedule(mContext, existing, config);
|
|
93
|
+
mConfig.put(config.getTaskId(), config);
|
|
94
|
+
return;
|
|
95
|
+
} else {
|
|
96
|
+
mConfig.put(config.getTaskId(), config);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
start(config.getTaskId());
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void onBoot() {
|
|
103
|
+
BackgroundFetchConfig.load(mContext, new BackgroundFetchConfig.OnLoadCallback() {
|
|
104
|
+
@Override public void onLoad(List<BackgroundFetchConfig> result) {
|
|
105
|
+
for (BackgroundFetchConfig config : result) {
|
|
106
|
+
if (!config.getStartOnBoot() || config.getStopOnTerminate()) {
|
|
107
|
+
config.destroy(mContext);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
synchronized (mConfig) {
|
|
111
|
+
mConfig.put(config.getTaskId(), config);
|
|
112
|
+
}
|
|
113
|
+
if ((android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) || config.getForceAlarmManager()) {
|
|
114
|
+
if (config.isFetchTask()) {
|
|
115
|
+
start(config.getTaskId());
|
|
116
|
+
} else {
|
|
117
|
+
scheduleTask(config);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
126
|
+
@TargetApi(21)
|
|
127
|
+
public void start(String fetchTaskId) {
|
|
128
|
+
Log.d(TAG, "- " + ACTION_START);
|
|
129
|
+
|
|
130
|
+
BGTask task = BGTask.getTask(fetchTaskId);
|
|
131
|
+
if (task != null) {
|
|
132
|
+
Log.e(TAG, "[" + TAG + " start] Task " + fetchTaskId + " already registered");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
registerTask(fetchTaskId);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
139
|
+
public void stop(String taskId) {
|
|
140
|
+
String msg = "- " + ACTION_STOP;
|
|
141
|
+
if (taskId != null) {
|
|
142
|
+
msg += ": " + taskId;
|
|
143
|
+
}
|
|
144
|
+
Log.d(TAG, msg);
|
|
145
|
+
|
|
146
|
+
if (taskId == null) {
|
|
147
|
+
synchronized (mConfig) {
|
|
148
|
+
for (BackgroundFetchConfig config : mConfig.values()) {
|
|
149
|
+
BGTask task = BGTask.getTask(config.getTaskId());
|
|
150
|
+
if (task != null) {
|
|
151
|
+
task.finish();
|
|
152
|
+
BGTask.removeTask(config.getTaskId());
|
|
153
|
+
}
|
|
154
|
+
BGTask.cancel(mContext, config.getTaskId(), config.getJobId());
|
|
155
|
+
config.destroy(mContext);
|
|
156
|
+
}
|
|
157
|
+
BGTask.clear();
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
BGTask task = BGTask.getTask(taskId);
|
|
161
|
+
if (task != null) {
|
|
162
|
+
task.finish();
|
|
163
|
+
BGTask.removeTask(task.getTaskId());
|
|
164
|
+
}
|
|
165
|
+
BackgroundFetchConfig config = getConfig(taskId);
|
|
166
|
+
if (config != null) {
|
|
167
|
+
config.destroy(mContext);
|
|
168
|
+
BGTask.cancel(mContext, config.getTaskId(), config.getJobId());
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
174
|
+
public void scheduleTask(BackgroundFetchConfig config) {
|
|
175
|
+
synchronized (mConfig) {
|
|
176
|
+
if (mConfig.containsKey(config.getTaskId())) {
|
|
177
|
+
// This BackgroundFetchConfig already exists? Should we halt any existing Job/Alarm here?
|
|
178
|
+
}
|
|
179
|
+
config.save(mContext);
|
|
180
|
+
mConfig.put(config.getTaskId(), config);
|
|
181
|
+
}
|
|
182
|
+
String taskId = config.getTaskId();
|
|
183
|
+
registerTask(taskId);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@SuppressWarnings({"WeakerAccess"})
|
|
187
|
+
public void finish(String taskId) {
|
|
188
|
+
Log.d(TAG, "- " + ACTION_FINISH + ": " + taskId);
|
|
189
|
+
|
|
190
|
+
BGTask task = BGTask.getTask(taskId);
|
|
191
|
+
if (task != null) {
|
|
192
|
+
task.finish();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
BackgroundFetchConfig config = getConfig(taskId);
|
|
196
|
+
|
|
197
|
+
if ((config != null) && !config.getPeriodic()) {
|
|
198
|
+
config.destroy(mContext);
|
|
199
|
+
synchronized (mConfig) {
|
|
200
|
+
mConfig.remove(taskId);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public int status() {
|
|
206
|
+
return STATUS_AVAILABLE;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
BackgroundFetch.Callback getFetchCallback() {
|
|
210
|
+
return mFetchCallback;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
void onFetch(final BGTask task) {
|
|
214
|
+
BGTask.addTask(task);
|
|
215
|
+
Log.d(TAG, "- Background Fetch event received: " + task.getTaskId());
|
|
216
|
+
synchronized (mConfig) {
|
|
217
|
+
if (mConfig.isEmpty()) {
|
|
218
|
+
BackgroundFetchConfig.load(mContext, new BackgroundFetchConfig.OnLoadCallback() {
|
|
219
|
+
@Override
|
|
220
|
+
public void onLoad(List<BackgroundFetchConfig> result) {
|
|
221
|
+
synchronized (mConfig) {
|
|
222
|
+
for (BackgroundFetchConfig config : result) {
|
|
223
|
+
mConfig.put(config.getTaskId(), config);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
doFetch(task);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
doFetch(task);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private void registerTask(String taskId) {
|
|
237
|
+
BackgroundFetchConfig config = getConfig(taskId);
|
|
238
|
+
|
|
239
|
+
if (config == null) {
|
|
240
|
+
Log.e(TAG, "- registerTask failed to find BackgroundFetchConfig for taskId " + taskId);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
config.save(mContext);
|
|
244
|
+
|
|
245
|
+
String msg = "- registerTask: " + taskId;
|
|
246
|
+
if (!config.getForceAlarmManager()) {
|
|
247
|
+
msg += " (jobId: " + config.getJobId() + ")";
|
|
248
|
+
}
|
|
249
|
+
Log.d(TAG, msg);
|
|
250
|
+
|
|
251
|
+
BGTask.schedule(mContext, config);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private void doFetch(BGTask task) {
|
|
255
|
+
BackgroundFetchConfig config = getConfig(task.getTaskId());
|
|
256
|
+
|
|
257
|
+
if (config == null) {
|
|
258
|
+
BGTask.cancel(mContext, task.getTaskId(), task.getJobId());
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!LifecycleManager.getInstance().isHeadless()) {
|
|
263
|
+
if (mFetchCallback != null) {
|
|
264
|
+
mFetchCallback.onFetch(task.getTaskId());
|
|
265
|
+
}
|
|
266
|
+
} else if (config.getStopOnTerminate()) {
|
|
267
|
+
Log.d(TAG, "- Stopping on terminate");
|
|
268
|
+
stop(task.getTaskId());
|
|
269
|
+
} else if (config.getJobService() != null) {
|
|
270
|
+
try {
|
|
271
|
+
task.fireHeadlessEvent(mContext, config);
|
|
272
|
+
} catch (BGTask.Error e) {
|
|
273
|
+
Log.e(TAG, "Headless task error: " + e.getMessage());
|
|
274
|
+
e.printStackTrace();
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
// {stopOnTerminate: false, forceReload: false} with no Headless JobService?? Don't know what else to do here but stop
|
|
278
|
+
Log.w(TAG, "- BackgroundFetch event has occurred while app is terminated but there's no jobService configured to handle the event. BackgroundFetch will terminate.");
|
|
279
|
+
finish(task.getTaskId());
|
|
280
|
+
stop(task.getTaskId());
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
BackgroundFetchConfig getConfig(String taskId) {
|
|
285
|
+
synchronized (mConfig) {
|
|
286
|
+
return (mConfig.containsKey(taskId)) ? mConfig.get(taskId) : null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @interface BackgroundFetch.Callback
|
|
292
|
+
*/
|
|
293
|
+
public interface Callback {
|
|
294
|
+
void onFetch(String taskId);
|
|
295
|
+
void onTimeout(String taskId);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
package com.transistorsoft.tsbackgroundfetch;
|
|
2
|
+
|
|
3
|
+
import android.app.job.JobInfo;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.SharedPreferences;
|
|
6
|
+
import android.os.Build;
|
|
7
|
+
import android.util.Log;
|
|
8
|
+
|
|
9
|
+
import org.json.JSONException;
|
|
10
|
+
import org.json.JSONObject;
|
|
11
|
+
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.HashSet;
|
|
14
|
+
import java.util.List;
|
|
15
|
+
import java.util.Set;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Created by chris on 2018-01-11.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
public class BackgroundFetchConfig {
|
|
22
|
+
private Builder config;
|
|
23
|
+
|
|
24
|
+
private static final int MINIMUM_FETCH_INTERVAL = 1;
|
|
25
|
+
private static final int DEFAULT_FETCH_INTERVAL = 15;
|
|
26
|
+
|
|
27
|
+
public static final String FIELD_TASK_ID = "taskId";
|
|
28
|
+
public static final String FIELD_MINIMUM_FETCH_INTERVAL = "minimumFetchInterval";
|
|
29
|
+
public static final String FIELD_START_ON_BOOT = "startOnBoot";
|
|
30
|
+
public static final String FIELD_REQUIRED_NETWORK_TYPE = "requiredNetworkType";
|
|
31
|
+
public static final String FIELD_REQUIRES_BATTERY_NOT_LOW = "requiresBatteryNotLow";
|
|
32
|
+
public static final String FIELD_REQUIRES_CHARGING = "requiresCharging";
|
|
33
|
+
public static final String FIELD_REQUIRES_DEVICE_IDLE = "requiresDeviceIdle";
|
|
34
|
+
public static final String FIELD_REQUIRES_STORAGE_NOT_LOW = "requiresStorageNotLow";
|
|
35
|
+
public static final String FIELD_STOP_ON_TERMINATE = "stopOnTerminate";
|
|
36
|
+
public static final String FIELD_JOB_SERVICE = "jobService";
|
|
37
|
+
public static final String FIELD_FORCE_ALARM_MANAGER = "forceAlarmManager";
|
|
38
|
+
public static final String FIELD_PERIODIC = "periodic";
|
|
39
|
+
public static final String FIELD_DELAY = "delay";
|
|
40
|
+
public static final String FIELD_IS_FETCH_TASK = "isFetchTask";
|
|
41
|
+
|
|
42
|
+
public static class Builder {
|
|
43
|
+
private String taskId;
|
|
44
|
+
private int minimumFetchInterval = DEFAULT_FETCH_INTERVAL;
|
|
45
|
+
private long delay = -1;
|
|
46
|
+
private boolean periodic = false;
|
|
47
|
+
private boolean forceAlarmManager = false;
|
|
48
|
+
private boolean stopOnTerminate = true;
|
|
49
|
+
private boolean startOnBoot = false;
|
|
50
|
+
private int requiredNetworkType = 0;
|
|
51
|
+
private boolean requiresBatteryNotLow = false;
|
|
52
|
+
private boolean requiresCharging = false;
|
|
53
|
+
private boolean requiresDeviceIdle = false;
|
|
54
|
+
private boolean requiresStorageNotLow = false;
|
|
55
|
+
private boolean isFetchTask = false;
|
|
56
|
+
|
|
57
|
+
private String jobService = null;
|
|
58
|
+
|
|
59
|
+
public Builder setTaskId(String taskId) {
|
|
60
|
+
this.taskId = taskId;
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public Builder setIsFetchTask(boolean value) {
|
|
65
|
+
this.isFetchTask = value;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public Builder setMinimumFetchInterval(int fetchInterval) {
|
|
70
|
+
if (fetchInterval >= MINIMUM_FETCH_INTERVAL) {
|
|
71
|
+
this.minimumFetchInterval = fetchInterval;
|
|
72
|
+
}
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public Builder setStopOnTerminate(boolean stopOnTerminate) {
|
|
77
|
+
this.stopOnTerminate = stopOnTerminate;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public Builder setStartOnBoot(boolean startOnBoot) {
|
|
82
|
+
this.startOnBoot = startOnBoot;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public Builder setRequiredNetworkType(int networkType) {
|
|
87
|
+
|
|
88
|
+
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
89
|
+
if (
|
|
90
|
+
(networkType != JobInfo.NETWORK_TYPE_ANY) &&
|
|
91
|
+
(networkType != JobInfo.NETWORK_TYPE_CELLULAR) &&
|
|
92
|
+
(networkType != JobInfo.NETWORK_TYPE_NONE) &&
|
|
93
|
+
(networkType != JobInfo.NETWORK_TYPE_NOT_ROAMING) &&
|
|
94
|
+
(networkType != JobInfo.NETWORK_TYPE_UNMETERED)
|
|
95
|
+
) {
|
|
96
|
+
Log.e(BackgroundFetch.TAG, "[ERROR] Invalid " + FIELD_REQUIRED_NETWORK_TYPE + ": " + networkType + "; Defaulting to NETWORK_TYPE_NONE");
|
|
97
|
+
networkType = JobInfo.NETWORK_TYPE_NONE;
|
|
98
|
+
}
|
|
99
|
+
this.requiredNetworkType = networkType;
|
|
100
|
+
}
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public Builder setRequiresBatteryNotLow(boolean value) {
|
|
105
|
+
this.requiresBatteryNotLow = value;
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public Builder setRequiresCharging(boolean value) {
|
|
110
|
+
this.requiresCharging = value;
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public Builder setRequiresDeviceIdle(boolean value) {
|
|
115
|
+
this.requiresDeviceIdle = value;
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public Builder setRequiresStorageNotLow(boolean value) {
|
|
120
|
+
this.requiresStorageNotLow = value;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public Builder setJobService(String className) {
|
|
125
|
+
this.jobService = className;
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public Builder setForceAlarmManager(boolean value) {
|
|
130
|
+
this.forceAlarmManager = value;
|
|
131
|
+
return this;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public Builder setPeriodic(boolean value) {
|
|
135
|
+
this.periodic = value;
|
|
136
|
+
return this;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public Builder setDelay(long value) {
|
|
140
|
+
this.delay = value;
|
|
141
|
+
return this;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public BackgroundFetchConfig build() {
|
|
145
|
+
return new BackgroundFetchConfig(this);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public BackgroundFetchConfig load(Context context, String taskId) {
|
|
149
|
+
SharedPreferences preferences = context.getSharedPreferences(BackgroundFetch.TAG + ":" + taskId, 0);
|
|
150
|
+
if (preferences.contains(FIELD_TASK_ID)) {
|
|
151
|
+
setTaskId(preferences.getString(FIELD_TASK_ID, taskId));
|
|
152
|
+
}
|
|
153
|
+
if (preferences.contains(FIELD_IS_FETCH_TASK)) {
|
|
154
|
+
setIsFetchTask(preferences.getBoolean(FIELD_IS_FETCH_TASK, isFetchTask));
|
|
155
|
+
}
|
|
156
|
+
if (preferences.contains(FIELD_MINIMUM_FETCH_INTERVAL)) {
|
|
157
|
+
setMinimumFetchInterval(preferences.getInt(FIELD_MINIMUM_FETCH_INTERVAL, minimumFetchInterval));
|
|
158
|
+
}
|
|
159
|
+
if (preferences.contains(FIELD_STOP_ON_TERMINATE)) {
|
|
160
|
+
setStopOnTerminate(preferences.getBoolean(FIELD_STOP_ON_TERMINATE, stopOnTerminate));
|
|
161
|
+
}
|
|
162
|
+
if (preferences.contains(FIELD_REQUIRED_NETWORK_TYPE)) {
|
|
163
|
+
setRequiredNetworkType(preferences.getInt(FIELD_REQUIRED_NETWORK_TYPE, requiredNetworkType));
|
|
164
|
+
}
|
|
165
|
+
if (preferences.contains(FIELD_REQUIRES_BATTERY_NOT_LOW)) {
|
|
166
|
+
setRequiresBatteryNotLow(preferences.getBoolean(FIELD_REQUIRES_BATTERY_NOT_LOW, requiresBatteryNotLow));
|
|
167
|
+
}
|
|
168
|
+
if (preferences.contains(FIELD_REQUIRES_CHARGING)) {
|
|
169
|
+
setRequiresCharging(preferences.getBoolean(FIELD_REQUIRES_CHARGING, requiresCharging));
|
|
170
|
+
}
|
|
171
|
+
if (preferences.contains(FIELD_REQUIRES_DEVICE_IDLE)) {
|
|
172
|
+
setRequiresDeviceIdle(preferences.getBoolean(FIELD_REQUIRES_DEVICE_IDLE, requiresDeviceIdle));
|
|
173
|
+
}
|
|
174
|
+
if (preferences.contains(FIELD_REQUIRES_STORAGE_NOT_LOW)) {
|
|
175
|
+
setRequiresStorageNotLow(preferences.getBoolean(FIELD_REQUIRES_STORAGE_NOT_LOW, requiresStorageNotLow));
|
|
176
|
+
}
|
|
177
|
+
if (preferences.contains(FIELD_START_ON_BOOT)) {
|
|
178
|
+
setStartOnBoot(preferences.getBoolean(FIELD_START_ON_BOOT, startOnBoot));
|
|
179
|
+
}
|
|
180
|
+
if (preferences.contains(FIELD_JOB_SERVICE)) {
|
|
181
|
+
setJobService(preferences.getString(FIELD_JOB_SERVICE, null));
|
|
182
|
+
}
|
|
183
|
+
if (preferences.contains(FIELD_FORCE_ALARM_MANAGER)) {
|
|
184
|
+
setForceAlarmManager(preferences.getBoolean(FIELD_FORCE_ALARM_MANAGER, forceAlarmManager));
|
|
185
|
+
}
|
|
186
|
+
if (preferences.contains(FIELD_PERIODIC)) {
|
|
187
|
+
setPeriodic(preferences.getBoolean(FIELD_PERIODIC, periodic));
|
|
188
|
+
}
|
|
189
|
+
if (preferences.contains(FIELD_DELAY)) {
|
|
190
|
+
setDelay(preferences.getLong(FIELD_DELAY, delay));
|
|
191
|
+
}
|
|
192
|
+
return new BackgroundFetchConfig(this);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private BackgroundFetchConfig(Builder builder) {
|
|
197
|
+
config = builder;
|
|
198
|
+
// Validate config
|
|
199
|
+
if (config.jobService == null) {
|
|
200
|
+
if (!config.stopOnTerminate) {
|
|
201
|
+
Log.w(BackgroundFetch.TAG, "- Configuration error: In order to use stopOnTerminate: false, you must set enableHeadless: true");
|
|
202
|
+
config.setStopOnTerminate(true);
|
|
203
|
+
}
|
|
204
|
+
if (config.startOnBoot) {
|
|
205
|
+
Log.w(BackgroundFetch.TAG, "- Configuration error: In order to use startOnBoot: true, you must enableHeadless: true");
|
|
206
|
+
config.setStartOnBoot(false);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void save(Context context) {
|
|
212
|
+
SharedPreferences preferences = context.getSharedPreferences(BackgroundFetch.TAG, 0);
|
|
213
|
+
Set<String> taskIds = preferences.getStringSet("tasks", new HashSet<String>());
|
|
214
|
+
if (taskIds == null) {
|
|
215
|
+
taskIds = new HashSet<>();
|
|
216
|
+
}
|
|
217
|
+
if (!taskIds.contains(config.taskId)) {
|
|
218
|
+
Set<String> newIds = new HashSet<>(taskIds);
|
|
219
|
+
newIds.add(config.taskId);
|
|
220
|
+
|
|
221
|
+
SharedPreferences.Editor editor = preferences.edit();
|
|
222
|
+
editor.putStringSet("tasks", newIds);
|
|
223
|
+
editor.apply();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
SharedPreferences.Editor editor = context.getSharedPreferences(BackgroundFetch.TAG + ":" + config.taskId, 0).edit();
|
|
227
|
+
|
|
228
|
+
editor.putString(FIELD_TASK_ID, config.taskId);
|
|
229
|
+
editor.putBoolean(FIELD_IS_FETCH_TASK, config.isFetchTask);
|
|
230
|
+
editor.putInt(FIELD_MINIMUM_FETCH_INTERVAL, config.minimumFetchInterval);
|
|
231
|
+
editor.putBoolean(FIELD_STOP_ON_TERMINATE, config.stopOnTerminate);
|
|
232
|
+
editor.putBoolean(FIELD_START_ON_BOOT, config.startOnBoot);
|
|
233
|
+
editor.putInt(FIELD_REQUIRED_NETWORK_TYPE, config.requiredNetworkType);
|
|
234
|
+
editor.putBoolean(FIELD_REQUIRES_BATTERY_NOT_LOW, config.requiresBatteryNotLow);
|
|
235
|
+
editor.putBoolean(FIELD_REQUIRES_CHARGING, config.requiresCharging);
|
|
236
|
+
editor.putBoolean(FIELD_REQUIRES_DEVICE_IDLE, config.requiresDeviceIdle);
|
|
237
|
+
editor.putBoolean(FIELD_REQUIRES_STORAGE_NOT_LOW, config.requiresStorageNotLow);
|
|
238
|
+
editor.putString(FIELD_JOB_SERVICE, config.jobService);
|
|
239
|
+
editor.putBoolean(FIELD_FORCE_ALARM_MANAGER, config.forceAlarmManager);
|
|
240
|
+
editor.putBoolean(FIELD_PERIODIC, config.periodic);
|
|
241
|
+
editor.putLong(FIELD_DELAY, config.delay);
|
|
242
|
+
|
|
243
|
+
editor.apply();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
void destroy(Context context) {
|
|
247
|
+
SharedPreferences preferences = context.getSharedPreferences(BackgroundFetch.TAG, 0);
|
|
248
|
+
Set<String> taskIds = preferences.getStringSet("tasks", new HashSet<String>());
|
|
249
|
+
if (taskIds == null) {
|
|
250
|
+
taskIds = new HashSet<>();
|
|
251
|
+
}
|
|
252
|
+
if (taskIds.contains(config.taskId)) {
|
|
253
|
+
Set<String> newIds = new HashSet<>(taskIds);
|
|
254
|
+
newIds.remove(config.taskId);
|
|
255
|
+
SharedPreferences.Editor editor = preferences.edit();
|
|
256
|
+
editor.putStringSet("tasks", newIds);
|
|
257
|
+
editor.apply();
|
|
258
|
+
}
|
|
259
|
+
if (!config.isFetchTask) {
|
|
260
|
+
SharedPreferences.Editor editor = context.getSharedPreferences(BackgroundFetch.TAG + ":" + config.taskId, 0).edit();
|
|
261
|
+
editor.clear();
|
|
262
|
+
editor.apply();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static int FETCH_JOB_ID = 999;
|
|
267
|
+
|
|
268
|
+
boolean isFetchTask() {
|
|
269
|
+
return config.isFetchTask;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
public String getTaskId() { return config.taskId; }
|
|
273
|
+
public int getMinimumFetchInterval() {
|
|
274
|
+
return config.minimumFetchInterval;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
public int getRequiredNetworkType() { return config.requiredNetworkType; }
|
|
278
|
+
public boolean getRequiresBatteryNotLow() { return config.requiresBatteryNotLow; }
|
|
279
|
+
public boolean getRequiresCharging() { return config.requiresCharging; }
|
|
280
|
+
public boolean getRequiresDeviceIdle() { return config.requiresDeviceIdle; }
|
|
281
|
+
public boolean getRequiresStorageNotLow() { return config.requiresStorageNotLow; }
|
|
282
|
+
public boolean getStopOnTerminate() {
|
|
283
|
+
return config.stopOnTerminate;
|
|
284
|
+
}
|
|
285
|
+
public boolean getStartOnBoot() {
|
|
286
|
+
return config.startOnBoot;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
public String getJobService() { return config.jobService; }
|
|
290
|
+
|
|
291
|
+
public boolean getForceAlarmManager() {
|
|
292
|
+
return config.forceAlarmManager;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
public boolean getPeriodic() {
|
|
296
|
+
return config.periodic || isFetchTask();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public long getDelay() {
|
|
300
|
+
return config.delay;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
int getJobId() {
|
|
304
|
+
if (config.forceAlarmManager) {
|
|
305
|
+
return 0;
|
|
306
|
+
} else {
|
|
307
|
+
return (isFetchTask()) ? FETCH_JOB_ID : config.taskId.hashCode();
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public String toString() {
|
|
312
|
+
JSONObject output = new JSONObject();
|
|
313
|
+
try {
|
|
314
|
+
output.put(FIELD_TASK_ID, config.taskId);
|
|
315
|
+
output.put(FIELD_IS_FETCH_TASK, config.isFetchTask);
|
|
316
|
+
output.put(FIELD_MINIMUM_FETCH_INTERVAL, config.minimumFetchInterval);
|
|
317
|
+
output.put(FIELD_STOP_ON_TERMINATE, config.stopOnTerminate);
|
|
318
|
+
output.put(FIELD_REQUIRED_NETWORK_TYPE, config.requiredNetworkType);
|
|
319
|
+
output.put(FIELD_REQUIRES_BATTERY_NOT_LOW, config.requiresBatteryNotLow);
|
|
320
|
+
output.put(FIELD_REQUIRES_CHARGING, config.requiresCharging);
|
|
321
|
+
output.put(FIELD_REQUIRES_DEVICE_IDLE, config.requiresDeviceIdle);
|
|
322
|
+
output.put(FIELD_REQUIRES_STORAGE_NOT_LOW, config.requiresStorageNotLow);
|
|
323
|
+
output.put(FIELD_START_ON_BOOT, config.startOnBoot);
|
|
324
|
+
output.put(FIELD_JOB_SERVICE, config.jobService);
|
|
325
|
+
output.put(FIELD_FORCE_ALARM_MANAGER, config.forceAlarmManager);
|
|
326
|
+
output.put(FIELD_PERIODIC, getPeriodic());
|
|
327
|
+
output.put(FIELD_DELAY, config.delay);
|
|
328
|
+
|
|
329
|
+
return output.toString(2);
|
|
330
|
+
} catch (JSONException e) {
|
|
331
|
+
e.printStackTrace();
|
|
332
|
+
return output.toString();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static void load(final Context context, final OnLoadCallback callback) {
|
|
337
|
+
BackgroundFetch.getThreadPool().execute(new Runnable() {
|
|
338
|
+
@Override
|
|
339
|
+
public void run() {
|
|
340
|
+
final List<BackgroundFetchConfig> result = new ArrayList<>();
|
|
341
|
+
|
|
342
|
+
SharedPreferences preferences = context.getSharedPreferences(BackgroundFetch.TAG, 0);
|
|
343
|
+
Set<String> taskIds = preferences.getStringSet("tasks", new HashSet<String>());
|
|
344
|
+
|
|
345
|
+
if (taskIds != null) {
|
|
346
|
+
for (String taskId : taskIds) {
|
|
347
|
+
result.add(new BackgroundFetchConfig.Builder().load(context, taskId));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
BackgroundFetch.getUiHandler().post(new Runnable() {
|
|
351
|
+
@Override public void run() {
|
|
352
|
+
callback.onLoad(result);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
interface OnLoadCallback {
|
|
360
|
+
void onLoad(List<BackgroundFetchConfig>config);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.transistorsoft.tsbackgroundfetch;
|
|
2
|
+
|
|
3
|
+
import android.content.BroadcastReceiver;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.Intent;
|
|
6
|
+
import android.util.Log;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Created by chris on 2018-01-15.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
public class BootReceiver extends BroadcastReceiver {
|
|
13
|
+
|
|
14
|
+
@Override
|
|
15
|
+
public void onReceive(final Context context, Intent intent) {
|
|
16
|
+
String action = intent.getAction();
|
|
17
|
+
Log.d(BackgroundFetch.TAG, "BootReceiver: " + action);
|
|
18
|
+
BackgroundFetch.getThreadPool().execute(new Runnable() {
|
|
19
|
+
@Override public void run() {
|
|
20
|
+
BackgroundFetch.getInstance(context.getApplicationContext()).onBoot();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|