Skip to content

Commit eff7fe2

Browse files
authored
feat: support lazy initialization of the SDK (#74)
1 parent 60857e5 commit eff7fe2

File tree

13 files changed

+269
-170
lines changed

13 files changed

+269
-170
lines changed

clickstream/src/main/java/software/aws/solution/clickstream/ActivityLifecycleManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner, @NonNull Life
155155
if (isNewSession) {
156156
autoRecordEventClient.handleSessionStart();
157157
autoRecordEventClient.setIsEntrances();
158+
sessionClient.startSession();
158159
recordScreenViewAfterSessionStart();
159160
}
160161
}

clickstream/src/main/java/software/aws/solution/clickstream/client/AutoRecordEventClient.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ public class AutoRecordEventClient {
4949
*/
5050
private boolean isFirstTime = true;
5151

52+
/**
53+
* whether the app has entered the background at least once.
54+
*/
55+
private boolean isAppEndCalled = false;
56+
5257
/**
5358
* current screen is entrances.
5459
*/
@@ -252,10 +257,12 @@ public void handleAppStart() {
252257
preferences.putBoolean("isFirstOpen", false);
253258
isFirstOpen = false;
254259
}
255-
final AnalyticsEvent event =
256-
this.clickstreamContext.getAnalyticsClient().createEvent(Event.PresetEvent.APP_START);
257-
event.addAttribute(Event.ReservedAttribute.IS_FIRST_TIME, isFirstTime);
258-
this.clickstreamContext.getAnalyticsClient().recordEvent(event);
260+
if (isFirstTime || isAppEndCalled) {
261+
final AnalyticsEvent event =
262+
this.clickstreamContext.getAnalyticsClient().createEvent(Event.PresetEvent.APP_START);
263+
event.addAttribute(Event.ReservedAttribute.IS_FIRST_TIME, isFirstTime);
264+
this.clickstreamContext.getAnalyticsClient().recordEvent(event);
265+
}
259266
isFirstTime = false;
260267
}
261268

@@ -275,6 +282,7 @@ public void handleAppEnd() {
275282
final AnalyticsEvent event =
276283
this.clickstreamContext.getAnalyticsClient().createEvent(Event.PresetEvent.APP_END);
277284
this.clickstreamContext.getAnalyticsClient().recordEvent(event);
285+
isAppEndCalled = true;
278286
}
279287

280288
/**

clickstream/src/main/java/software/aws/solution/clickstream/client/ClickstreamManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,27 @@ public ClickstreamManager(@NonNull final ClickstreamConfiguration config) {
6363
}
6464
LOG.debug(String.format(Locale.US,
6565
"Clickstream SDK(%s) initialization successfully completed", BuildConfig.VERSION_NAME));
66+
this.autoRecordEventClient.handleAppStart();
67+
handleSessionStart();
6668
} catch (final RuntimeException runtimeException) {
6769
LOG.error(String.format(Locale.US,
6870
"Cannot initialize Clickstream SDK %s", runtimeException.getMessage()));
6971
throw new AmazonClientException(runtimeException.getLocalizedMessage());
7072
}
7173
}
7274

75+
/**
76+
* handle session start after SDK initialize.
77+
*/
78+
private void handleSessionStart() {
79+
boolean isNewSession = sessionClient.initialSession();
80+
if (isNewSession) {
81+
autoRecordEventClient.handleSessionStart();
82+
autoRecordEventClient.setIsEntrances();
83+
sessionClient.startSession();
84+
}
85+
}
86+
7387
/**
7488
* Enable track app exception.
7589
*/

