Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 25.4.9
* Added a new config option `disableViewRestartForManualRecording()` to disable auto close/restart behavior of manual views on app background/foreground actions.

## 25.4.8
* Mitigated an issue where push notifications were not shown when consent was not required and app was killed.

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ org.gradle.configureondemand=true
android.useAndroidX=true
android.enableJetifier=true
# RELEASE FIELD SECTION
VERSION_NAME=25.4.8
VERSION_NAME=25.4.9
GROUP=ly.count.android
POM_URL=https://github.com/Countly/countly-sdk-android
POM_SCM_URL=https://github.com/Countly/countly-sdk-android
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2062,6 +2062,92 @@ public void autoViewTracking_consentRemoval() throws JSONException {
Assert.assertEquals(9, TestUtils.getCurrentRQ().length);
}

/**
* "startView" with bg/fg switch case
* - Validate that after an auto stopped view is started and app gone to background
* running view should not stop because behavior is disabled
* - After coming from the background to foreground no view should be started because behavior is disabled
*
* @throws InterruptedException if the thread is interrupted
* @throws JSONException if the JSON is not valid
*/
@Test
public void startView_restartAfterActivityComesFromForeground_behaviorDisabled() throws InterruptedException, JSONException {
CountlyConfig countlyConfig = TestUtils.createScenarioEventIDConfig(TestUtils.incrementalViewIdGenerator(), TestUtils.incrementalEventIdGenerator());
countlyConfig.setApplication(null);
countlyConfig.setContext(TestUtils.getContext());
countlyConfig.disableViewRestartForManualRecording();
countlyConfig.setEventQueueSizeToSend(1);
Countly countly = new Countly().init(countlyConfig);

Activity activity = mock(Activity.class);

TestUtils.assertRQSize(0);

countly.onStart(activity);
countly.views().startView("test");

ModuleSessionsTests.validateSessionBeginRequest(0, TestUtils.commonDeviceId);
ModuleEventsTests.validateEventInRQ(TestUtils.commonDeviceId, ModuleViews.ORIENTATION_EVENT_KEY, null, 1, 0.0, 0.0, "ide1", "_CLY_", "", "_CLY_", 1, 3, 0, 1);
validateView("test", 0.0, 2, 3, true, true, null, "idv1", "");

Thread.sleep(1000);

countly.onStop();
ModuleSessionsTests.validateSessionEndRequest(3, 1, TestUtils.commonDeviceId);
Thread.sleep(1000);
countly.onStart(activity);

ModuleSessionsTests.validateSessionBeginRequest(4, TestUtils.commonDeviceId);
ModuleEventsTests.validateEventInRQ(TestUtils.commonDeviceId, ModuleViews.ORIENTATION_EVENT_KEY, null, 1, 0.0, 0.0, "ide2", "_CLY_", "idv1", "_CLY_", 5, 6, 0, 1);

Thread.sleep(1000);

countly.views().stopViewWithName("test");
validateView("test", 3.0, 6, 7, false, false, null, "idv1", "");
countly.onStop();

ModuleSessionsTests.validateSessionEndRequest(7, 1, TestUtils.commonDeviceId);
TestUtils.assertRQSize(8);
}

/**
* Auto view tracking with restart is disabled for manual views
* Validate that after an auto stopped view is started and app gone to background
* running view should stop because auto views are not affected by the disabled behavior
*
* @throws JSONException if the JSON is not valid
*/
@Test
public void autoViewTracking_restartDisabledForManualViews() throws JSONException, InterruptedException {
CountlyConfig countlyConfig = TestUtils.createBaseConfig(TestUtils.getContext());
countlyConfig.setLoggingEnabled(true);
countlyConfig.enableAutomaticViewTracking();
countlyConfig.disableViewRestartForManualRecording();
countlyConfig.setEventQueueSizeToSend(1);

Countly countly = new Countly().init(countlyConfig);

Activity activity = Mockito.mock(Activity.class);
countly.onStart(activity);

ModuleSessionsTests.validateSessionBeginRequest(0, TestUtils.commonDeviceId);
ModuleEventsTests.validateEventInRQ("[CLY]_orientation", TestUtils.map("mode", "portrait"), 1, 0, 0, 1, 3);
validateView(activity.getClass().getName(), 0.0, 2, 3, true, true, TestUtils.map(), "_CLY_", "_CLY_", null);
Thread.sleep(1000);
countly.onStop();
ModuleSessionsTests.validateSessionEndRequest(3, 1, TestUtils.commonDeviceId);
validateView(activity.getClass().getName(), 1.0, 4, 5, false, false, null, "_CLY_", "_CLY_");

countly.onStart(activity);
Thread.sleep(1000);
ModuleSessionsTests.validateSessionBeginRequest(5, TestUtils.commonDeviceId);
ModuleEventsTests.validateEventInRQ("[CLY]_orientation", TestUtils.map("mode", "portrait"), 1, 0, 0, 6, 8);

validateView(activity.getClass().getName(), 0.0, 7, 8, true, true, TestUtils.map(), "_CLY_", "_CLY_", null);
Assert.assertEquals(8, TestUtils.getCurrentRQ().length);
}

