Skip to content

Commit

Permalink
Merge pull request #144 from Countly/SDK-916
Browse files Browse the repository at this point in the history
[SDK-916] : Added ability to record direct requests
  • Loading branch information
ArtursKadikis authored Aug 31, 2022
2 parents dea8774 + 2365c51 commit 88741d4
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 22.02.2
* Added ability to record direct requests.

## 22.02.1
* Fixed bug that would be opening two intents for MainActivity when clicking on a push notification with a deep-link.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public void onClickViewOther10(View v) {
Countly.sharedInstance().requestQueue().attemptToSendStoredRequests();
}

public void onAddDirectRequestClick(View v) {
Map<String, String> requestMap = new HashMap<>();
requestMap.put("city", "Istanbul");
requestMap.put("country_code", "TR");
requestMap.put("ip_address", "41.0082,28.9784");
requestMap.put("events", "[{\"key\":\"test\",\"count\":201,\"sum\":2010,\"dur\":2010,\"segmentation\":{\"trickplay\":[{\"type\":\"FF\",\"start_time\":123456789,\"end_time\":123456789},{\"type\":\"skip\",\"start_time\":123456789,\"end_time\":123456789},{\"type\":\"resume_play\",\"start_time\":123456789,\"end_time\":123456789}]}}]");
Countly.sharedInstance().requestQueue().addDirectRequest(requestMap);
}

public void onClickTestcrashFilterSample(View v) {
Countly.sharedInstance().crashes().recordUnhandledException(new Throwable("A really secret exception"));
}
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/layout/activity_example_others.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
android:onClick="onClickViewOther10"
android:text="Do Stored Requests" />

<Button
android:id="@+id/button70"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onAddDirectRequestClick"
android:text="Add direct Request" />

<Button
android:id="@+id/button64"
android:layout_width="match_parent"
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 @@ android.useAndroidX=true
android.enableJetifier=true

# RELEASE FIELD SECTION
VERSION_NAME=22.02.1
VERSION_NAME=22.02.2
GROUP=ly.count.android

