Skip to content

Commit 2540a7f

Browse files
milos1290e7mac
authored andcommitted
Fixing DB not initialized when PN arrives (#368)
* Fixing DB not initialized when PN arrives * Fixing failing test * Fixing failing tests * Fixing failing test case * Setting context in service onCreate * Fixing PR comments
1 parent 24a7c17 commit 2540a7f

File tree

10 files changed

+87
-64
lines changed

10 files changed

+87
-64
lines changed

AndroidSDKCore/src/main/java/com/leanplum/Leanplum.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ private static void checkAndStartNotificationsModules() {
625625

626626
private static void startHelper(
627627
String userId, final Map<String, ?> attributes, final boolean isBackground) {
628-
LeanplumEventDataManager.init(context);
628+
LeanplumEventDataManager.sharedInstance();
629629
checkAndStartNotificationsModules();
630630
Boolean limitAdTracking = null;
631631
String deviceId = RequestOld.deviceId();

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

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -48,53 +48,58 @@
4848
* @author Anna Orlova
4949
*/
5050
public class LeanplumEventDataManager {
51+
52+
private static LeanplumEventDataManager instance;
53+
5154
private static final String DATABASE_NAME = "__leanplum.db";
5255
private static final int DATABASE_VERSION = 1;
5356
private static final String EVENT_TABLE_NAME = "event";
5457
private static final String COLUMN_DATA = "data";
5558
private static final String KEY_ROWID = "rowid";
5659

57-
private static SQLiteDatabase database;
58-
private static LeanplumDataBaseManager databaseManager;
59-
private static ContentValues contentValues = new ContentValues();
60+
private SQLiteDatabase database;
61+
private LeanplumDataBaseManager databaseManager;
62+
private ContentValues contentValues = new ContentValues();
63+
private boolean sendErrorLogs = false;
6064

61-
static boolean willSendErrorLog = false;
65+
private LeanplumEventDataManager() {
66+
try {
67+
Context context = Leanplum.getContext();
6268

63-
/**
64-
* Creates connection to database, if database is not present, it will automatically create it.
65-
*
66-
* @param context Current context.
67-
*/
68-
public static void init(Context context) {
69-
if (database != null) {
70-
Log.e("Database is already initialized.");
71-
return;
72-
}
69+
if (context == null) {
70+
return;
71+
}
7372

74-
// Create database if needed.
75-
try {
7673
if (databaseManager == null) {
77-
databaseManager = new LeanplumDataBaseManager(context);
74+
databaseManager = new LeanplumDataBaseManager(Leanplum.getContext());
7875
}
7976
database = databaseManager.getWritableDatabase();
77+
8078
} catch (Throwable t) {
8179
handleSQLiteError("Cannot create database.", t);
8280
}
8381
}
8482

83+
public static LeanplumEventDataManager sharedInstance() {
84+
if (instance == null) {
85+
instance = new LeanplumEventDataManager();
86+
}
87+
return instance;
88+
}
89+
8590
/**
8691
* Inserts event to event table.
8792
*
8893
* @param event String with json of event.
8994
*/
90-
static void insertEvent(String event) {
95+
void insertEvent(String event) {
9196
if (database == null) {
9297
return;
9398
}
9499
contentValues.put(COLUMN_DATA, event);
95100
try {
96101
database.insert(EVENT_TABLE_NAME, null, contentValues);
97-
willSendErrorLog = false;
102+
sendErrorLogs = false;
98103
} catch (Throwable t) {
99104
handleSQLiteError("Unable to insert event to database.", t);
100105
}
@@ -108,7 +113,7 @@ static void insertEvent(String event) {
108113
* @param count Number of events.
109114
* @return List of events.
110115
*/
111-
static List<Map<String, Object>> getEvents(int count) {
116+
List<Map<String, Object>> getEvents(int count) {
112117
List<Map<String, Object>> events = new ArrayList<>();
113118
if (database == null) {
114119
return events;
@@ -117,7 +122,7 @@ static List<Map<String, Object>> getEvents(int count) {
117122
try {
118123
cursor = database.query(EVENT_TABLE_NAME, new String[] {COLUMN_DATA}, null, null, null,
119124
null, KEY_ROWID + " ASC", "" + count);
120-
willSendErrorLog = false;
125+
sendErrorLogs = false;
121126
while (cursor.moveToNext()) {
122127
Map<String, Object> requestArgs = JsonConverter.mapFromJson(new JSONObject(
123128
cursor.getString(cursor.getColumnIndex(COLUMN_DATA))));
@@ -139,14 +144,14 @@ static List<Map<String, Object>> getEvents(int count) {
139144
*
140145
* @param count Number of event that need to be deleted.
141146
*/
142-
static void deleteEvents(int count) {
147+
void deleteEvents(int count) {
143148
if (database == null) {
144149
return;
145150
}
146151
try {
147152
database.delete(EVENT_TABLE_NAME, KEY_ROWID + " in (select " + KEY_ROWID + " from " +
148153
EVENT_TABLE_NAME + " ORDER BY " + KEY_ROWID + " ASC LIMIT " + count + ")", null);
149-
willSendErrorLog = false;
154+
sendErrorLogs = false;
150155
} catch (Throwable t) {
151156
handleSQLiteError("Unable to delete events from the table.", t);
152157
}
@@ -158,33 +163,41 @@ static void deleteEvents(int count) {
158163
*
159164
* @return Number of rows in the event table.
160165
*/
161-
static long getEventsCount() {
166+
long getEventsCount() {
162167
long count = 0;
163168
if (database == null) {
164169
return count;
165170
}
166171
try {
167172
count = DatabaseUtils.queryNumEntries(database, EVENT_TABLE_NAME);
168-
willSendErrorLog = false;
173+
sendErrorLogs = false;
169174
} catch (Throwable t) {
170175
handleSQLiteError("Unable to get a number of rows in the table.", t);
171176
}
172177
return count;
173178
}
174179

180+
/**
181+
* Whether we are going to send error log or not.
182+
*/
183+
boolean willSendErrorLogs() {
184+
return sendErrorLogs;
185+
}
186+
175187
/**
176188
* Helper function that logs and sends errors to the server.
177189
*/
178-
private static void handleSQLiteError(String log, Throwable t) {
190+
private void handleSQLiteError(String log, Throwable t) {
179191
Log.e(log, t);
180192
// Send error log. Using willSendErrorLog to prevent infinte loop.
181-
if (!willSendErrorLog) {
182-
willSendErrorLog = true;
193+
if (!sendErrorLogs) {
194+
sendErrorLogs = true;
183195
Util.handleException(t);
184196
}
185197
}
186198

187199
private static class LeanplumDataBaseManager extends SQLiteOpenHelper {
200+
188201
LeanplumDataBaseManager(Context context) {
189202
super(context, DATABASE_NAME, null, DATABASE_VERSION);
190203
}
@@ -239,6 +252,8 @@ private static void migrateFromSharedPreferences(SQLiteDatabase db) {
239252

240253
editor.remove(Constants.Defaults.COUNT_KEY);
241254

255+
ContentValues contentValues = new ContentValues();
256+
242257
try {
243258
String uuid = preferences.getString(Constants.Defaults.UUID_KEY, null);
244259
if (uuid == null || count % RequestOld.MAX_EVENTS_PER_API_CALL == 0) {

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@
2525
import android.content.SharedPreferences;
2626
import android.os.AsyncTask;
2727
import android.os.Build;
28+
29+
import androidx.annotation.MainThread;
2830
import androidx.annotation.NonNull;
2931
import androidx.annotation.VisibleForTesting;
32+
33+
import android.os.Looper;
3034
import android.text.TextUtils;
3135

3236
import com.leanplum.Leanplum;
@@ -215,7 +219,7 @@ public RequestOld(String httpMethod, String apiMethod, Map<String, Object> param
215219
this.apiMethod = apiMethod;
216220
this.params = params != null ? params : new HashMap<String, Object>();
217221
// Check if it is error and here was SQLite exception.
218-
if (Constants.Methods.LOG.equals(apiMethod) && LeanplumEventDataManager.willSendErrorLog) {
222+
if (Constants.Methods.LOG.equals(apiMethod) && LeanplumEventDataManager.sharedInstance().willSendErrorLogs()) {
219223
localErrors.add(createArgsDictionary());
220224
}
221225
// Make sure the Handler is initialized on the main thread.
@@ -286,15 +290,15 @@ private void saveRequestForLater(Map<String, Object> args) {
286290
SharedPreferences preferences = context.getSharedPreferences(
287291
LEANPLUM, Context.MODE_PRIVATE);
288292
SharedPreferences.Editor editor = preferences.edit();
289-
long count = LeanplumEventDataManager.getEventsCount();
293+
long count = LeanplumEventDataManager.sharedInstance().getEventsCount();
290294
String uuid = preferences.getString(Constants.Defaults.UUID_KEY, null);
291295
if (uuid == null || count % MAX_EVENTS_PER_API_CALL == 0) {
292296
uuid = UUID.randomUUID().toString();
293297
editor.putString(Constants.Defaults.UUID_KEY, uuid);
294298
SharedPreferencesUtil.commitChanges(editor);
295299
}
296300
args.put(UUID_KEY, uuid);
297-
LeanplumEventDataManager.insertEvent(JsonConverter.toJson(args));
301+
LeanplumEventDataManager.sharedInstance().insertEvent(JsonConverter.toJson(args));
298302

299303
dataBaseIndex = count;
300304
// Checks if here response and/or error callback for this request. We need to add callbacks to
@@ -370,9 +374,9 @@ private void sendIfDelayedHelper() {
370374

371375
public void sendIfConnected() {
372376
if (Util.isConnected()) {
373-
this.sendNow();
377+
sendNow();
374378
} else {
375-
this.sendEventually();
379+
sendEventually();
376380
Log.i("Device is offline, will send later");
377381
triggerErrorCallback(new Exception("Not connected to the Internet"));
378382
}
@@ -529,7 +533,6 @@ protected Void doInBackground(Void... params) {
529533
});
530534
}
531535

532-
533536
/**
534537
* This class wraps the unsent requests, requests that we need to send
535538
* and the JSON encoded string. Wrapping it in the class allows us to
@@ -697,7 +700,7 @@ public void sendEventually() {
697700
return;
698701
}
699702

700-
if (LeanplumEventDataManager.willSendErrorLog) {
703+
if (LeanplumEventDataManager.sharedInstance().willSendErrorLogs()) {
701704
return;
702705
}
703706

@@ -714,7 +717,7 @@ static void deleteSentRequests(int requestsCount) {
714717
return;
715718
}
716719
synchronized (RequestOld.class) {
717-
LeanplumEventDataManager.deleteEvents(requestsCount);
720+
LeanplumEventDataManager.sharedInstance().deleteEvents(requestsCount);
718721
}
719722
}
720723

@@ -728,7 +731,7 @@ public List<Map<String, Object>> getUnsentRequests(double fraction) {
728731
LEANPLUM, Context.MODE_PRIVATE);
729732
SharedPreferences.Editor editor = preferences.edit();
730733
int count = (int) (fraction * MAX_EVENTS_PER_API_CALL);
731-
requestData = LeanplumEventDataManager.getEvents(count);
734+
requestData = LeanplumEventDataManager.sharedInstance().getEvents(count);
732735
editor.remove(Constants.Defaults.UUID_KEY);
733736
SharedPreferencesUtil.commitChanges(editor);
734737
// if we send less than 100% of requests, we need to reset the batch

AndroidSDKFcm/src/main/java/com/leanplum/LeanplumPushFirebaseMessagingService.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,21 @@
4141
@SuppressLint("Registered")
4242
public class LeanplumPushFirebaseMessagingService extends FirebaseMessagingService {
4343

44+
@Override
45+
public void onCreate() {
46+
super.onCreate();
47+
Leanplum.setApplicationContext(getApplicationContext());
48+
}
49+
4450
@Override
4551
public void onNewToken(String token) {
4652
super.onNewToken(token);
4753

4854
LeanplumPushService.setCloudMessagingProvider(new LeanplumFcmProvider());
49-
LeanplumPushService.getCloudMessagingProvider().storePreferences(this.getApplicationContext(), token);
55+
LeanplumPushService.getCloudMessagingProvider().storePreferences(getApplicationContext(), token);
5056

5157
//send the new token to backend
52-
LeanplumPushService.getCloudMessagingProvider().onRegistrationIdReceived(this.getApplicationContext(), token);
58+
LeanplumPushService.getCloudMessagingProvider().onRegistrationIdReceived(getApplicationContext(), token);
5359
}
5460

5561
/**
@@ -61,12 +67,9 @@ public void onNewToken(String token) {
6167
@Override
6268
public void onMessageReceived(RemoteMessage remoteMessage) {
6369
try {
64-
if (Leanplum.getContext() == null) {
65-
Leanplum.setApplicationContext(this);
66-
}
6770
Map<String, String> messageMap = remoteMessage.getData();
6871
if (messageMap.containsKey(Constants.Keys.PUSH_MESSAGE_TEXT)) {
69-
LeanplumPushService.handleNotification(this, getBundle(messageMap));
72+
LeanplumPushService.handleNotification(getApplicationContext(), getBundle(messageMap));
7073
}
7174
Log.i("Received: " + messageMap.toString());
7275
} catch (Throwable t) {

AndroidSDKPush/src/main/java/com/leanplum/LeanplumPushService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import java.util.List;
5858
import java.util.Map;
5959
import java.util.Random;
60+
import java.util.concurrent.CountDownLatch;
6061

6162
/**
6263
* Leanplum push notification service class, handling initialization, opening, showing, integration
@@ -367,6 +368,9 @@ private static void showNotification(Context context, final Bundle message) {
367368
// Check if we have a chained message, and if it exists in var cache.
368369
if (ActionContext.shouldForceContentUpdateForChainedMessage(
369370
JsonConverter.fromJson(message.getString(Keys.PUSH_MESSAGE_ACTION)))) {
371+
372+
final CountDownLatch countDownLatch = new CountDownLatch(1);
373+
370374
final int currentNotificationId = notificationId;
371375
final Notification.Builder currentNotificationBuilder = notificationBuilder;
372376
final NotificationCompat.Builder currentNotificationCompatBuilder = notificationCompatBuilder;
@@ -378,8 +382,10 @@ public void variablesChanged() {
378382
} else {
379383
notificationManager.notify(currentNotificationId, currentNotificationCompatBuilder.build());
380384
}
385+
countDownLatch.countDown();
381386
}
382387
});
388+
countDownLatch.await();
383389
} else {
384390
if (notificationBuilder != null) {
385391
notificationManager.notify(notificationId, notificationBuilder.build());

AndroidSDKTests/src/test/java/com/leanplum/LeanplumTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ public void testCrashes() throws Exception {
437437

438438
Context currentCotext = Leanplum.getContext();
439439
assertNotNull(currentCotext);
440-
LeanplumEventDataManager.init(Leanplum.getContext());
440+
LeanplumEventDataManager.sharedInstance();
441441

442442
// Add two events to database.
443443
RequestOld request1 = new RequestOld("POST", Constants.Methods.GET_INBOX_MESSAGES, null);

AndroidSDKTests/src/test/java/com/leanplum/__setup/AbstractTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ public void before() throws Exception {
129129
// Mock with our executor which will run on main thread.
130130
ReflectionHelpers.setStaticField(Util.class, "asyncExecutor", new SynchronousExecutor());
131131
ReflectionHelpers.setStaticField(Util.class, "singleThreadExecutor", new SynchronousExecutor());
132-
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "databaseManager", null);
133-
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "database", null);
132+
133+
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "instance", null);
134134
// Get and set application context.
135135
mContext = RuntimeEnvironment.application;
136136
Leanplum.setApplicationContext(mContext);

AndroidSDKTests/src/test/java/com/leanplum/internal/LeanplumEventDataManagerTest.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ public void setUp() {
6767
Leanplum.setApplicationContext(this.mContext);
6868
}
6969

70-
/**
71-
* Test for {@link LeanplumEventDataManager.LeanplumDataBaseManager#migrateFromSharedPreferences(
72-
*SQLiteDatabase)} that should migrate data from shared preferences to SQLite.
73-
*/
7470
@Test
7571
public void migrateFromSharedPreferencesTest() {
7672
setDatabaseToNull();
@@ -99,16 +95,16 @@ public void migrateFromSharedPreferencesTest() {
9995
assertEquals(3, count);
10096

10197
// Create database. That should also migrate data from shared preferences.
102-
LeanplumEventDataManager.init(mContext);
98+
LeanplumEventDataManager.sharedInstance();
10399
// Assert in database after migration 3 events.
104-
assertEquals(count, LeanplumEventDataManager.getEventsCount());
100+
assertEquals(count, LeanplumEventDataManager.sharedInstance().getEventsCount());
105101

106102
// Assert count 0 after data migration.
107103
count = preferences.getInt(Constants.Defaults.COUNT_KEY, 0);
108104
assertEquals(0, count);
109105

110106
// Get list of events from SQLite.
111-
List<Map<String, Object>> events = LeanplumEventDataManager.getEvents(3);
107+
List<Map<String, Object>> events = LeanplumEventDataManager.sharedInstance().getEvents(3);
112108
assertNotNull(events);
113109
assertEquals(3, events.size());
114110
// Checks that all events inserted to SQLite in order.
@@ -120,10 +116,7 @@ public void migrateFromSharedPreferencesTest() {
120116
}
121117

122118
public static void setDatabaseToNull(){
123-
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "databaseManager",
124-
null);
125-
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "database",
126-
null);
119+
ReflectionHelpers.setStaticField(LeanplumEventDataManager.class, "instance", null);
127120
}
128121
}
129122

0 commit comments

Comments
 (0)