static void validateView(String viewName, Double viewDuration, int idx, int size, boolean start, boolean visit, Map<String, Object> customSegmentation, String id, String pvid) throws JSONException {
validateView(viewName, viewDuration, idx, size, start, visit, customSegmentation, id, pvid, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class TestUtils {
public final static String commonAppKey = "appkey";
public final static String commonDeviceId = "1234";
public final static String SDK_NAME = "java-native-android";
public final static String SDK_VERSION = "25.4.8";
public final static String SDK_VERSION = "25.4.9";
public static final int MAX_THREAD_COUNT_PER_STACK_TRACE = 50;

public static class Activity2 extends Activity {
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/main/java/ly/count/android/sdk/Countly.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ of this software and associated documentation files (the "Software"), to deal
*/
public class Countly {

private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "25.4.8";
private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "25.4.9";
/**
* Used as request meta data on every request
*/
Expand Down
16 changes: 16 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/CountlyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ public class CountlyConfig {
// If set to true, the SDK will not store the default push consent state on initialization for not requiring consent
boolean disableStoringDefaultPushConsent = false;

// If set to true, the SDK will not restart manual views while switching between foreground and background
boolean disableViewRestartForManualRecording = false;

/**
* THIS VARIABLE SHOULD NOT BE USED
* IT IS ONLY FOR INTERNAL TESTING
Expand Down Expand Up @@ -1116,6 +1119,19 @@ public synchronized CountlyConfig disableStoringDefaultPushConsent() {
return this;
}

/**
* Disable view restart when manual view recording is done.
* By default, if automatic view tracking is not enabled and a manual view is recorded,
* the SDK was restarting the views to properly track the view duration in bg/fg transitions.
* Now, with this option enabled, the SDK will not restart the views on manual view recording.
*
* @return Returns the same config object for convenient linking
*/
public synchronized CountlyConfig disableViewRestartForManualRecording() {
this.disableViewRestartForManualRecording = true;
return this;
}

/**
* APM configuration interface to be used with CountlyConfig
*/
Expand Down
7 changes: 4 additions & 3 deletions sdk/src/main/java/ly/count/android/sdk/ModuleViews.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class ModuleViews extends ModuleBase implements ViewIdProvider {
String currentViewName = "";
private boolean firstView = true;
boolean autoViewTracker = false;
boolean restartManualViews = true;
boolean automaticTrackingShouldUseShortName = false;

//track orientation changes
Expand Down Expand Up @@ -84,6 +85,7 @@ static class ViewData {
setGlobalViewSegmentationInternal(config.globalViewSegmentation);
autoTrackingActivityExceptions = config.automaticViewTrackingExceptions;
trackOrientationChanges = config.trackOrientationChange;
restartManualViews = !config.disableViewRestartForManualRecording;

viewsInterface = new Views();
}
Expand Down Expand Up @@ -552,7 +554,7 @@ void onActivityStopped(int updatedActivityCount) {
}
}

if (updatedActivityCount <= 0) {
if (updatedActivityCount <= 0 && (autoViewTracker || restartManualViews)) {
//if we go to the background, stop all running views
stopRunningViewsAndSend();
}
Expand Down Expand Up @@ -587,8 +589,7 @@ void onActivityStarted(Activity activity, int updatedActivityCount) {
}
}

if (updatedActivityCount == 1) {
//if we go to the background, stop all running views
if (updatedActivityCount == 1 && (autoViewTracker || restartManualViews)) {
startStoppedViews();
}
}
Expand Down
Loading