POM_URL=https://github.com/Countly/countly-sdk-android
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ public void testPrepareCommonRequest() {
break;
case "sdk_version":
if (a == 0) {
Assert.assertTrue(pair[1].equals("22.02.1"));
Assert.assertTrue(pair[1].equals("22.02.2"));
} else if (a == 1) {
Assert.assertTrue(pair[1].equals("123sdf.v-213"));
}
Expand Down
37 changes: 34 additions & 3 deletions sdk/src/main/java/ly/count/android/sdk/ConnectionQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ public void sendIndirectAttribution(@NonNull String attributionObj) {
return;
}

if(attributionObj.isEmpty()) {
if (attributionObj.isEmpty()) {
L.e("[Connection Queue] provided attribution ID is not valid, aborting");
return;
}
Expand All @@ -364,7 +364,7 @@ public void sendDirectAttributionTest(@NonNull String attributionData) {
return;
}

if(attributionData.isEmpty()) {
if (attributionData.isEmpty()) {
L.w("[Connection Queue] sendDirectAttributionTest, attribution not sent, data is empty");
return;
}
Expand Down Expand Up @@ -429,6 +429,37 @@ public void sendCrashReport(@NonNull final String crashData) {
tick();
}

/**
* Send a direct request to server
* We have encoded each key and value as http url encoded.
* You need to check the required consents by yourself before this call, we are just checking that if any consent is given.
*
* @param requestData key value pair for direct request
*/
public void sendDirectRequest(@NonNull final Map<String, String> requestData) {
checkInternalState();
L.d("[Connection Queue] sendDirectRequest");

if (!consentProvider.anyConsentGiven()) {
L.d("[Connection Queue] request ignored, no consent given");
return;
}

StringBuilder data = new StringBuilder(prepareCommonRequestData());
for (Map.Entry<String, String> entry : requestData.entrySet()) {
if (data.length() > 0) {
data.append("&");
}
data.append(String.format("%s=%s",
UtilsNetworking.urlEncodeString(entry.getKey()),
UtilsNetworking.urlEncodeString(entry.getValue())
));
}

addRequestToQueue(data.toString());
tick();
}

/**
* Records the specified events and sends them to the server.
*
Expand Down Expand Up @@ -656,7 +687,7 @@ public void tick() {
L.v("[Connection Queue] tick, Not empty:[" + !isRequestQueueEmpty() + "], Has processor:[" + (connectionProcessorFuture_ == null) + "], Done or null:[" + (connectionProcessorFuture_ == null
|| connectionProcessorFuture_.isDone()) + "]");

if(!Countly.sharedInstance().isInitialized()) {
if (!Countly.sharedInstance().isInitialized()) {
//attempting to tick when the SDK is not initialized
return;
}
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 @@ -43,7 +43,7 @@ of this software and associated documentation files (the "Software"), to deal
*/
public class Countly {

private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "22.02.1";
private final String DEFAULT_COUNTLY_SDK_VERSION_STRING = "22.02.2";

/**
* Used as request meta data on every request
Expand Down
80 changes: 80 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/ModuleRequestQueue.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONObject;

public class ModuleRequestQueue extends ModuleBase implements BaseInfoProvider {
RequestQueue requestQueueInterface;
Expand All @@ -16,6 +19,18 @@ public class ModuleRequestQueue extends ModuleBase implements BaseInfoProvider {
private boolean deviceIsAppCrawler = false;//by default assume that device is not a app crawler
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
private final List<String> appCrawlerNames = new ArrayList<>(Arrays.asList("Calypso AppCrawler"));//List against which device name is checked to determine if device is app crawler
static final String APP_KEY_KEY = "app_key";
static final String HOUR_KEY = "hour";
static final String DOW_KEY = "dow";
static final String TZ_KEY = "tz";
static final String SDK_VERSION_KEY = "sdk_version";
static final String SDK_NAME_KEY = "sdk_name";
static final String DEVICE_ID_KEY = "device_id";
static final String OVVERIDE_KEY = "override_id";
static final String OLD_DEVICE_ID_KEY = "old_device_id";
static final String CHECKSUM_KEY = "checksum";
static final String CHECKSUM_256_KEY = "checksum256";
String[] preDefinedKeys = new String[] { APP_KEY_KEY, HOUR_KEY, DOW_KEY, TZ_KEY, SDK_VERSION_KEY, SDK_NAME_KEY, DEVICE_ID_KEY, OVVERIDE_KEY, OLD_DEVICE_ID_KEY, CHECKSUM_KEY, CHECKSUM_256_KEY };

ModuleRequestQueue(@NonNull Countly cly, @NonNull CountlyConfig config) {
super(cly, config);
Expand Down Expand Up @@ -217,6 +232,61 @@ synchronized public void requestQueueEraseAppKeysRequestsInternal() {
attemptToSendStoredRequestsInternal();
}

/**
* Send request data after removing the predefined keys
*/
synchronized public void addDirectRequestInternal(@NonNull Map<String, String> requestMap) {
L.i("[Countly] Calling addDirectRequest");
if (!_cly.isInitialized()) {
L.e("Countly.sharedInstance().init must be called before adding direct request, returning");
return;
}

if (!consentProvider.anyConsentGiven()) {
L.e("[ModuleRequestQueue] addDirectRequest, no consent is given, returning");
return;
}

if (requestMap == null || requestMap.isEmpty()) {
L.e("[ModuleRequestQueue] addDirectRequest, provided requestMap was null or empty, returning");
return;
}

// Filtering and removing predefined/restricted keys
Map<String, String> filteredRequestMap = new HashMap<>();
for (Map.Entry<String, String> entry : requestMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
boolean isPreDefinedKey = false;

for (String preDefinedKey : preDefinedKeys) {
if (preDefinedKey.equals(key)) {
//if it's a predefined field
isPreDefinedKey = true;
L.w("[ModuleRequestQueue] addDirectRequest, removing provided key: [" + key + "] is a restricted key.");
break;
}
}

if (!isPreDefinedKey) {
filteredRequestMap.put(key, value.toString());
}
}

if (filteredRequestMap.isEmpty()) {
L.e("[ModuleRequestQueue] addDirectRequest, filteredRequestMap was null or empty, returning");
return;
}

int requestDataCount = requestMap.size();
int filteredDataCount = filteredRequestMap.size();
int delta = requestDataCount - filteredDataCount;
if (delta > 0) {
L.w("[ModuleRequestQueue] addDirectRequest, [" + delta + "] restricted keys are removed");
}
requestQueueProvider.sendDirectRequest(filteredRequestMap);
}

@Override
void halt() {
requestQueueInterface = null;
Expand Down Expand Up @@ -300,5 +370,15 @@ public void eraseWrongAppKeyRequests() {
requestQueueEraseAppKeysRequestsInternal();
}
}

/**
* Send request data after removing the predefined keys
*/
public void addDirectRequest(@NonNull Map<String, String> requestMap) {
synchronized (_cly) {
L.i("[Countly] Calling addDirectRequest");
addDirectRequestInternal(requestMap);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import androidx.annotation.Nullable;
import java.util.Map;

interface RequestQueueProvider {
interface RequestQueueProvider {
void beginSession(boolean locationDisabled, String locationCountryCode, String locationCity, String locationGpsCoordinates, String locationIpAddress);
void updateSession(final int duration);
void changeDeviceId(String deviceId, final int duration);
Expand All @@ -23,6 +23,7 @@ interface RequestQueueProvider {
void sendAPMNetworkTrace(String networkTraceKey, Long responseTimeMs, int responseCode, int requestPayloadSize, int responsePayloadSize, Long startMs, Long endMs);
void sendAPMAppStart(long durationMs, Long startMs, Long endMs);
void sendAPMScreenTime(boolean recordForegroundTime, long durationMs, Long startMs, Long endMs);
void sendDirectRequest(@NonNull final Map<String, String> requestData);

//todo these should be moved or replaced in the future
boolean queueContainsTemporaryIdItems();
Expand Down

0 comments on commit 88741d4

Please sign in to comment.