Skip to content

Commit cf1f4ee

Browse files
authored
Merge pull request #271 from adjust/v4112
Version 4.11.2
2 parents eb7f762 + 977e31f commit cf1f4ee

File tree

24 files changed

+239
-67
lines changed

24 files changed

+239
-67
lines changed

Adjust/adjust/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apply plugin: 'com.android.library'
22

33
def getVersionName() {
4-
return "4.11.1"
4+
return "4.11.2"
55
}
66

77
android {

Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import android.content.pm.PackageManager;
1616
import android.content.pm.ResolveInfo;
1717
import android.net.Uri;
18+
import android.net.UrlQuerySanitizer;
1819
import android.os.Handler;
1920
import android.util.*;
2021

@@ -119,6 +120,8 @@ public class InternalState {
119120
boolean background;
120121
boolean delayStart;
121122
boolean updatePackages;
123+
boolean firstLaunch;
124+
boolean sessionResponseProcessed;
122125

123126
public boolean isEnabled() {
124127
return enabled;
@@ -155,6 +158,14 @@ public boolean isToStartNow() {
155158
public boolean isToUpdatePackages() {
156159
return updatePackages;
157160
}
161+
162+
public boolean isFirstLaunch() {
163+
return firstLaunch;
164+
}
165+
166+
public boolean isSessionResponseProcessed() {
167+
return sessionResponseProcessed;
168+
}
158169
}
159170

160171
private ActivityHandler(AdjustConfig adjustConfig) {
@@ -178,6 +189,8 @@ private ActivityHandler(AdjustConfig adjustConfig) {
178189
internalState.delayStart = false;
179190
// does not need to update packages by default
180191
internalState.updatePackages = false;
192+
// does not have the session response by default
193+
internalState.sessionResponseProcessed = false;
181194

182195
scheduledExecutor.submit(new Runnable() {
183196
@Override
@@ -579,6 +592,24 @@ public void run() {
579592
});
580593
}
581594

595+
public void foregroundTimerFired() {
596+
scheduledExecutor.submit(new Runnable() {
597+
@Override
598+
public void run() {
599+
foregroundTimerFiredI();
600+
}
601+
});
602+
}
603+
604+
public void backgroundTimerFired() {
605+
scheduledExecutor.submit(new Runnable() {
606+
@Override
607+
public void run() {
608+
backgroundTimerFiredI();
609+
}
610+
});
611+
}
612+
582613
public String getAdid() {
583614
if (activityState == null) {
584615
return null;
@@ -631,6 +662,9 @@ private void initI() {
631662
if (activityState != null) {
632663
internalState.enabled = activityState.enabled;
633664
internalState.updatePackages = activityState.updatePackages;
665+
internalState.firstLaunch = false;
666+
} else {
667+
internalState.firstLaunch = true; // first launch if activity state is null
634668
}
635669

636670
readConfigFile(adjustConfig.context);
@@ -669,18 +703,18 @@ private void initI() {
669703
new Runnable() {
670704
@Override
671705
public void run() {
672-
foregroundTimerFiredI();
706+
foregroundTimerFired();
673707
}
674708
}, FOREGROUND_TIMER_START, FOREGROUND_TIMER_INTERVAL, FOREGROUND_TIMER_NAME);
675709

676710
// create background timer
677711
if (adjustConfig.sendInBackground) {
678712
logger.info("Send in background configured");
679713

680-
backgroundTimer = new TimerOnce(scheduledExecutor, new Runnable() {
714+
backgroundTimer = new TimerOnce(new Runnable() {
681715
@Override
682716
public void run() {
683-
backgroundTimerFiredI();
717+
backgroundTimerFired();
684718
}
685719
}, BACKGROUND_TIMER_NAME);
686720
}
@@ -692,10 +726,10 @@ public void run() {
692726
{
693727
logger.info("Delay start configured");
694728
internalState.delayStart = true;
695-
delayStartTimer = new TimerOnce(scheduledExecutor, new Runnable() {
729+
delayStartTimer = new TimerOnce(new Runnable() {
696730
@Override
697731
public void run() {
698-
sendFirstPackagesI();
732+
sendFirstPackages();
699733
}
700734
}, DELAY_START_TIMER_NAME);
701735
}
@@ -823,9 +857,12 @@ private void processSessionI() {
823857
private void checkAttributionStateI() {
824858
if (!checkActivityStateI(activityState)) { return; }
825859

826-
// if it's a new session
827-
if (activityState.subsessionCount <= 1) {
828-
return;
860+
// if it's the first launch
861+
if (internalState.isFirstLaunch()) {
862+
// and it hasn't received the session response
863+
if (!internalState.isSessionResponseProcessed()) {
864+
return;
865+
}
829866
}
830867

831868
// if there is already an attribution saved and there was no attribution being asked
@@ -929,6 +966,9 @@ private void launchSessionResponseTasksI(SessionResponseData sessionResponseData
929966

930967
// launch Session tracking listener if available
931968
launchSessionResponseListenerI(sessionResponseData, handler);
969+
970+
// mark session response has proccessed
971+
internalState.sessionResponseProcessed = true;
932972
}
933973

934974
private void launchSessionResponseListenerI(final SessionResponseData sessionResponseData, Handler handler) {
@@ -1053,7 +1093,15 @@ private void sendReferrerI(String referrer, long clickTime) {
10531093
if (referrer == null || referrer.length() == 0 ) {
10541094
return;
10551095
}
1056-
PackageBuilder clickPackageBuilder = queryStringClickPackageBuilderI(referrer);
1096+
1097+
logger.verbose("Referrer to parse (%s)", referrer);
1098+
1099+
UrlQuerySanitizer querySanitizer = new UrlQuerySanitizer();
1100+
querySanitizer.setUnregisteredParameterValueSanitizer(UrlQuerySanitizer.getAllButNulLegal());
1101+
querySanitizer.setAllowUnregisteredParamaters(true);
1102+
querySanitizer.parseQuery(referrer);
1103+
1104+
PackageBuilder clickPackageBuilder = queryStringClickPackageBuilderI(querySanitizer.getParameterList());
10571105

10581106
if (clickPackageBuilder == null) {
10591107
return;
@@ -1071,13 +1119,15 @@ private void readOpenUrlI(Uri url, long clickTime) {
10711119
return;
10721120
}
10731121

1074-
String queryString = url.getQuery();
1122+
String urlString = url.toString();
1123+
logger.verbose("Url to parse (%s)", url);
10751124

1076-
if (queryString == null && url.toString().length() > 0) {
1077-
queryString = "";
1078-
}
1125+
UrlQuerySanitizer querySanitizer = new UrlQuerySanitizer();
1126+
querySanitizer.setUnregisteredParameterValueSanitizer(UrlQuerySanitizer.getAllButNulLegal());
1127+
querySanitizer.setAllowUnregisteredParamaters(true);
1128+
querySanitizer.parseUrl(urlString);
10791129

1080-
PackageBuilder clickPackageBuilder = queryStringClickPackageBuilderI(queryString);
1130+
PackageBuilder clickPackageBuilder = queryStringClickPackageBuilderI(querySanitizer.getParameterList());
10811131
if (clickPackageBuilder == null) {
10821132
return;
10831133
}
@@ -1089,20 +1139,19 @@ private void readOpenUrlI(Uri url, long clickTime) {
10891139
sdkClickHandler.sendSdkClick(clickPackage);
10901140
}
10911141

1092-
private PackageBuilder queryStringClickPackageBuilderI(String queryString) {
1093-
if (queryString == null) {
1142+
private PackageBuilder queryStringClickPackageBuilderI(
1143+
List<UrlQuerySanitizer.ParameterValuePair> queryList) {
1144+
if (queryList == null) {
10941145
return null;
10951146
}
10961147

10971148
Map<String, String> queryStringParameters = new LinkedHashMap<String, String>();
10981149
AdjustAttribution queryStringAttribution = new AdjustAttribution();
10991150

1100-
logger.verbose("Reading query string (%s)", queryString);
1101-
1102-
String[] queryPairs = queryString.split("&");
1103-
1104-
for (String pair : queryPairs) {
1105-
readQueryStringI(pair, queryStringParameters, queryStringAttribution);
1151+
for (UrlQuerySanitizer.ParameterValuePair parameterValuePair : queryList) {
1152+
readQueryStringI(parameterValuePair.mParameter,
1153+
parameterValuePair.mValue,
1154+
queryStringParameters, queryStringAttribution);
11061155
}
11071156

11081157
String reftag = queryStringParameters.remove(Constants.REFTAG);
@@ -1116,17 +1165,13 @@ private PackageBuilder queryStringClickPackageBuilderI(String queryString) {
11161165
return builder;
11171166
}
11181167

1119-
private boolean readQueryStringI(String queryString,
1168+
private boolean readQueryStringI(String key, String value,
11201169
Map<String, String> extraParameters,
11211170
AdjustAttribution queryStringAttribution) {
1122-
String[] pairComponents = queryString.split("=");
1123-
if (pairComponents.length != 2) return false;
1124-
1125-
String key = pairComponents[0];
1126-
if (!key.startsWith(ADJUST_PREFIX)) return false;
1171+
if (key == null || value == null) { return false; }
11271172

1128-
String value = pairComponents[1];
1129-
if (value.length() == 0) return false;
1173+
// parameter key does not start with "adjust_"
1174+
if (!key.startsWith(ADJUST_PREFIX)) { return false; }
11301175

11311176
String keyWOutPrefix = key.substring(ADJUST_PREFIX.length());
11321177
if (keyWOutPrefix.length() == 0) return false;

Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ public AttributionHandler(IActivityHandler activityHandler,
5050
scheduledExecutor = new CustomScheduledExecutor("AttributionHandler", false);
5151
logger = AdjustFactory.getLogger();
5252

53-
timer = new TimerOnce(scheduledExecutor, new Runnable() {
53+
timer = new TimerOnce(new Runnable() {
5454
@Override
5555
public void run() {
56-
sendAttributionRequestI();
56+
sendAttributionRequest();
5757
}
5858
}, ATTRIBUTION_TIMER_NAME);
5959

@@ -117,6 +117,15 @@ public void resumeSending() {
117117
paused = false;
118118
}
119119

120+
public void sendAttributionRequest() {
121+
scheduledExecutor.submit(new Runnable() {
122+
@Override
123+
public void run() {
124+
sendAttributionRequestI();
125+
}
126+
});
127+
}
128+
120129
private void getAttributionI(long delayInMilliseconds) {
121130
// don't reset if new time is shorter than last one
122131
if (timer.getFireIn() > delayInMilliseconds) {

Adjust/adjust/src/main/java/com/adjust/sdk/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public interface Constants {
2929
String BASE_URL = "https://app.adjust.com";
3030
String SCHEME = "https";
3131
String AUTHORITY = "app.adjust.com";
32-
String CLIENT_SDK = "android4.11.1";
32+
String CLIENT_SDK = "android4.11.2";
3333
String LOGTAG = "Adjust";
3434
String REFTAG = "reftag";
3535
String DEEPLINK = "deeplink";

Adjust/adjust/src/main/java/com/adjust/sdk/DeviceInfo.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.os.Build;
1212
import android.util.DisplayMetrics;
1313

14+
import java.util.Date;
1415
import java.util.Locale;
1516
import java.util.Map;
1617

@@ -51,6 +52,8 @@ class DeviceInfo {
5152
String abi;
5253
String buildName;
5354
String vmInstructionSet;
55+
String appInstallTime;
56+
String appUpdateTime;
5457
Map<String, String> pluginKeys;
5558

5659
DeviceInfo(Context context, String sdkPrefix) {
@@ -88,6 +91,8 @@ class DeviceInfo {
8891
abi = getABI();
8992
buildName = getBuildName();
9093
vmInstructionSet = getVmInstructionSet();
94+
appInstallTime = getAppInstallTime(context);
95+
appUpdateTime = getAppUpdateTime(context);
9196
}
9297

9398
private String getMacAddress(Context context, boolean isGooglePlayServicesAvailable) {
@@ -294,4 +299,30 @@ private String getVmInstructionSet() {
294299
String instructionSet = Util.getVmInstructionSet();
295300
return instructionSet;
296301
}
302+
303+
private String getAppInstallTime(Context context) {
304+
try {
305+
PackageManager packageManager = context.getPackageManager();
306+
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
307+
308+
String appInstallTime = Util.dateFormatter.format(new Date(packageInfo.firstInstallTime));
309+
310+
return appInstallTime;
311+
} catch (Exception ex) {
312+
return null;
313+
}
314+
}
315+
316+
private String getAppUpdateTime(Context context) {
317+
try {
318+
PackageManager packageManager = context.getPackageManager();
319+
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
320+
321+
String appInstallTime = Util.dateFormatter.format(new Date(packageInfo.lastUpdateTime));
322+
323+
return appInstallTime;
324+
} catch (Exception ex) {
325+
return null;
326+
}
327+
}
297328
}

Adjust/adjust/src/main/java/com/adjust/sdk/PackageBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public ActivityPackage buildSessionPackage(SessionParameters sessionParameters,
7575
Map<String, String> parameters = getDefaultParameters();
7676
PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval);
7777
PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker);
78+
PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime);
79+
PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime);
7880

7981
if (!isInDelay) {
8082
PackageBuilder.addMapJson(parameters, CALLBACK_PARAMETERS, sessionParameters.callbackParameters);
@@ -141,7 +143,6 @@ public ActivityPackage buildInfoPackage(String source) {
141143
Map<String, String> parameters = getIdsParameters();
142144

143145
PackageBuilder.addString(parameters, "source", source);
144-
injectAttribution(parameters);
145146

146147
ActivityPackage clickPackage = getDefaultActivityPackage(ActivityKind.INFO);
147148
clickPackage.setPath("/sdk_info");

Adjust/adjust/src/main/java/com/adjust/sdk/TimerOnce.java

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
* Created by pfms on 08/05/15.
99
*/
1010
public class TimerOnce {
11-
private WeakReference<CustomScheduledExecutor> scheduledExecutorWeakRef;
11+
private CustomScheduledExecutor executor;
12+
1213
private ScheduledFuture waitingTask;
1314
private String name;
1415
private Runnable command;
1516
private ILogger logger;
1617

17-
public TimerOnce(CustomScheduledExecutor scheduler, Runnable command, String name) {
18+
public TimerOnce(Runnable command, String name) {
1819
this.name = name;
19-
this.scheduledExecutorWeakRef = new WeakReference<CustomScheduledExecutor>(scheduler);
20+
this.executor = new CustomScheduledExecutor(name, true);
2021
this.command = command;
2122
this.logger = AdjustFactory.getLogger();
2223
}
@@ -25,16 +26,11 @@ public void startIn(long fireIn) {
2526
// cancel previous
2627
cancel(false);
2728

28-
CustomScheduledExecutor scheduledExecutor = scheduledExecutorWeakRef.get();
29-
if (scheduledExecutor == null) {
30-
return;
31-
}
32-
3329
String fireInSeconds = Util.SecondsDisplayFormat.format(fireIn / 1000.0);
3430

3531
logger.verbose("%s starting. Launching in %s seconds", name, fireInSeconds);
3632

37-
waitingTask = scheduledExecutor.schedule(new Runnable() {
33+
waitingTask = executor.schedule(new Runnable() {
3834
@Override
3935
public void run() {
4036
logger.verbose("%s fired", name);
@@ -66,9 +62,7 @@ public void cancel() {
6662

6763
public void teardown() {
6864
cancel(true);
69-
if (scheduledExecutorWeakRef != null) {
70-
scheduledExecutorWeakRef.clear();
71-
}
72-
scheduledExecutorWeakRef = null;
65+
66+
executor = null;
7367
}
7468
}

0 commit comments

Comments
 (0)