11package com .cloudinary .android ;
22
33import android .content .Context ;
4- import android .os .PowerManager ;
4+ import android .os .Bundle ;
55
66import androidx .annotation .NonNull ;
7- import androidx .lifecycle .LiveData ;
87import androidx .work .BackoffPolicy ;
98import androidx .work .Constraints ;
109import androidx .work .Data ;
10+ import androidx .work .ExistingWorkPolicy ;
1111import androidx .work .NetworkType ;
1212import androidx .work .OneTimeWorkRequest ;
1313import androidx .work .Operation ;
1414import androidx .work .WorkInfo ;
1515import androidx .work .WorkManager ;
16- import androidx .work .WorkRequest ;
1716import androidx .work .Worker ;
1817import androidx .work .WorkerParameters ;
1918
2019import com .cloudinary .android .callback .UploadStatus ;
2120import com .cloudinary .android .policy .UploadPolicy ;
2221
23- import java .lang .ref .WeakReference ;
22+ import java .io .File ;
23+ import java .io .FileInputStream ;
24+ import java .io .IOException ;
25+ import java .io .ObjectInputStream ;
2426import java .util .List ;
25- import java .util .Map ;
26- import java .util .concurrent .ConcurrentHashMap ;
2727import java .util .concurrent .TimeUnit ;
2828
2929public class AndroidJobStrategy implements BackgroundRequestStrategy {
3030
3131 private static final String JOB_TAG = "CLD" ;
3232
33- private static final Map <String , WeakReference <Thread >> threads = new ConcurrentHashMap <>();
34- private static final Object threadsMapLockObject = new Object ();
3533 private Context context ;
3634
37- public static WorkRequest adapt (UploadRequest request ) {
35+ public static OneTimeWorkRequest adapt (UploadRequest <?> request , File payloadFile ) {
3836 UploadPolicy policy = request .getUploadPolicy ();
3937
40- Constraints .Builder constraintsBuilder = new Constraints .Builder ()
41- .setRequiredNetworkType (adaptNetworkType (policy .getNetworkType ()))
42- .setRequiresCharging (policy .isRequiresCharging ());
38+ Constraints .Builder constraintsBuilder = new Constraints .Builder ().setRequiredNetworkType (adaptNetworkType (policy .getNetworkType ())).setRequiresCharging (policy .isRequiresCharging ());
4339 if (android .os .Build .VERSION .SDK_INT >= android .os .Build .VERSION_CODES .M ) {
4440 constraintsBuilder .setRequiresDeviceIdle (policy .isRequiresIdle ());
4541 }
4642 Constraints constraints = constraintsBuilder .build ();
4743
48- Data inputData = request .buildPayload ();
44+ Data inputData = request .buildPayload (payloadFile );
4945
50- OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest .Builder (UploadJob .class )
51- .setBackoffCriteria (adaptBackoffPolicy (policy .getBackoffPolicy ()),policy .getBackoffMillis (), TimeUnit .MILLISECONDS )
52- .setInputData (inputData )
53- .setConstraints (constraints )
54- .addTag (JOB_TAG )
55- .build ();
56- return uploadWorkRequest ;
46+ return new OneTimeWorkRequest .Builder (UploadJob .class ).setBackoffCriteria (adaptBackoffPolicy (policy .getBackoffPolicy ()), policy .getBackoffMillis (), TimeUnit .MILLISECONDS ).setInputData (inputData ).setConstraints (constraints ).addTag (JOB_TAG ).build ();
5747 }
5848
5949 private static BackoffPolicy adaptBackoffPolicy (UploadPolicy .BackoffPolicy backoffPolicy ) {
@@ -85,9 +75,20 @@ public void init(Context context) {
8575 }
8676
8777 @ Override
88- public void doDispatch (UploadRequest request ) {
89- WorkRequest uploadWorkRequest = adapt (request );
90- WorkManager .getInstance ().enqueue (uploadWorkRequest );
78+ public void doDispatch (@ SuppressWarnings ("rawtypes" ) @ NonNull UploadRequest request ) {
79+ File cacheDir = context .getCacheDir ();
80+ try {
81+ // Prepare payload file placeholder to temporarily store payload data.
82+ File payloadFile = File .createTempFile ("payload" , request .getRequestId (), cacheDir );
83+ OneTimeWorkRequest uploadWorkRequest = adapt (request , payloadFile );
84+ WorkManager .getInstance (context ).beginUniqueWork (
85+ // Use request ID as unique work name
86+ request .getRequestId (),
87+ // If work already exist, do nothing.
88+ ExistingWorkPolicy .KEEP , uploadWorkRequest ).enqueue ();
89+ } catch (IOException e ) {
90+ e .printStackTrace ();
91+ }
9192 }
9293
9394 @ Override
@@ -97,13 +98,13 @@ public void executeRequestsNow(int howMany) {
9798
9899 @ Override
99100 public boolean cancelRequest (String requestId ) {
100- Operation operation = WorkManager .getInstance ().cancelAllWorkByTag (requestId );
101+ Operation operation = WorkManager .getInstance (context ).cancelAllWorkByTag (requestId );
101102 return operation .getResult ().isCancelled ();
102103 }
103104
104105 @ Override
105106 public int cancelAllRequests () {
106- WorkManager .getInstance ().cancelAllWork ();
107+ WorkManager .getInstance (context ).cancelAllWork ();
107108 return 0 ;
108109 }
109110
@@ -119,7 +120,7 @@ public int getRunningJobsCount() {
119120
120121 private int getJobCountByState (WorkInfo .State state ) {
121122 int counter = 0 ;
122- List <WorkInfo > list = WorkManager .getInstance ().getWorkInfosByTagLiveData (JOB_TAG ).getValue ();
123+ List <WorkInfo > list = WorkManager .getInstance (context ).getWorkInfosByTagLiveData (JOB_TAG ).getValue ();
123124 if (list != null ) {
124125 for (WorkInfo info : list ) {
125126 if (info .getState () == state ) {
@@ -133,9 +134,8 @@ private int getJobCountByState(WorkInfo.State state) {
133134
134135 public static final class UploadJob extends Worker {
135136
136- private Context context ;
137- private String requestId ;
138- private WorkerParameters workParams ;
137+ private final Context context ;
138+ private final WorkerParameters workParams ;
139139
140140 public UploadJob (@ NonNull Context context , @ NonNull WorkerParameters workerParams ) {
141141 super (context , workerParams );
@@ -146,35 +146,27 @@ public UploadJob(@NonNull Context context, @NonNull WorkerParameters workerParam
146146 @ NonNull
147147 @ Override
148148 public Result doWork () {
149- PowerManager pm = (PowerManager ) context .getSystemService (Context .POWER_SERVICE );
150- final PowerManager .WakeLock wl = pm .newWakeLock (PowerManager .PARTIAL_WAKE_LOCK , "CLD:UPLOADER" );
151- requestId = workParams .getInputData ().getString ("requestId" );
152- registerThread ();
149+ // Removed Wakelock logic as it causes RuntimeException ("WakeLock under-locked")
153150
154- wl .acquire ();
155- try {
151+ // Prepare extract payload data from temporary file.
152+ String payloadFilePath = workParams .getInputData ().getString (UploadRequest .PayloadData .KEY );
153+ if (payloadFilePath == null ) {
154+ // NO Payload input file created prior to request.
155+ return Result .failure ();
156+ }
157+ File payloadFile = new File (payloadFilePath );
158+ try (ObjectInputStream ois = new ObjectInputStream (new FileInputStream (payloadFile ))) {
159+ UploadRequest .PayloadData payloadData = (UploadRequest .PayloadData ) ois .readObject ();
160+ AndroidJobStrategy .AndroidJobRequestParams jobInputData = new AndroidJobStrategy .AndroidJobRequestParams (payloadData );
156161
157162 // call the generic processor:
158- UploadStatus result = MediaManager .get ().processRequest (context , new AndroidJobStrategy . AndroidJobRequestParams ( workParams . getInputData ()) );
163+ UploadStatus result = MediaManager .get ().processRequest (context , jobInputData );
159164 return adaptResult (result );
160- } finally {
161- wl .release ();
162- unregisterThread ();
163- }
164- }
165-
166- private void registerThread () {
167- synchronized (threadsMapLockObject ) {
168- threads .put (requestId , new WeakReference <>(Thread .currentThread ()));
169- }
170- }
171165
172- private void unregisterThread () {
173- synchronized (threadsMapLockObject ) {
174- WeakReference <Thread > removed = threads .remove (requestId );
175- if (removed != null ) {
176- removed .clear ();
177- }
166+ } catch (NullPointerException | IOException | ClassNotFoundException e ) {
167+ // Unable to deserialize payload data from file.
168+ e .printStackTrace ();
169+ return Result .failure ();
178170 }
179171 }
180172
@@ -194,54 +186,54 @@ private Result adaptResult(UploadStatus res) {
194186 }
195187
196188 private static final class AndroidJobRequestParams implements RequestParams {
197- private final Data bundle ;
189+ private final Bundle data ;
198190
199- private AndroidJobRequestParams (Data bundle ) {
200- this .bundle = bundle ;
191+ private AndroidJobRequestParams (UploadRequest .PayloadData payloadData ) {
192+ this .data = new Bundle ();
193+ this .data .putString ("uri" , payloadData .getUri ());
194+ this .data .putString ("requestId" , payloadData .getRequestId ());
195+ this .data .putInt ("maxErrorRetries" , payloadData .getMaxErrorRetries ());
196+ this .data .putString ("options" , payloadData .getOptions ());
201197 }
202198
203199 @ Override
204200 public void putString (String key , String value ) {
205- putIntoExistingDataObject () .putString (key , value ). build ( );
201+ data .putString (key , value );
206202 }
207203
208204 @ Override
209205 public void putInt (String key , int value ) {
210- putIntoExistingDataObject () .putInt (key , value ). build ( );
206+ data .putInt (key , value );
211207 }
212208
213209 @ Override
214210 public void putLong (String key , long value ) {
215- putIntoExistingDataObject () .putLong (key , value ). build ( );
211+ data .putLong (key , value );
216212 }
217213
218214 @ Override
219215 public void putBoolean (String key , boolean value ) {
220- putIntoExistingDataObject () .putBoolean (key , value ). build ( );
216+ data .putBoolean (key , value );
221217 }
222218
223219 @ Override
224220 public String getString (String key , String defaultValue ) {
225- return (bundle .getString (key ) != null ) ? bundle .getString (key ) : defaultValue ;
221+ return (data .getString (key ) != null ) ? data .getString (key ) : defaultValue ;
226222 }
227223
228224 @ Override
229225 public int getInt (String key , int defaultValue ) {
230- return bundle .getInt (key , defaultValue );
226+ return data .getInt (key , defaultValue );
231227 }
232228
233229 @ Override
234230 public long getLong (String key , long defaultValue ) {
235- return bundle .getLong (key , defaultValue );
231+ return data .getLong (key , defaultValue );
236232 }
237233
238234 @ Override
239235 public boolean getBoolean (String key , boolean defaultValue ) {
240- return bundle .getBoolean (key , defaultValue );
241- }
242-
243- private Data .Builder putIntoExistingDataObject () {
244- return new Data .Builder ().putAll (bundle );
236+ return data .getBoolean (key , defaultValue );
245237 }
246238 }
247239}
0 commit comments