Skip to content

Commit a57f8a9

Browse files
committed
merge master
1 parent 57ab58d commit a57f8a9

File tree

13 files changed

+441
-198
lines changed

13 files changed

+441
-198
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2019, Leanplum, Inc. All rights reserved.
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
package com.leanplum.internal;
23+
24+
import android.os.Handler;
25+
import android.os.Looper;
26+
27+
28+
public class Operation extends Thread {
29+
30+
private static final Handler handler = new Handler(Looper.getMainLooper());
31+
32+
private Runnable runnable;
33+
34+
protected Operation(Runnable runnable) {
35+
this.runnable = runnable;
36+
}
37+
38+
/**
39+
* Helper methods to execute runnable on main thread
40+
*
41+
* @param runnable to executes
42+
*/
43+
public static void runOnUiThread(Runnable runnable) {
44+
handler.post(runnable);
45+
}
46+
47+
/**
48+
* Helper methods to execute runnable on main thread after delay
49+
*
50+
* @param runnable to executes
51+
*/
52+
public static void runOnUiThreadAfterDelay(Runnable runnable, long delayTimeMillis) {
53+
handler.postDelayed(runnable, delayTimeMillis);
54+
}
55+
56+
/**
57+
* Helper methods to remove runnable from main thread
58+
*
59+
* @param runnable to remove
60+
*/
61+
public static void removeOperationOnUiThread(Runnable runnable) {
62+
handler.removeCallbacks(runnable);
63+
}
64+
65+
@Override
66+
public void run() {
67+
if (runnable != null) {
68+
runnable.run();
69+
}
70+
}
71+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright 2019, Leanplum, Inc. All rights reserved.
3+
*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
package com.leanplum.internal;
23+
24+
import android.os.Handler;
25+
import android.os.HandlerThread;
26+
import android.os.Process;
27+
28+
public class OperationQueue {
29+
30+
private static OperationQueue instance;
31+
32+
private static final String OPERATION_QUEUE_NAME = "com.leanplum.operation_queue";
33+
private static final int OPERATION_QUEUE_PRIORITY = Process.THREAD_PRIORITY_DEFAULT;
34+
35+
private HandlerThread handlerThread;
36+
private Handler handler;
37+
38+
public static OperationQueue sharedInstance() {
39+
if (instance == null) {
40+
instance = new OperationQueue();
41+
}
42+
return instance;
43+
}
44+
45+
OperationQueue() {
46+
start();
47+
}
48+
49+
/**
50+
* Start the underlying thread, call to this method is optional.
51+
*/
52+
void start() {
53+
if (handlerThread == null) {
54+
handlerThread = new HandlerThread(OPERATION_QUEUE_NAME, OPERATION_QUEUE_PRIORITY);
55+
handlerThread.start();
56+
}
57+
58+
handler = new Handler(handlerThread.getLooper());
59+
}
60+
61+
/**
62+
* Stop OperationQueue and remove all operations
63+
*/
64+
void stop() {
65+
removeAllOperations();
66+
67+
handlerThread.quit();
68+
handlerThread = null;
69+
}
70+
71+
/**
72+
* Add operation to OperationQueue at the end
73+
* @param operation The operation that will be executed.
74+
* @return return true if the operation was successfully placed in to the operation queue. Returns false on failure.
75+
*/
76+
boolean addOperation(Runnable operation) {
77+
if (operation != null && handler != null) {
78+
return handler.post(new Operation(operation));
79+
}
80+
return false;
81+
}
82+
83+
/**
84+
* Add operation to OperationQueue at the front
85+
* @param operation The operation that will be executed.
86+
* @return return true if the operation was successfully placed in to the operation queue. Returns false on failure.
87+
*/
88+
boolean addOperationAtFront(Runnable operation) {
89+
if (operation != null && handler != null) {
90+
return handler.postAtFrontOfQueue(new Operation(operation));
91+
}
92+
return false;
93+
}
94+
95+
/**
96+
* Add operation to OperationQueue, to be run at a specific time given by millis.
97+
* @param operation operation The operation that will be executed.
98+
* @return return true if the operation was successfully placed in to the operation queue. Returns false on failure.
99+
*/
100+
boolean addOperationAtTime(Runnable operation, long millis) {
101+
if (operation != null && handler != null) {
102+
return handler.postAtTime(new Operation(operation), millis);
103+
}
104+
return false;
105+
}
106+
107+
/**
108+
* Add operation to OperationQueue, to be run after the specific time given by delayMillis.
109+
* @param operation operation operation The operation that will be executed.
110+
* @param delayMillis
111+
* @return return true if the operation was successfully placed in to the operation queue. Returns false on failure.
112+
*/
113+
boolean addOperationAfterDelay(Runnable operation, long delayMillis) {
114+
if (operation != null && handler != null) {
115+
return handler.postDelayed(new Operation(operation), delayMillis);
116+
}
117+
return false;
118+
}
119+
120+
/**
121+
* Remove all pending Operations that are in OperationQueue
122+
*/
123+
void removeAllOperations() {
124+
if (handler != null) {
125+
handler.removeCallbacksAndMessages(null);
126+
}
127+
}
128+
}

AndroidSDKCore/src/main/java/com/leanplum/internal/RequestOld.java

Lines changed: 39 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public class RequestOld implements Requesting {
6464
private static final long DEVELOPMENT_MIN_DELAY_MS = 100;
6565
private static final long DEVELOPMENT_MAX_DELAY_MS = 5000;
6666
private static final long PRODUCTION_DELAY = 60000;
67-
private RequestSequenceRecorder requestSequenceRecorder;
67+
6868
static final int MAX_EVENTS_PER_API_CALL;
6969
static final String LEANPLUM = "__leanplum__";
7070
static final String UUID_KEY = "uuid";
@@ -174,28 +174,6 @@ public static void saveToken() {
174174
SharedPreferencesUtil.commitChanges(editor);
175175
}
176176

177-
private static class NoRequestSequenceRecorder implements RequestSequenceRecorder {
178-
@Override
179-
public void beforeRead() {
180-
// No op.
181-
}
182-
183-
@Override
184-
public void afterRead() {
185-
// No op.
186-
}
187-
188-
@Override
189-
public void beforeWrite() {
190-
// No op.
191-
}
192-
193-
@Override
194-
public void afterWrite() {
195-
// No op.
196-
}
197-
}
198-
199177
public static String appId() {
200178
return appId;
201179
}
@@ -209,10 +187,6 @@ public static String userId() {
209187
}
210188

211189
public RequestOld(String httpMethod, String apiMethod, Map<String, Object> params) {
212-
this(httpMethod, apiMethod, params, new NoRequestSequenceRecorder());
213-
}
214-
215-
RequestOld(String httpMethod, String apiMethod, Map<String, Object> params, RequestSequenceRecorder requestSequenceRecorder) {
216190
this.httpMethod = httpMethod;
217191
this.apiMethod = apiMethod;
218192
this.params = params != null ? params : new HashMap<String, Object>();
@@ -223,7 +197,7 @@ public RequestOld(String httpMethod, String apiMethod, Map<String, Object> param
223197
// Make sure the Handler is initialized on the main thread.
224198
OsHandler.getInstance();
225199
dataBaseIndex = -1;
226-
this.requestSequenceRecorder = requestSequenceRecorder;
200+
227201
this.requestId = UUID.randomUUID().toString();
228202
}
229203

@@ -257,7 +231,6 @@ public void onApiResponse(ApiResponseCallback apiResponse) {
257231
RequestOld.apiResponse = apiResponse;
258232
}
259233

260-
@VisibleForTesting
261234
public Map<String, Object> createArgsDictionary() {
262235
Map<String, Object> args = new HashMap<>();
263236
args.put(Constants.Params.DEVICE_ID, deviceId);
@@ -274,43 +247,47 @@ public Map<String, Object> createArgsDictionary() {
274247
return args;
275248
}
276249

277-
private void saveRequestForLater(Map<String, Object> args) {
278-
try {
250+
/**
251+
* Saves requests into database.
252+
* Saving will be executed on background thread serially.
253+
* @param args json to save.
254+
*/
255+
private void saveRequestForLater(final Map<String, Object> args) {
256+
OperationQueue.sharedInstance().addOperation(new Runnable() {
257+
@Override
258+
public void run() {
259+
try {
260+
Context context = Leanplum.getContext();
261+
if (context == null) {
262+
return;
263+
}
279264

280-
Context context = Leanplum.getContext();
281-
if (context == null) {
282-
return;
283-
}
265+
SharedPreferences preferences = context.getSharedPreferences(LEANPLUM,
266+
Context.MODE_PRIVATE);
267+
SharedPreferences.Editor editor = preferences.edit();
268+
long count = LeanplumEventDataManager.sharedInstance().getEventsCount();
269+
String uuid = preferences.getString(Constants.Defaults.UUID_KEY, null);
270+
if (uuid == null || count % MAX_EVENTS_PER_API_CALL == 0) {
271+
uuid = UUID.randomUUID().toString();
272+
editor.putString(Constants.Defaults.UUID_KEY, uuid);
273+
SharedPreferencesUtil.commitChanges(editor);
274+
}
275+
args.put(UUID_KEY, uuid);
276+
LeanplumEventDataManager.sharedInstance().insertEvent(JsonConverter.toJson(args));
277+
278+
dataBaseIndex = count;
279+
// Checks if here response and/or error callback for this request. We need to add callbacks to
280+
// eventCallbackManager only if here was internet connection, otherwise triggerErrorCallback
281+
// will handle error callback for this event.
282+
if (response != null || error != null && !Util.isConnected()) {
283+
eventCallbackManager.addCallbacks(RequestOld.this, response, error);
284+
}
284285

285-
requestSequenceRecorder.beforeWrite();
286-
287-
synchronized (RequestOld.class) {
288-
SharedPreferences preferences = context.getSharedPreferences(
289-
LEANPLUM, Context.MODE_PRIVATE);
290-
SharedPreferences.Editor editor = preferences.edit();
291-
long count = LeanplumEventDataManager.sharedInstance().getEventsCount();
292-
String uuid = preferences.getString(Constants.Defaults.UUID_KEY, null);
293-
if (uuid == null || count % MAX_EVENTS_PER_API_CALL == 0) {
294-
uuid = UUID.randomUUID().toString();
295-
editor.putString(Constants.Defaults.UUID_KEY, uuid);
296-
SharedPreferencesUtil.commitChanges(editor);
297-
}
298-
args.put(UUID_KEY, uuid);
299-
LeanplumEventDataManager.sharedInstance().insertEvent(JsonConverter.toJson(args));
300-
301-
dataBaseIndex = count;
302-
// Checks if here response and/or error callback for this request. We need to add callbacks to
303-
// eventCallbackManager only if here was internet connection, otherwise triggerErrorCallback
304-
// will handle error callback for this event.
305-
if (response != null || error != null && !Util.isConnected()) {
306-
eventCallbackManager.addCallbacks(this, response, error);
286+
} catch (Throwable t) {
287+
Util.handleException(t);
307288
}
308289
}
309-
310-
requestSequenceRecorder.afterWrite();
311-
} catch (Throwable t) {
312-
Util.handleException(t);
313-
}
290+
});
314291
}
315292

316293
public void send() {
@@ -481,7 +458,6 @@ private void parseResponseBody(JSONObject responseBody, List<Map<String, Object>
481458
* @param errorMessage String of error from server response.
482459
* @return String of readable error message.
483460
*/
484-
@NonNull
485461
private String getReadableErrorMessage(String errorMessage) {
486462
if (errorMessage == null || errorMessage.length() == 0) {
487463
errorMessage = "API error";
@@ -607,12 +583,9 @@ private RequestsWithEncoding getRequestsWithEncodedString() {
607583

608584
private void sendRequests() {
609585
Leanplum.countAggregator().sendAllCounts();
610-
requestSequenceRecorder.beforeRead();
611586

612587
RequestsWithEncoding requestsWithEncoding = getRequestsWithEncodedString();
613588

614-
requestSequenceRecorder.afterRead();
615-
616589
List<Map<String, Object>> unsentRequests = requestsWithEncoding.unsentRequests;
617590
List<Map<String, Object>> requestsToSend = requestsWithEncoding.requestsToSend;
618591
String jsonEncodedString = requestsWithEncoding.jsonEncodedString;

AndroidSDKCore/src/main/java/com/leanplum/internal/RequestSequenceRecorder.java

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)