clickstream/src/main/java/software/aws/solution/clickstream/client/Session.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public final class Session {
5858
private Long pauseTime;
5959
private final int sessionIndex;
6060

61+
private boolean isStarted;
62+
6163
/**
6264
* CONSTRUCTOR - ACTUAL Used by SessionClient.
6365
*
@@ -118,6 +120,22 @@ public static Session getInstance(final ClickstreamContext context, Session prev
118120
}
119121
}
120122

123+
/**
124+
* function for get session whether is started.
125+
*
126+
* @return session whether is started.
127+
*/
128+
public boolean isStarted() {
129+
return this.isStarted;
130+
}
131+
132+
/**
133+
* function for flag the session is started.
134+
*/
135+
public void start() {
136+
this.isStarted = true;
137+
}
138+
121139
/**
122140
* Pauses the session object. Generates a stop time.
123141
*/

clickstream/src/main/java/software/aws/solution/clickstream/client/SessionClient.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@ public SessionClient(@NonNull final ClickstreamContext clickstreamContext) {
6060
public synchronized boolean initialSession() {
6161
session = Session.getInstance(clickstreamContext, session);
6262
this.clickstreamContext.getAnalyticsClient().setSession(session);
63-
return session.isNewSession();
63+
return session.isNewSession() && !session.isStarted();
64+
}
65+
66+
/**
67+
* method for start the session.
68+
*/
69+
public void startSession() {
70+
session.start();
6471
}
6572

6673
/**

clickstream/src/test/java/software/aws/solution/clickstream/ActivityLifecycleManagerUnitTest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
import org.robolectric.RobolectricTestRunner;
3131
import software.aws.solution.clickstream.client.AutoRecordEventClient;
3232
import software.aws.solution.clickstream.client.ClickstreamManager;
33+
import software.aws.solution.clickstream.client.ScreenRefererTool;
3334
import software.aws.solution.clickstream.client.SessionClient;
3435
import software.aws.solution.clickstream.util.ReflectUtil;
3536

37+
import static org.junit.Assert.assertNotNull;
3638
import static org.mockito.Mockito.mock;
3739
import static org.mockito.Mockito.verify;
3840
import static org.mockito.Mockito.when;
@@ -47,6 +49,7 @@ public final class ActivityLifecycleManagerUnitTest {
4749
private Application.ActivityLifecycleCallbacks callbacks;
4850
private Log log;
4951
private LifecycleRegistry lifecycle;
52+
private LifecycleOwner lifecycleOwner;
5053
private ActivityLifecycleManager lifecycleManager;
5154

5255
/**
@@ -65,9 +68,10 @@ public void setup() throws Exception {
6568
this.callbacks = lifecycleManager;
6669
log = mock(Log.class);
6770
ReflectUtil.modifyFiled(this.callbacks, "LOG", log);
68-
69-
lifecycle = new LifecycleRegistry(mock(LifecycleOwner.class));
71+
lifecycleOwner = mock(LifecycleOwner.class);
72+
lifecycle = new LifecycleRegistry(lifecycleOwner);
7073
lifecycleManager.startLifecycleTracking(ApplicationProvider.getApplicationContext(), lifecycle);
74+
ScreenRefererTool.clear();
7175
}
7276

7377
/**
@@ -121,6 +125,7 @@ public void testContextIsInValid() {
121125
*/
122126
@Test
123127
public void testOnAppForegrounded() {
128+
assertNotNull(lifecycleOwner);
124129
when(sessionClient.initialSession()).thenReturn(true);
125130
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
126131
verify(autoRecordEventClient).updateStartEngageTimestamp();

clickstream/src/test/java/software/aws/solution/clickstream/AnalyticsClientTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void setup() throws Exception {
7070
Context context = ApplicationProvider.getApplicationContext();
7171
AWSClickstreamPluginConfiguration.Builder configurationBuilder = AWSClickstreamPluginConfiguration.builder();
7272
configurationBuilder.withAppId("demo-app")
73-
.withEndpoint("http://cs-se-serve-1qtj719j88vwn-1291141553.ap-southeast-1.elb.amazonaws.com/collect")
73+
.withEndpoint("http://example.com/collect")
7474
.withSendEventsInterval(10000);
7575
AWSClickstreamPluginConfiguration clickstreamPluginConfiguration = configurationBuilder.build();
7676
ClickstreamManager clickstreamManager =

clickstream/src/test/java/software/aws/solution/clickstream/AutoRecordEventClientTest.java

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class AutoRecordEventClientTest {
7373
private ClickstreamContext clickstreamContext;
7474
private AutoRecordEventClient client;
7575
private LifecycleRegistry lifecycle;
76+
private LifecycleOwner lifecycleOwner;
77+
private ClickstreamManager clickstreamManager;
7678

7779
/**
7880
* prepare AutoRecordEventClient and context.
@@ -83,22 +85,91 @@ public void setup() {
8385
dbUtil = new ClickstreamDBUtil(context);
8486
AWSClickstreamPluginConfiguration.Builder configurationBuilder = AWSClickstreamPluginConfiguration.builder();
8587
configurationBuilder.withAppId("demo-app")
86-
.withEndpoint("http://cs-se-serve-1qtj719j88vwn-1291141553.ap-southeast-1.elb.amazonaws.com/collect")
88+
.withEndpoint("http://example.com/collect")
8789
.withSendEventsInterval(10000)
8890
.withTrackScreenViewEvents(true)
8991
.withTrackUserEngagementEvents(true);
9092
AWSClickstreamPluginConfiguration clickstreamPluginConfiguration = configurationBuilder.build();
91-
ClickstreamManager clickstreamManager =
92-
ClickstreamManagerFactory.create(context, clickstreamPluginConfiguration);
93+
clickstreamManager = ClickstreamManagerFactory.create(context, clickstreamPluginConfiguration);
9394
client = clickstreamManager.getAutoRecordEventClient();
9495
clickstreamContext = clickstreamManager.getClickstreamContext();
9596
callbacks = new ActivityLifecycleManager(clickstreamManager);
9697

9798
ActivityLifecycleManager lifecycleManager = new ActivityLifecycleManager(clickstreamManager);
98-
lifecycle = new LifecycleRegistry(mock(LifecycleOwner.class));
99+
lifecycleOwner = mock(LifecycleOwner.class);
100+
lifecycle = new LifecycleRegistry(lifecycleOwner);
99101
lifecycleManager.startLifecycleTracking(ApplicationProvider.getApplicationContext(), lifecycle);
100102
}
101103

104+
/**
105+
* test events after SDK initialization.
106+
*
107+
* @throws Exception exception.
108+
*/
109+
@Test
110+
public void testSDKInitializationEvents() throws Exception {
111+
try (Cursor cursor = dbUtil.queryAllEvents()) {
112+
List<String> eventList = new ArrayList<>();
113+
while (cursor.moveToNext()) {
114+
String eventString = cursor.getString(2);
115+
JSONObject jsonObject = new JSONObject(eventString);
116+
String eventName = jsonObject.getString("event_type");
117+
eventList.add(eventName);
118+
}
119+
assertEquals(3, eventList.size());
120+
assertEquals(Event.PresetEvent.FIRST_OPEN, eventList.get(0));
121+
assertEquals(Event.PresetEvent.APP_START, eventList.get(1));
122+
assertEquals(Event.PresetEvent.SESSION_START, eventList.get(2));
123+
}
124+
}
125+
126+
/**
127+
* test SDK initialize with stored session.
128+
*
129+
* @throws Exception exception.
130+
*/
131+
@Test
132+
public void testSDKInitializeWithStoredSession() throws Exception {
133+
ReflectUtil.invokeMethod(clickstreamManager, "handleSessionStart");
134+
try (Cursor cursor = dbUtil.queryAllEvents()) {
135+
List<String> eventList = new ArrayList<>();
136+
while (cursor.moveToNext()) {
137+
String eventString = cursor.getString(2);
138+
JSONObject jsonObject = new JSONObject(eventString);
139+
String eventName = jsonObject.getString("event_type");
140+
eventList.add(eventName);
141+
}
142+
assertEquals(3, eventList.size());
143+
assertEquals(Event.PresetEvent.FIRST_OPEN, eventList.get(0));
144+
assertEquals(Event.PresetEvent.APP_START, eventList.get(1));
145+
assertEquals(Event.PresetEvent.SESSION_START, eventList.get(2));
146+
}
147+
}
148+
149+
/**
150+
* test SDK lazy initialization.
151+
*
152+
* @throws Exception exception.
153+
*/
154+
@Test
155+
public void testLazyInitialization() throws Exception {
156+
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
157+
try (Cursor cursor = dbUtil.queryAllEvents()) {
158+
List<String> eventList = new ArrayList<>();
159+
while (cursor.moveToNext()) {
160+
String eventString = cursor.getString(2);
161+
JSONObject jsonObject = new JSONObject(eventString);
162+
String eventName = jsonObject.getString("event_type");
163+
eventList.add(eventName);
164+
}
165+
assertEquals(3, eventList.size());
166+
assertEquals(Event.PresetEvent.FIRST_OPEN, eventList.get(0));
167+
assertEquals(Event.PresetEvent.APP_START, eventList.get(1));
168+
assertEquals(Event.PresetEvent.SESSION_START, eventList.get(2));
169+
}
170+
}
171+
172+
102173
/**
103174
* test record user engagement event after view screen more than 1 second.
104175
*
@@ -147,6 +218,7 @@ public void testEventsHaveSameSessionId() throws Exception {
147218
callbacks.onActivityCreated(activity, bundle);
148219
callbacks.onActivityStarted(activity);
149220
callbacks.onActivityResumed(activity);
221+
assertNotNull(lifecycleOwner);
150222
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
151223
try (Cursor cursor = dbUtil.queryAllEvents()) {
152224
List<String> eventList = new ArrayList<>();
@@ -864,7 +936,7 @@ public void testOSVersionForUpdate() throws Exception {
864936
@Test
865937
public void testHandleFirstOpen() throws Exception {
866938
client.handleAppStart();
867-
assertEquals(2, dbUtil.getTotalNumber());
939+
assertEquals(3, dbUtil.getTotalNumber());
868940
Cursor cursor = dbUtil.queryAllEvents();
869941
cursor.moveToFirst();
870942
String eventString = cursor.getString(2);
@@ -889,7 +961,7 @@ public void testHandleFirstOpenMultiTimes() throws Exception {
889961
client.handleAppStart();
890962
client.handleAppStart();
891963
client.handleAppStart();
892-
assertEquals(4, dbUtil.getTotalNumber());
964+
assertEquals(3, dbUtil.getTotalNumber());
893965
Cursor cursor = dbUtil.queryAllEvents();
894966
cursor.moveToFirst();
895967
String eventString = cursor.getString(2);
@@ -906,14 +978,14 @@ public void testHandleFirstOpenMultiTimes() throws Exception {
906978
*/
907979
@Test
908980
public void testHandleAppStart() throws Exception {
909-
client.handleAppStart();
910981
Activity activity1 = mock(Activity.class);
911982
Bundle bundle = mock(Bundle.class);
912983
callbacks.onActivityCreated(activity1, bundle);
913984
callbacks.onActivityStarted(activity1);
914985
callbacks.onActivityResumed(activity1);
986+
client.handleAppEnd();
915987
client.handleAppStart();
916-
assertEquals(4, dbUtil.getTotalNumber());
988+
assertEquals(6, dbUtil.getTotalNumber());
917989
try (Cursor cursor = dbUtil.queryAllEvents()) {
918990
List<JSONObject> eventList = new ArrayList<>();
919991
while (cursor.moveToNext()) {
@@ -928,10 +1000,11 @@ public void testHandleAppStart() throws Exception {
9281000
assertFalse(appStart1.has(ReservedAttribute.SCREEN_NAME));
9291001
assertFalse(appStart1.has(Event.ReservedAttribute.SCREEN_ID));
9301002

931-
assertEquals(Event.PresetEvent.SCREEN_VIEW, eventList.get(2).getString("event_type"));
932-
933-
assertEquals(Event.PresetEvent.APP_START, eventList.get(3).getString("event_type"));
934-
JSONObject appStart2 = eventList.get(3).getJSONObject("attributes");
1003+
assertEquals(Event.PresetEvent.SESSION_START, eventList.get(2).getString("event_type"));
1004+
assertEquals(Event.PresetEvent.SCREEN_VIEW, eventList.get(3).getString("event_type"));
1005+
assertEquals(Event.PresetEvent.APP_END, eventList.get(4).getString("event_type"));
1006+
assertEquals(Event.PresetEvent.APP_START, eventList.get(5).getString("event_type"));
1007+
JSONObject appStart2 = eventList.get(5).getJSONObject("attributes");
9351008
assertFalse(appStart2.getBoolean(Event.ReservedAttribute.IS_FIRST_TIME));
9361009
assertTrue(appStart2.has(ReservedAttribute.SCREEN_NAME));
9371010
assertTrue(appStart2.has(ReservedAttribute.SCREEN_UNIQUE_ID));

clickstream/src/test/java/software/aws/solution/clickstream/EventRecorderTest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public void setup() throws Exception {
121121

122122
AWSClickstreamPluginConfiguration.Builder configurationBuilder = AWSClickstreamPluginConfiguration.builder();
123123
configurationBuilder.withAppId("demo-app")
124-
.withEndpoint("http://cs-se-serve-1qtj719j88vwn-1291141553.ap-southeast-1.elb.amazonaws.com/collect")
124+
.withEndpoint("http://example.com/collect")
125125
.withSendEventsInterval(10000);
126126
AWSClickstreamPluginConfiguration clickstreamPluginConfiguration = configurationBuilder.build();
127127
ClickstreamManager clickstreamManager =
@@ -137,6 +137,8 @@ public void setup() throws Exception {
137137
(EventRecorder) ReflectUtil.newInstance(EventRecorder.class, clickstreamContext, dbUtil, executorService);
138138
log = mock(Log.class);
139139
ReflectUtil.modifyFiled(eventRecorder, "LOG", log);
140+
assertEquals(3, dbUtil.getTotalNumber());
141+
dbUtil.deleteBatchEvents(3);
140142
}
141143

142144
/**
@@ -214,7 +216,7 @@ public void testGetBatchOfEventsForOneEvent() throws Exception {
214216
String[] result = getBatchOfEvents(cursor);
215217
assertEquals(result.length, 2);
216218
assertTrue(result[0].contains(event.getEventId()));
217-
assertEquals("1", result[1]);
219+
assertEquals("4", result[1]);
218220
cursor.close();
219221
}
220222

@@ -241,7 +243,7 @@ public void testGetBatchOfEventsForOneEventReachedLimitSize() throws Exception {
241243
assertEquals(result.length, 2);
242244
assertNotNull(result[0]);
243245
assertTrue(result[0].length() > 512 * 1024);
244-
assertEquals("1", result[1]);
246+
assertEquals("4", result[1]);
245247
cursor.close();
246248
}
247249

@@ -259,7 +261,7 @@ public void testGetBatchOfEventsNotReachedDefaultLimitSize() throws Exception {
259261
String[] result = getBatchOfEvents(cursor);
260262
assertEquals(2, result.length);
261263
assertEquals(new JSONArray(result[0]).length(), 20);
262-
assertEquals("20", result[1]);
264+
assertEquals("23", result[1]);
263265
cursor.close();
264266
}
265267

@@ -277,7 +279,7 @@ public void testGetBatchOfEventsReachedLimitNumber() throws Exception {
277279
String[] result = getBatchOfEvents(cursor);
278280
assertEquals(2, result.length);
279281
assertEquals(new JSONArray(result[0]).length(), 100);
280-
assertEquals("100", result[1]);
282+
assertEquals("103", result[1]);
281283
cursor.close();
282284
}
283285

@@ -299,7 +301,7 @@ public void testGetBatchOfEventsReachedDefaultLimitSize() throws Exception {
299301
assertEquals(2, result.length);
300302
int length = new JSONArray(result[0]).length();
301303
assertTrue(length < 30);
302-
assertEquals(String.valueOf(length), result[1]);
304+
assertEquals(length, Integer.parseInt(result[1]) - 3);
303305
cursor.close();
304306
}
305307

0 commit comments

Comments
 (0)