From 9bd421ccb3c15b6d62c4b430bca04524795cf244 Mon Sep 17 00:00:00 2001 From: nonelse Date: Tue, 9 Jan 2018 15:24:54 +0100 Subject: [PATCH 01/52] Update gradle --- Adjust/adjust/build.gradle | 2 +- Adjust/example/build.gradle | 2 +- Adjust/gradle/wrapper/gradle-wrapper.properties | 4 ++-- Adjust/test/build.gradle | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Adjust/adjust/build.gradle b/Adjust/adjust/build.gradle index df3c67eb4..1a364af77 100644 --- a/Adjust/adjust/build.gradle +++ b/Adjust/adjust/build.gradle @@ -6,7 +6,7 @@ def getVersionName() { android { compileSdkVersion 26 - buildToolsVersion '26.0.2' + buildToolsVersion '27.0.1' defaultConfig { minSdkVersion 9 diff --git a/Adjust/example/build.gradle b/Adjust/example/build.gradle index 02062f5a0..d8f809875 100644 --- a/Adjust/example/build.gradle +++ b/Adjust/example/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 - buildToolsVersion '26.0.2' + buildToolsVersion '27.0.1' defaultConfig { applicationId "com.adjust.examples" diff --git a/Adjust/gradle/wrapper/gradle-wrapper.properties b/Adjust/gradle/wrapper/gradle-wrapper.properties index 2e23b91cb..6e867aa42 100644 --- a/Adjust/gradle/wrapper/gradle-wrapper.properties +++ b/Adjust/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Nov 02 14:01:25 CET 2017 +#Mon Jan 08 16:51:23 CET 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/Adjust/test/build.gradle b/Adjust/test/build.gradle index 2570c8409..6de647d84 100644 --- a/Adjust/test/build.gradle +++ b/Adjust/test/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' android { compileSdkVersion 25 - buildToolsVersion '26.0.2' + buildToolsVersion '27.0.1' defaultConfig { minSdkVersion 9 From 955484e3f0ee2297a09c550c8448b33b1a519c0b Mon Sep 17 00:00:00 2001 From: nonelse Date: Tue, 9 Jan 2018 15:25:22 +0100 Subject: [PATCH 02/52] Add test options --- .../java/com/adjust/sdk/ActivityHandler.java | 8 ++ .../src/main/java/com/adjust/sdk/Adjust.java | 5 + .../java/com/adjust/sdk/AdjustConfig.java | 1 + .../java/com/adjust/sdk/AdjustFactory.java | 111 ++++++++++++++++++ .../java/com/adjust/sdk/AdjustInstance.java | 27 +++++ .../com/adjust/sdk/AdjustTestOptions.java | 19 +++ .../com/adjust/sdk/AttributionHandler.java | 4 +- .../java/com/adjust/sdk/IActivityHandler.java | 1 + .../java/com/adjust/sdk/IPackageHandler.java | 2 + .../java/com/adjust/sdk/PackageHandler.java | 8 ++ .../java/com/adjust/sdk/RequestHandler.java | 8 +- .../java/com/adjust/sdk/SdkClickHandler.java | 14 ++- .../java/com/adjust/sdk/UtilNetworking.java | 63 +++++++--- 13 files changed, 251 insertions(+), 20 deletions(-) create mode 100644 Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java index be3097f7c..5bc051230 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java @@ -53,6 +53,7 @@ public class ActivityHandler implements IActivityHandler { private TimerOnce backgroundTimer; private TimerOnce delayStartTimer; private InternalState internalState; + private String basePath; private DeviceInfo deviceInfo; private AdjustConfig adjustConfig; // always valid after construction @@ -611,6 +612,11 @@ public AdjustAttribution getAttribution() { return attribution; } + @Override + public String getBasePath() { + return this.basePath; + } + public ActivityPackage getAttributionPackageI() { long now = System.currentTimeMillis(); PackageBuilder attributionBuilder = new PackageBuilder(adjustConfig, @@ -739,6 +745,8 @@ public void run() { UtilNetworking.setUserAgent(adjustConfig.userAgent); + this.basePath = adjustConfig.basePath; + packageHandler = AdjustFactory.getPackageHandler(this, adjustConfig.context, toSendI(false)); ActivityPackage attributionPackage = getAttributionPackageI(); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java b/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java index dd3dbe1fd..99c21a530 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java @@ -138,4 +138,9 @@ public static AdjustAttribution getAttribution() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); return adjustInstance.getAttribution(); } + + public static void setTestOptions(AdjustTestOptions testOptions) { + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.setTestOptions(testOptions); + } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java index 9de97494f..a9425c63c 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustConfig.java @@ -8,6 +8,7 @@ * Created by pfms on 06/11/14. */ public class AdjustConfig { + String basePath; Context context; String appToken; String environment; diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java index 929813c7b..a7cfc90d6 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java @@ -4,8 +4,18 @@ import java.io.IOException; import java.net.URL; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; public class AdjustFactory { private static IPackageHandler packageHandler = null; @@ -23,6 +33,8 @@ public class AdjustFactory { private static BackoffStrategy sdkClickBackoffStrategy = null; private static BackoffStrategy packageHandlerBackoffStrategy = null; private static long maxDelayStart = -1; + private static String baseUrl = Constants.BASE_URL; + private static UtilNetworking.IConnectionOptions connectionOptions = null; public static class URLGetConnection { HttpsURLConnection httpsURLConnection; @@ -143,6 +155,20 @@ public static long getMaxDelayStart() { return maxDelayStart; } + public static String getBaseUrl() { + if (AdjustFactory.baseUrl == null) { + return Constants.BASE_URL; + } + return AdjustFactory.baseUrl; + } + + public static UtilNetworking.IConnectionOptions getConnectionOptions() { + if (connectionOptions == null) { + return new UtilNetworking.ConnectionOptions(); + } + return connectionOptions; + } + public static void setPackageHandler(IPackageHandler packageHandler) { AdjustFactory.packageHandler = packageHandler; } @@ -194,4 +220,89 @@ public static void setHttpsURLConnection(HttpsURLConnection httpsURLConnection) public static void setSdkClickHandler(ISdkClickHandler sdkClickHandler) { AdjustFactory.sdkClickHandler = sdkClickHandler; } + + public static void setBaseUrl(String baseUrl) { + AdjustFactory.baseUrl = baseUrl; + } + + public static void useTestConnectionOptions() { + AdjustFactory.connectionOptions = new UtilNetworking.IConnectionOptions() { + @Override + public void applyConnectionOptions(HttpsURLConnection connection, String clientSdk) { + UtilNetworking.ConnectionOptions defaultConnectionOption = new UtilNetworking.ConnectionOptions(); + defaultConnectionOption.applyConnectionOptions(connection, clientSdk); + try { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, new TrustManager[]{ + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + getLogger().verbose("getAcceptedIssuers"); + return null; + } + public void checkClientTrusted( + X509Certificate[] certs, String authType) { + getLogger().verbose("checkClientTrusted "); + } + public void checkServerTrusted( + X509Certificate[] certs, String authType) throws CertificateException { + getLogger().verbose("checkServerTrusted "); + + String serverThumbprint = "7BCFF44099A35BC093BB48C5A6B9A516CDFDA0D1"; + X509Certificate certificate = certs[0]; + + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA1"); + byte[] publicKey = md.digest(certificate.getEncoded()); + String hexString = byte2HexFormatted(publicKey); + + if (!hexString.equalsIgnoreCase(serverThumbprint)) { + throw new CertificateException(); + } + } catch (NoSuchAlgorithmException e) { + getLogger().error("testingMode error %s", e.getMessage()); + } catch (CertificateEncodingException e) { + getLogger().error("testingMode error %s", e.getMessage()); + } + } + } + }, new java.security.SecureRandom()); + connection.setSSLSocketFactory(sc.getSocketFactory()); + + connection.setHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + getLogger().verbose("verify hostname "); + return true; + } + }); + } catch (Exception e) { + getLogger().error("testingMode error %s", e.getMessage()); + } + } + }; + + } + + private static String byte2HexFormatted(byte[] arr) { + StringBuilder str = new StringBuilder(arr.length * 2); + + for (int i = 0; i < arr.length; i++) { + String h = Integer.toHexString(arr[i]); + int l = h.length(); + + if (l == 1) { + h = "0" + h; + } + + if (l > 2) { + h = h.substring(l - 2, l); + } + + str.append(h.toUpperCase()); + + // if (i < (arr.length - 1)) str.append(':'); + } + return str.toString(); + } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java index 599375a27..7aa55b245 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java @@ -37,6 +37,7 @@ public class AdjustInstance { * Array of actions that were requested before SDK initialisation. */ private List preLaunchActionsArray; + private String basePath; /** * Called upon SDK initialisation. @@ -53,6 +54,7 @@ public void onCreate(final AdjustConfig adjustConfig) { adjustConfig.pushToken = pushToken; adjustConfig.startEnabled = startEnabled; adjustConfig.startOffline = startOffline; + adjustConfig.basePath = this.basePath; activityHandler = AdjustFactory.getActivityHandler(adjustConfig); @@ -488,4 +490,29 @@ public void run() { private boolean isInstanceEnabled() { return this.startEnabled == null || this.startEnabled; } + + public void setTestOptions(AdjustTestOptions testOptions) { + if (testOptions.basePath != null) { + this.basePath = testOptions.basePath; + } + if (testOptions.baseUrl != null) { + AdjustFactory.setBaseUrl(testOptions.baseUrl); + } + if (testOptions.useTestConnectionOptions != null && testOptions.useTestConnectionOptions.booleanValue()) { + AdjustFactory.useTestConnectionOptions(); + } + if (testOptions.timerIntervalInMilliseconds != null) { + AdjustFactory.setTimerInterval(testOptions.timerIntervalInMilliseconds); + } + if (testOptions.timerStartInMilliseconds != null) { + AdjustFactory.setTimerStart(testOptions.timerIntervalInMilliseconds); + } + if (testOptions.sessionIntervalInMilliseconds != null) { + AdjustFactory.setSessionInterval(testOptions.sessionIntervalInMilliseconds); + } + if (testOptions.subsessionIntervalInMilliseconds != null) { + AdjustFactory.setSubsessionInterval(testOptions.subsessionIntervalInMilliseconds); + } + + } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java new file mode 100644 index 000000000..12cce99a2 --- /dev/null +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustTestOptions.java @@ -0,0 +1,19 @@ +package com.adjust.sdk; + +import android.content.Context; + +/** + * Created by nonelse on 08.01.2018 + */ + +public class AdjustTestOptions { + public Context context; + public String baseUrl; + public String basePath; + public Boolean useTestConnectionOptions; + public Long timerIntervalInMilliseconds; + public Long timerStartInMilliseconds; + public Long sessionIntervalInMilliseconds; + public Long subsessionIntervalInMilliseconds; + public Boolean teardown; +} diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java index 3ef836531..a99ce2dae 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AttributionHandler.java @@ -20,6 +20,7 @@ public class AttributionHandler implements IAttributionHandler { private static final String ATTRIBUTION_TIMER_NAME = "Attribution timer"; private boolean paused; + private String basePath; @Override public void teardown() { @@ -55,6 +56,7 @@ public void run() { } }, ATTRIBUTION_TIMER_NAME); + basePath = activityHandler.getBasePath(); init(activityHandler, attributionPackage, startsSending); } @@ -223,7 +225,7 @@ private void sendAttributionRequestI() { logger.verbose("%s", attributionPackage.getExtendedString()); try { - ResponseData responseData = UtilNetworking.createGETHttpsURLConnection(attributionPackage); + ResponseData responseData = UtilNetworking.createGETHttpsURLConnection(attributionPackage, basePath); if (!(responseData instanceof AttributionResponseData)) { return; diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java index 4b78fe6ef..db79bfb29 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java @@ -73,4 +73,5 @@ public interface IActivityHandler { SessionParameters getSessionParameters(); + String getBasePath(); } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java index f1304ed66..9109a0e0c 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java @@ -19,5 +19,7 @@ public interface IPackageHandler { void updatePackages(SessionParameters sessionParameters); + String getBasePath(); + void teardown(boolean deleteState); } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java index 958bc9fcf..1ee49c21b 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java @@ -35,6 +35,7 @@ public class PackageHandler implements IPackageHandler { private Context context; private ILogger logger; private BackoffStrategy backoffStrategy; + private String basePath; @Override public void teardown(boolean deleteState) { @@ -88,6 +89,7 @@ public void init(IActivityHandler activityHandler, Context context, boolean star this.activityHandlerWeakRef = new WeakReference(activityHandler); this.context = context; this.paused = !startsSending; + this.basePath = activityHandler.getBasePath(); } // add a package to the queue @@ -193,6 +195,12 @@ public void run() { } }); } + + @Override + public String getBasePath() { + return this.basePath; + } + // internal methods run in dedicated queue thread private void initI() { diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java index 9c596b088..fbd79f3fb 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/RequestHandler.java @@ -20,11 +20,13 @@ public class RequestHandler implements IRequestHandler { private CustomScheduledExecutor scheduledExecutor; private WeakReference packageHandlerWeakRef; private ILogger logger; + private String basePath; public RequestHandler(IPackageHandler packageHandler) { this.logger = AdjustFactory.getLogger(); this.scheduledExecutor = new CustomScheduledExecutor("RequestHandler", false); init(packageHandler); + this.basePath = packageHandler.getBasePath(); } @Override @@ -59,7 +61,11 @@ public void teardown() { } private void sendI(ActivityPackage activityPackage, int queueSize) { - String targetURL = Constants.BASE_URL + activityPackage.getPath(); + String url = AdjustFactory.getBaseUrl(); + if (basePath != null) { + url += basePath; + } + String targetURL = url + activityPackage.getPath(); try { ResponseData responseData = UtilNetworking.createPOSTHttpsURLConnection(targetURL, activityPackage, queueSize); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java index de8537d21..56a5d7406 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/SdkClickHandler.java @@ -56,6 +56,11 @@ public class SdkClickHandler implements ISdkClickHandler { */ private BackoffStrategy backoffStrategy; + /** + * Base path. + */ + private String basePath; + /** * Sending queue. */ @@ -93,6 +98,7 @@ public void init(final IActivityHandler activityHandler, final boolean startsSen paused = !startsSending; packageQueue = new ArrayList(); activityHandlerWeakRef = new WeakReference(activityHandler); + basePath = activityHandler.getBasePath(); } /** @@ -303,7 +309,13 @@ private void sendSdkClickI(final ActivityPackage sdkClickPackage) { installReferrer = sdkClickPackage.getParameters().get("referrer"); } - String targetURL = Constants.BASE_URL + sdkClickPackage.getPath(); + String url = AdjustFactory.getBaseUrl(); + + if (basePath != null) { + url += basePath; + } + + String targetURL = url + sdkClickPackage.getPath(); try { SdkClickResponseData responseData = (SdkClickResponseData) UtilNetworking.createPOSTHttpsURLConnection( diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java b/Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java index 83367d171..51e35824f 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/UtilNetworking.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; @@ -40,10 +41,12 @@ public static ResponseData createPOSTHttpsURLConnection(String urlString, Activi HttpsURLConnection connection = AdjustFactory.getHttpsURLConnection(url); Map parameters = new HashMap(activityPackage.getParameters()); + IConnectionOptions connectionOptions = AdjustFactory.getConnectionOptions(); + connectionOptions.applyConnectionOptions(connection, activityPackage.getClientSdk()); + String appSecret = extractAppSecret(parameters); String secretId = extractSecretId(parameters); - setDefaultHttpsUrlConnectionProperties(connection, activityPackage.getClientSdk()); String authorizationHeader = buildAuthorizationHeader(parameters, appSecret, secretId, activityPackage.getActivityKind().toString()); if (authorizationHeader != null) { connection.setRequestProperty("Authorization", authorizationHeader); @@ -72,23 +75,25 @@ public static ResponseData createPOSTHttpsURLConnection(String urlString, Activi } } - public static ResponseData createGETHttpsURLConnection(ActivityPackage activityPackage) throws Exception { + public static ResponseData createGETHttpsURLConnection(ActivityPackage activityPackage, String basePath) throws Exception { try { Map parameters = new HashMap(activityPackage.getParameters()); + String appSecret = extractAppSecret(parameters); String secretId = extractSecretId(parameters); - Uri uri = buildUri(activityPackage.getPath(), parameters); + Uri uri = buildUri(activityPackage.getPath(), parameters, basePath); URL url = new URL(uri.toString()); HttpsURLConnection connection = AdjustFactory.getHttpsURLConnection(url); + IConnectionOptions connectionOptions = AdjustFactory.getConnectionOptions(); + connectionOptions.applyConnectionOptions(connection, activityPackage.getClientSdk()); + String authorizationHeader = buildAuthorizationHeader(parameters, appSecret, secretId, activityPackage.getActivityKind().toString()); if (authorizationHeader != null) { connection.setRequestProperty("Authorization", authorizationHeader); } - setDefaultHttpsUrlConnectionProperties(connection, activityPackage.getClientSdk()); - connection.setRequestMethod("GET"); ResponseData responseData = readHttpResponse(connection, activityPackage); @@ -214,21 +219,29 @@ private static String getPostDataString(Map body, int queueSize) return result.toString(); } - private static void setDefaultHttpsUrlConnectionProperties(HttpsURLConnection connection, String clientSdk) { - connection.setRequestProperty("Client-SDK", clientSdk); - connection.setConnectTimeout(Constants.ONE_MINUTE); - connection.setReadTimeout(Constants.ONE_MINUTE); + private static Uri buildUri(String path, Map parameters, String basePath) { + Uri.Builder uriBuilder = new Uri.Builder(); - if (userAgent != null) { - connection.setRequestProperty("User-Agent", userAgent); - } - } + String scheme = Constants.SCHEME; + String authority = Constants.AUTHORITY; + String initialPath = ""; - private static Uri buildUri(String path, Map parameters) { - Uri.Builder uriBuilder = new Uri.Builder(); + try { + String url = AdjustFactory.getBaseUrl(); + if (basePath != null) { + url += basePath; + } + URL baseUrl = new URL(url); + scheme = baseUrl.getProtocol(); + authority = baseUrl.getAuthority(); + initialPath = baseUrl.getPath(); + } catch (MalformedURLException e) { + getLogger().error("Unable to parse endpoint (%s)", e.getMessage()); + } - uriBuilder.scheme(Constants.SCHEME); - uriBuilder.authority(Constants.AUTHORITY); + uriBuilder.scheme(scheme); + uriBuilder.encodedAuthority(authority); + uriBuilder.path(initialPath); uriBuilder.appendPath(path); for (Map.Entry entry : parameters.entrySet()) { @@ -350,4 +363,20 @@ private static String getValidIdentifier(final Map parameters) { return null; } + public interface IConnectionOptions { + void applyConnectionOptions(HttpsURLConnection connection, String clientSdk); + } + + static class ConnectionOptions implements IConnectionOptions { + @Override + public void applyConnectionOptions(HttpsURLConnection connection, String clientSdk) { + connection.setRequestProperty("Client-SDK", clientSdk); + connection.setConnectTimeout(Constants.ONE_MINUTE); + connection.setReadTimeout(Constants.ONE_MINUTE); + + if (userAgent != null) { + connection.setRequestProperty("User-Agent", userAgent); + } + } + } } From 68e02a40fb62858764038e3c55c1bf8ac87e318a Mon Sep 17 00:00:00 2001 From: nonelse Date: Tue, 9 Jan 2018 15:50:31 +0100 Subject: [PATCH 03/52] Update Build tools --- Adjust/adjust/build.gradle | 6 +++--- Adjust/example/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Adjust/adjust/build.gradle b/Adjust/adjust/build.gradle index 1a364af77..cfd176647 100644 --- a/Adjust/adjust/build.gradle +++ b/Adjust/adjust/build.gradle @@ -5,12 +5,12 @@ def getVersionName() { } android { - compileSdkVersion 26 - buildToolsVersion '27.0.1' + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { minSdkVersion 9 - targetSdkVersion 26 + targetSdkVersion 27 versionCode 1 versionName getVersionName() consumerProguardFiles 'adjust-proguard-rules.txt' diff --git a/Adjust/example/build.gradle b/Adjust/example/build.gradle index d8f809875..10e30d0d1 100644 --- a/Adjust/example/build.gradle +++ b/Adjust/example/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 - buildToolsVersion '27.0.1' + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.adjust.examples" @@ -21,7 +21,7 @@ android { dependencies { implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'com.google.android.gms:play-services-analytics:11.4.2' + implementation 'com.google.android.gms:play-services-analytics:11.8.0' // imported module implementation project(":adjust") // running mvn package From 6bd48cb2116858f09b5b7af6fc08e435e5dfa365 Mon Sep 17 00:00:00 2001 From: nonelse Date: Tue, 9 Jan 2018 16:01:02 +0100 Subject: [PATCH 04/52] Add test library --- Adjust/settings.gradle | 2 +- Adjust/testlibrary/.gitignore | 1 + Adjust/testlibrary/build.gradle | 32 ++ Adjust/testlibrary/proguard-rules.pro | 21 ++ .../testlibrary/src/main/AndroidManifest.xml | 2 + .../com/adjust/testlibrary/Constants.java | 22 ++ .../adjust/testlibrary/ControlChannel.java | 81 +++++ .../testlibrary/ICommandJsonListener.java | 9 + .../adjust/testlibrary/ICommandListener.java | 12 + .../testlibrary/ICommandRawJsonListener.java | 9 + .../adjust/testlibrary/IOnExitListener.java | 9 + .../com/adjust/testlibrary/TestCommand.java | 14 + .../com/adjust/testlibrary/TestLibrary.java | 298 ++++++++++++++++++ .../java/com/adjust/testlibrary/Utils.java | 49 +++ .../adjust/testlibrary/UtilsNetworking.java | 270 ++++++++++++++++ .../src/main/res/values/strings.xml | 3 + 16 files changed, 833 insertions(+), 1 deletion(-) create mode 100644 Adjust/testlibrary/.gitignore create mode 100644 Adjust/testlibrary/build.gradle create mode 100644 Adjust/testlibrary/proguard-rules.pro create mode 100644 Adjust/testlibrary/src/main/AndroidManifest.xml create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java create mode 100644 Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java create mode 100644 Adjust/testlibrary/src/main/res/values/strings.xml diff --git a/Adjust/settings.gradle b/Adjust/settings.gradle index ab8c3e3e4..02218b9e3 100644 --- a/Adjust/settings.gradle +++ b/Adjust/settings.gradle @@ -1 +1 @@ -include ':adjust', ':test', ':example' +include ':adjust', ':test', ':example', ':testlibrary' diff --git a/Adjust/testlibrary/.gitignore b/Adjust/testlibrary/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/testlibrary/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/testlibrary/build.gradle b/Adjust/testlibrary/build.gradle new file mode 100644 index 000000000..6038184b6 --- /dev/null +++ b/Adjust/testlibrary/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 27 + buildToolsVersion '27.0.3' + + defaultConfig { + minSdkVersion 9 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + compile 'com.google.code.gson:gson:2.8.0' +} + +task clearJar(type: Delete) { + delete "build/outputs/adjust-testing.jar" +} + +task makeJar(type: Copy) { + from('build/intermediates/bundles/debug/') + into('build/outputs/') + include('classes.jar') + rename('classes.jar', "adjust-testing.jar") +} + +makeJar.dependsOn(clearJar, build) diff --git a/Adjust/testlibrary/proguard-rules.pro b/Adjust/testlibrary/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/testlibrary/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Adjust/testlibrary/src/main/AndroidManifest.xml b/Adjust/testlibrary/src/main/AndroidManifest.xml new file mode 100644 index 000000000..7fa906d59 --- /dev/null +++ b/Adjust/testlibrary/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java new file mode 100644 index 000000000..0d1b894a9 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Constants.java @@ -0,0 +1,22 @@ +package com.adjust.testlibrary; + +/** + * Created by nonelse on 09.03.17. + */ + +public interface Constants { + int ONE_SECOND = 1000; + int ONE_MINUTE = 60 * ONE_SECOND; + + String ENCODING = "UTF-8"; + + String LOGTAG = "TestLibrary"; + String TEST_SCRIPT_HEADER = "TestScript"; + String BASE_PATH_HEADER = "BasePath"; + String TEST_SESSION_END_HEADER = "TestSessionEnd"; + String TEST_CANCELTEST_HEADER = "CancelTest"; + String TEST_ENDWAIT_HEADER = "EndWait"; + String TEST_LIBRARY_CLASSNAME = "TestLibrary"; + String WAIT_FOR_CONTROL = "control"; + String WAIT_FOR_SLEEP = "sleep"; +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java new file mode 100644 index 000000000..6b9ca1948 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ControlChannel.java @@ -0,0 +1,81 @@ +package com.adjust.testlibrary; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static com.adjust.testlibrary.Constants.TEST_CANCELTEST_HEADER; +import static com.adjust.testlibrary.Constants.TEST_ENDWAIT_HEADER; +import static com.adjust.testlibrary.Utils.debug; +import static com.adjust.testlibrary.UtilsNetworking.sendPostI; + +/** + * Created by nonelse on 21.03.17. + */ + +public class ControlChannel { + private static final String CONTROL_START_PATH = "/control_start"; + private static final String CONTROL_CONTINUE_PATH = "/control_continue"; + + ExecutorService controlChannelExecutor = Executors.newCachedThreadPool(); + TestLibrary testLibrary; + private boolean closed = false; + + public ControlChannel(TestLibrary testLibrary) { + this.testLibrary = testLibrary; + sendControlRequest(CONTROL_START_PATH); + } + + public void teardown() { + if (controlChannelExecutor != null) { + debug("controlChannelExecutor shutdown"); + controlChannelExecutor.shutdown(); + } + + closed = true; + controlChannelExecutor = null; + } + + private void sendControlRequest(final String controlPath) { + controlChannelExecutor.submit(new Runnable() { + @Override + public void run() { + long timeBefore = System.nanoTime(); + debug("time before wait: %d", timeBefore); + + UtilsNetworking.HttpResponse httpResponse = sendPostI( + Utils.appendBasePath(testLibrary.currentBasePath, controlPath)); + + long timeAfter = System.nanoTime(); + long timeElapsedMillis = TimeUnit.NANOSECONDS.toMillis(timeAfter - timeBefore); + debug("time after wait: %d", timeAfter); + debug("time elapsed waiting in milli seconds: %d", timeElapsedMillis); + + readControlHeaders(httpResponse); + } + }); + } + + void readControlHeaders(UtilsNetworking.HttpResponse httpResponse) { + if (closed) { + debug("control channel already closed"); + return; + } + if (httpResponse.headerFields.containsKey(TEST_CANCELTEST_HEADER)) { + debug("Test canceled due to %s", httpResponse.headerFields.get(TEST_CANCELTEST_HEADER).get(0)); + testLibrary.resetTestLibrary(); + testLibrary.readHeaders(httpResponse); + } + if (httpResponse.headerFields.containsKey(TEST_ENDWAIT_HEADER)) { + String waitEndReason = httpResponse.headerFields.get(TEST_ENDWAIT_HEADER).get(0); + sendControlRequest(CONTROL_CONTINUE_PATH); + endWait(waitEndReason); + } + } + + void endWait(String waitEndReason) { + debug("End wait from control channel due to %s", waitEndReason); + testLibrary.waitControlQueue.offer(waitEndReason); + debug("Wait ended from control channel due to %s", waitEndReason); + } +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java new file mode 100644 index 000000000..0ba75f5e1 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandJsonListener.java @@ -0,0 +1,9 @@ +package com.adjust.testlibrary; + +/** + * Created by nonelse on 10.03.17. + */ + +public interface ICommandJsonListener { + void executeCommand(String className, String methodName, String jsonParameters); +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java new file mode 100644 index 000000000..ea8f16590 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandListener.java @@ -0,0 +1,12 @@ +package com.adjust.testlibrary; + +import java.util.List; +import java.util.Map; + +/** + * Created by nonelse on 09.03.17. + */ + +public interface ICommandListener { + void executeCommand(String className, String methodName, Map> parameters); +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java new file mode 100644 index 000000000..c74e3e0d5 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/ICommandRawJsonListener.java @@ -0,0 +1,9 @@ +package com.adjust.testlibrary; + +/** + * Created by nonelse on 10.03.17. + */ + +public interface ICommandRawJsonListener { + void executeCommand(String json); +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java new file mode 100644 index 000000000..86126a9fd --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/IOnExitListener.java @@ -0,0 +1,9 @@ +package com.adjust.testlibrary; + +/** + * Created by nonelse on 09.03.17. + */ + +public interface IOnExitListener { + void onExit(); +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java new file mode 100644 index 000000000..ca53bed81 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestCommand.java @@ -0,0 +1,14 @@ +package com.adjust.testlibrary; + +import java.util.List; +import java.util.Map; + +/** + * Created by nonelse on 09.03.17. + */ + +public class TestCommand { + public String className; + public String functionName; + public Map> params; +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java new file mode 100644 index 000000000..21241d2ad --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/TestLibrary.java @@ -0,0 +1,298 @@ +package com.adjust.testlibrary; + +import android.os.SystemClock; + +import com.google.gson.Gson; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static com.adjust.testlibrary.Constants.BASE_PATH_HEADER; +import static com.adjust.testlibrary.Constants.TEST_LIBRARY_CLASSNAME; +import static com.adjust.testlibrary.Constants.TEST_SCRIPT_HEADER; +import static com.adjust.testlibrary.Constants.TEST_SESSION_END_HEADER; +import static com.adjust.testlibrary.Constants.WAIT_FOR_CONTROL; +import static com.adjust.testlibrary.Constants.WAIT_FOR_SLEEP; +import static com.adjust.testlibrary.Utils.debug; +import static com.adjust.testlibrary.UtilsNetworking.sendPostI; + + +/** + * Created by nonelse on 09.03.17. + */ + +public class TestLibrary { + static String baseUrl; + ExecutorService executor; + IOnExitListener onExitListener; + ICommandListener commandListener; + ICommandJsonListener commandJsonListener; + ICommandRawJsonListener commandRawJsonListener; + ControlChannel controlChannel; + String currentTest; + String currentBasePath; + Gson gson = new Gson(); + BlockingQueue waitControlQueue; + Map infoToServer; + + String testNames = null; + boolean exitAfterEnd = true; + + public TestLibrary(String baseUrl, ICommandRawJsonListener commandRawJsonListener) { + this(baseUrl); + this.commandRawJsonListener = commandRawJsonListener; + } + + public TestLibrary(String baseUrl, ICommandJsonListener commandJsonListener) { + this(baseUrl); + this.commandJsonListener = commandJsonListener; + } + + public TestLibrary(String baseUrl, ICommandListener commandListener) { + this(baseUrl); + this.commandListener = commandListener; + } + + private TestLibrary(String baseUrl) { + this.baseUrl = baseUrl; + debug("base url: %s", baseUrl); + } + + // resets test library to initial state + void resetTestLibrary() { + teardown(true); + + executor = Executors.newCachedThreadPool(); + waitControlQueue = new LinkedBlockingQueue(); + } + + // clears test library + private void teardown(boolean shutdownNow) { + if (executor != null) { + if (shutdownNow) { + debug("test library executor shutdownNow"); + executor.shutdownNow(); + } else { + debug("test library executor shutdown"); + executor.shutdown(); + } + } + executor = null; + + clearTest(); + } + + // clear for each test + private void clearTest() { + if (waitControlQueue != null) { + waitControlQueue.clear(); + } + waitControlQueue = null; + if (controlChannel != null) { + controlChannel.teardown(); + } + controlChannel = null; + infoToServer = null; + } + + // reset for each test + private void resetTest() { + clearTest(); + + waitControlQueue = new LinkedBlockingQueue(); + controlChannel = new ControlChannel(this); + } + + public void setTests(String testNames) { + this.testNames = testNames; + } + + public void doNotExitAfterEnd() { + this.exitAfterEnd = false; + } + + public void initTestSession(final String clientSdk) { + resetTestLibrary(); + + executor.submit(new Runnable() { + @Override + public void run() { + sendTestSessionI(clientSdk); + } + }); + } + + public void setOnExitListener(IOnExitListener onExitListener) { + this.onExitListener = onExitListener; + } + + public void addInfoToSend(String key, String value) { + if (infoToServer == null) { + infoToServer = new HashMap(); + } + + infoToServer.put(key, value); + } + + public void sendInfoToServer() { + executor.submit(new Runnable() { + @Override + public void run() { + sendInfoToServerI(); + } + }); + } + + + void readHeaders(final UtilsNetworking.HttpResponse httpResponse) { + executor.submit(new Runnable() { + @Override + public void run() { + readHeadersI(httpResponse); + } + }); + } + + private void sendTestSessionI(String clientSdk) { + UtilsNetworking.HttpResponse httpResponse = sendPostI("/init_session", clientSdk, testNames); + if (httpResponse == null) { + return; + } + + readHeadersI(httpResponse); + } + + private void sendInfoToServerI() { + debug("sendInfoToServerI called"); + UtilsNetworking.HttpResponse httpResponse = sendPostI(Utils.appendBasePath(currentBasePath, "/test_info"), null, infoToServer); + infoToServer = null; + if (httpResponse == null) { + return; + } + + readHeadersI(httpResponse); + } + + public void readHeadersI(UtilsNetworking.HttpResponse httpResponse) { + if (httpResponse.headerFields.containsKey(TEST_SESSION_END_HEADER)) { + teardown(false); + debug("TestSessionEnd received"); + if (exitAfterEnd) { + exit(); + } + return; + } + + if (httpResponse.headerFields.containsKey(BASE_PATH_HEADER)) { + currentBasePath = httpResponse.headerFields.get(BASE_PATH_HEADER).get(0); + } + + if (httpResponse.headerFields.containsKey(TEST_SCRIPT_HEADER)) { + currentTest = httpResponse.headerFields.get(TEST_SCRIPT_HEADER).get(0); + resetTest(); + + List testCommands = Arrays.asList(gson.fromJson(httpResponse.response, TestCommand[].class)); + try { + execTestCommandsI(testCommands); + } catch (InterruptedException e) { + debug("InterruptedException thrown %s", e.getMessage()); + } + } + } + + private void execTestCommandsI(List testCommands) throws InterruptedException { + debug("testCommands: %s", testCommands); + + for (TestCommand testCommand : testCommands) { + if (Thread.interrupted()) { + debug("Thread interrupted"); + return; + } + debug("ClassName: %s", testCommand.className); + debug("FunctionName: %s", testCommand.functionName); + debug("Params:"); + if (testCommand.params != null && testCommand.params.size() > 0) { + for (Map.Entry> entry : testCommand.params.entrySet()) { + debug("\t%s: %s", entry.getKey(), entry.getValue()); + } + } + long timeBefore = System.nanoTime(); + debug("time before %s %s: %d", testCommand.className, testCommand.functionName, timeBefore); + + if (TEST_LIBRARY_CLASSNAME.equals(testCommand.className)) { + executeTestLibraryCommandI(testCommand); + long timeAfter = System.nanoTime(); + long timeElapsedMillis = TimeUnit.NANOSECONDS.toMillis(timeAfter - timeBefore); + debug("time after %s %s: %d", testCommand.className, testCommand.functionName, timeAfter); + debug("time elapsed %s %s in milli seconds: %d", testCommand.className, testCommand.functionName, timeElapsedMillis); + + continue; + } + if (commandListener != null) { + commandListener.executeCommand(testCommand.className, testCommand.functionName, testCommand.params); + } else if (commandJsonListener != null) { + commandJsonListener.executeCommand(testCommand.className, testCommand.functionName, gson.toJson(testCommand.params)); + } else if (commandRawJsonListener != null) { + commandRawJsonListener.executeCommand(gson.toJson(testCommand)); + } + long timeAfter = System.nanoTime(); + long timeElapsedMillis = TimeUnit.NANOSECONDS.toMillis(timeAfter - timeBefore); + debug("time after %s.%s: %d", testCommand.className, testCommand.functionName, timeAfter); + debug("time elapsed %s.%s in milli seconds: %d", testCommand.className, testCommand.functionName, timeElapsedMillis); + } + } + + private void executeTestLibraryCommandI(TestCommand testCommand) throws InterruptedException { + switch (testCommand.functionName) { + case "end_test": endTestI(); break; + case "wait": waitI(testCommand.params); break; + case "exit": exit(); break; + } + } + + private void endTestI() { + UtilsNetworking.HttpResponse httpResponse = sendPostI(Utils.appendBasePath(currentBasePath, "/end_test")); + if (httpResponse == null) { + if (exitAfterEnd) { + exit(); + } + return; + } + + readHeadersI(httpResponse); + } + + private void waitI(Map> params) throws InterruptedException { + if (params.containsKey(WAIT_FOR_CONTROL)) { + String waitExpectedReason = params.get(WAIT_FOR_CONTROL).get(0); + debug("wait for %s", waitExpectedReason); + String endReason = waitControlQueue.take(); + debug("wait ended due to %s", endReason); + } + if (params.containsKey(WAIT_FOR_SLEEP)) { + long millisToSleep = Long.parseLong(params.get(WAIT_FOR_SLEEP).get(0)); + debug("sleep for %s", millisToSleep); + + SystemClock.sleep(millisToSleep); + debug("sleep ended"); + } + } + + private void exit() { + if(onExitListener != null){ + onExitListener.onExit(); + } + System.exit(0); + } +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java new file mode 100644 index 000000000..524b7f697 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/Utils.java @@ -0,0 +1,49 @@ +package com.adjust.testlibrary; + +import android.util.Log; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.Locale; +import java.util.Map; + +import javax.net.ssl.HttpsURLConnection; + +import static com.adjust.testlibrary.Constants.LOGTAG; +import static com.adjust.testlibrary.UtilsNetworking.connectionOptions; +import static com.adjust.testlibrary.UtilsNetworking.createPOSTHttpsURLConnection; +import static com.adjust.testlibrary.UtilsNetworking.readHttpResponse; + +/** + * Created by nonelse on 11.03.17. + */ + +public class Utils { + + public static void debug(String message, Object... parameters) { + try { + Log.d(LOGTAG, String.format(Locale.US, message, parameters)); + } catch (Exception e) { + Log.e(LOGTAG, String.format(Locale.US, "Error formating log message: %s, with params: %s" + , message, Arrays.toString(parameters))); + } + } + + public static void error(String message, Object... parameters) { + try { + Log.e(LOGTAG, String.format(Locale.US, message, parameters)); + } catch (Exception e) { + Log.e(LOGTAG, String.format(Locale.US, "Error formating log message: %s, with params: %s" + , message, Arrays.toString(parameters))); + } + } + + public static String appendBasePath(String basePath, String path) { + if (basePath == null) { + return path; + } + return basePath + path; + } +} diff --git a/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java new file mode 100644 index 000000000..c12a878b4 --- /dev/null +++ b/Adjust/testlibrary/src/main/java/com/adjust/testlibrary/UtilsNetworking.java @@ -0,0 +1,270 @@ +package com.adjust.testlibrary; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.URL; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import static com.adjust.testlibrary.Constants.ONE_MINUTE; +import static com.adjust.testlibrary.Utils.debug; +import static com.adjust.testlibrary.Utils.error; + +/** + * Created by uerceg on 03/04/2017. + */ + +public class UtilsNetworking { + static ConnectionOptions connectionOptions; + static TrustManager[] trustAllCerts; + static HostnameVerifier hostnameVerifier; + + public static UtilsNetworking.HttpResponse sendPostI(String path) { + return sendPostI(path, null, null, null); + } + + public static UtilsNetworking.HttpResponse sendPostI(String path, String clientSdk) { + return sendPostI(path, clientSdk, null, null); + } + + public static UtilsNetworking.HttpResponse sendPostI(String path, String clientSdk, String testNames) { + return sendPostI(path, clientSdk, testNames, null); + } + + public static UtilsNetworking.HttpResponse sendPostI(String path, String clientSdk, Map postBody) { + return sendPostI(path, clientSdk, null, postBody); + } + + public static UtilsNetworking.HttpResponse sendPostI(String path, String clientSdk, String testNames, Map postBody) { + String targetURL = TestLibrary.baseUrl + path; + + try { + connectionOptions.clientSdk = clientSdk; + connectionOptions.testNames = testNames; + + HttpsURLConnection connection = createPOSTHttpsURLConnection( + targetURL, postBody, connectionOptions); + UtilsNetworking.HttpResponse httpResponse = readHttpResponse(connection); + debug("Response: %s", httpResponse.response); + + httpResponse.headerFields= connection.getHeaderFields(); + debug("Headers: %s", httpResponse.headerFields); + + return httpResponse; + } catch (IOException e) { + error(e.getMessage()); + } catch (Exception e) { + error(e.getMessage()); + } + return null; + } + + private static String getPostDataString(Map body) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder(); + + for (Map.Entry entry : body.entrySet()) { + String encodedName = URLEncoder.encode(entry.getKey(), Constants.ENCODING); + String value = entry.getValue(); + String encodedValue = value != null ? URLEncoder.encode(value, Constants.ENCODING) : ""; + + if (result.length() > 0) { + result.append("&"); + } + + result.append(encodedName); + result.append("="); + result.append(encodedValue); + } + + return result.toString(); + } + + static { + trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + debug("getAcceptedIssuers"); + + return null; + } + + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + debug("checkClientTrusted"); + } + + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + debug("checkServerTrusted"); + } + } + }; + hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + connectionOptions = new ConnectionOptions(); + } + + public static class HttpResponse { + public String response = null; + public Integer responseCode = null; + public Map> headerFields = null; + } + + public interface IConnectionOptions { + void applyConnectionOptions(HttpsURLConnection connection); + } + + static class ConnectionOptions implements IConnectionOptions { + public String clientSdk; + public String testNames; + + @Override + public void applyConnectionOptions(HttpsURLConnection connection) { + if (clientSdk != null) { + connection.setRequestProperty("Client-SDK", clientSdk); + } + if (testNames != null) { + connection.setRequestProperty("Test-Names", testNames); + } + //Inject local ip address for Jenkins script + connection.setRequestProperty("Local-Ip", getIPAddress(true)); + + connection.setConnectTimeout(ONE_MINUTE); + connection.setReadTimeout(ONE_MINUTE); + try { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + connection.setSSLSocketFactory(sc.getSocketFactory()); + + connection.setHostnameVerifier(hostnameVerifier); + debug("applyConnectionOptions"); + } catch (Exception e) { + debug("applyConnectionOptions %s", e.getMessage()); + } + } + } + + static HttpsURLConnection createPOSTHttpsURLConnection(String urlString, + Map postBody, + IConnectionOptions connectionOptions) + throws IOException + { + DataOutputStream wr = null; + HttpsURLConnection connection = null; + + try { + debug("POST request: %s", urlString); + URL url = new URL(urlString); + connection = (HttpsURLConnection) url.openConnection(); + + connectionOptions.applyConnectionOptions(connection); + + connection.setRequestMethod("POST"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + + if (postBody != null && postBody.size() > 0) { + wr = new DataOutputStream(connection.getOutputStream()); + wr.writeBytes(getPostDataString(postBody)); + } + + return connection; + } catch (Exception e) { + throw e; + } finally { + try { + if (wr != null) { + wr.flush(); + wr.close(); + } + } catch (Exception e) { + } + } + } + + static HttpResponse readHttpResponse(HttpsURLConnection connection) throws Exception { + StringBuffer sb = new StringBuffer(); + HttpResponse httpResponse = new HttpResponse(); + + try { + connection.connect(); + + httpResponse.responseCode = connection.getResponseCode(); + InputStream inputStream; + + if (httpResponse.responseCode >= 400) { + inputStream = connection.getErrorStream(); + } else { + inputStream = connection.getInputStream(); + } + + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + + String line; + + while ((line = bufferedReader.readLine()) != null) { + sb.append(line); + } + } catch (Exception e) { + error("Failed to read response. (%s)", e.getMessage()); + throw e; + } finally { + if (connection != null) { + connection.disconnect(); + } + } + + httpResponse.response = sb.toString(); + return httpResponse; + } + + static String getIPAddress(boolean useIPv4) { + try { + List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface intf : interfaces) { + List addrs = Collections.list(intf.getInetAddresses()); + for (InetAddress addr : addrs) { + if (!addr.isLoopbackAddress()) { + String sAddr = addr.getHostAddress(); + boolean isIPv4 = sAddr.indexOf(':') < 0; + + if (useIPv4) { + if (isIPv4) + return sAddr; + } else { + if (!isIPv4) { + int delim = sAddr.indexOf('%'); // drop ip6 zone suffix + return delim < 0 ? sAddr.toUpperCase() : sAddr.substring(0, delim).toUpperCase(); + } + } + } + } + } + } catch (Exception ex) { + error("Failed to read ip address (%s)", ex.getMessage()); + } + + return ""; + } +} diff --git a/Adjust/testlibrary/src/main/res/values/strings.xml b/Adjust/testlibrary/src/main/res/values/strings.xml new file mode 100644 index 000000000..a4019487d --- /dev/null +++ b/Adjust/testlibrary/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + testlibrary + From fbfc673dd39b2623722fcf5857134979496760d4 Mon Sep 17 00:00:00 2001 From: nonelse Date: Wed, 10 Jan 2018 11:45:01 +0100 Subject: [PATCH 05/52] Change teardown --- .../java/com/adjust/sdk/ActivityHandler.java | 41 ++++++++----------- .../src/main/java/com/adjust/sdk/Adjust.java | 7 ++++ .../java/com/adjust/sdk/AdjustFactory.java | 14 +++++++ .../java/com/adjust/sdk/AdjustInstance.java | 6 +-- .../java/com/adjust/sdk/IActivityHandler.java | 2 +- .../java/com/adjust/sdk/IPackageHandler.java | 2 +- .../java/com/adjust/sdk/PackageHandler.java | 9 ++-- 7 files changed, 48 insertions(+), 33 deletions(-) diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java index 5bc051230..31caff386 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/ActivityHandler.java @@ -64,7 +64,7 @@ public class ActivityHandler implements IActivityHandler { private InstallReferrer installReferrer; @Override - public void teardown(boolean deleteState) { + public void teardown() { if (backgroundTimer != null) { backgroundTimer.teardown(); } @@ -80,7 +80,7 @@ public void teardown(boolean deleteState) { } catch(SecurityException se) {} } if (packageHandler != null) { - packageHandler.teardown(deleteState); + packageHandler.teardown(); } if (attributionHandler != null) { attributionHandler.teardown(); @@ -97,14 +97,9 @@ public void teardown(boolean deleteState) { } } - teardownActivityStateS(deleteState); - teardownAttributionS(deleteState); - teardownAllSessionParametersS(deleteState); - - if (deleteState) { - SharedPreferencesManager sharedPreferencesManager = new SharedPreferencesManager(getContext()); - sharedPreferencesManager.clear(); - } + teardownActivityStateS(); + teardownAttributionS(); + teardownAllSessionParametersS(); packageHandler = null; logger = null; @@ -120,6 +115,16 @@ public void teardown(boolean deleteState) { sessionParameters = null; } + static void deleteState(Context context) { + deleteActivityState(context); + deleteAttribution(context); + deleteSessionCallbackParameters(context); + deleteSessionPartnerParameters(context); + + SharedPreferencesManager sharedPreferencesManager = new SharedPreferencesManager(context); + sharedPreferencesManager.clear(); + } + public class InternalState { boolean enabled; boolean offline; @@ -1755,14 +1760,11 @@ private void writeActivityStateI() { } } - private void teardownActivityStateS(boolean toDelete) { + private void teardownActivityStateS() { synchronized (ActivityState.class) { if (activityState == null) { return; } - if (toDelete && adjustConfig != null && adjustConfig.context != null) { - deleteActivityState(adjustConfig.context); - } activityState = null; } } @@ -1776,14 +1778,11 @@ private void writeAttributionI() { } } - private void teardownAttributionS(boolean toDelete) { + private void teardownAttributionS() { synchronized (AdjustAttribution.class) { if (attribution == null) { return; } - if (toDelete && adjustConfig != null && adjustConfig.context != null) { - deleteAttribution(adjustConfig.context); - } attribution = null; } } @@ -1806,15 +1805,11 @@ private void writeSessionPartnerParametersI() { } } - private void teardownAllSessionParametersS(boolean toDelete) { + private void teardownAllSessionParametersS() { synchronized (SessionParameters.class) { if (sessionParameters == null) { return; } - if (toDelete && adjustConfig != null && adjustConfig.context != null) { - deleteSessionCallbackParameters(adjustConfig.context); - deleteSessionPartnerParameters(adjustConfig.context); - } sessionParameters = null; } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java b/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java index 99c21a530..7c37d83d3 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/Adjust.java @@ -140,6 +140,13 @@ public static AdjustAttribution getAttribution() { } public static void setTestOptions(AdjustTestOptions testOptions) { + if (testOptions.teardown != null && testOptions.teardown.booleanValue()) { + if (defaultInstance != null) { + defaultInstance.teardown(); + } + defaultInstance = null; + AdjustFactory.teardown(testOptions.context); + } AdjustInstance adjustInstance = Adjust.getDefaultInstance(); adjustInstance.setTestOptions(testOptions); } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java index a7cfc90d6..d22fa56ee 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustFactory.java @@ -305,4 +305,18 @@ private static String byte2HexFormatted(byte[] arr) { } return str.toString(); } + + public static void teardown(Context context) { + if(context != null) { + ActivityHandler.deleteState(context); + PackageHandler.deleteState(context); + } + packageHandler = null; + requestHandler = null; + attributionHandler = null; + activityHandler = null; + logger = null; + httpsURLConnection = null; + sdkClickHandler = null; + } } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java index 7aa55b245..78380941e 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/AdjustInstance.java @@ -322,15 +322,13 @@ public void run(final ActivityHandler activityHandler) { /** * Called to teardown SDK state. * Used only for Adjust tests, shouldn't be used in client apps. - * - * @param deleteState boolean indicating should internal Adjust files also be removed or not */ - public void teardown(final boolean deleteState) { + public void teardown() { if (!checkActivityHandler()) { return; } - activityHandler.teardown(deleteState); + activityHandler.teardown(); activityHandler = null; } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java index db79bfb29..ce227bf4d 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/IActivityHandler.java @@ -55,7 +55,7 @@ public interface IActivityHandler { void resetSessionPartnerParameters(); - void teardown(boolean deleteState); + void teardown(); void setPushToken(String token, boolean preSaved); diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java index 9109a0e0c..ab186b239 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/IPackageHandler.java @@ -21,5 +21,5 @@ public interface IPackageHandler { String getBasePath(); - void teardown(boolean deleteState); + void teardown(); } diff --git a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java b/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java index 1ee49c21b..3fc57630e 100644 --- a/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java +++ b/Adjust/adjust/src/main/java/com/adjust/sdk/PackageHandler.java @@ -38,7 +38,7 @@ public class PackageHandler implements IPackageHandler { private String basePath; @Override - public void teardown(boolean deleteState) { + public void teardown() { logger.verbose("PackageHandler teardown"); if (scheduledExecutor != null) { try { @@ -54,9 +54,6 @@ public void teardown(boolean deleteState) { if (packageQueue != null) { packageQueue.clear(); } - if (deleteState && context != null) { - deletePackageQueue(context); - } scheduledExecutor = null; requestHandler = null; activityHandlerWeakRef = null; @@ -67,6 +64,10 @@ public void teardown(boolean deleteState) { backoffStrategy = null; } + static void deleteState(Context context) { + deletePackageQueue(context); + } + public PackageHandler(IActivityHandler activityHandler, Context context, boolean startsSending) { From cbc7fc13acd284e84bc803d0a5c32d0c7988f217 Mon Sep 17 00:00:00 2001 From: nonelse Date: Wed, 10 Jan 2018 11:45:26 +0100 Subject: [PATCH 06/52] Add test app --- Adjust/settings.gradle | 2 +- Adjust/testapp/.gitignore | 1 + Adjust/testapp/build.gradle | 24 + Adjust/testapp/proguard-rules.pro | 21 + Adjust/testapp/src/main/AndroidManifest.xml | 21 + .../adjust/testapp/AdjustCommandExecutor.java | 579 ++++++++++++++++++ .../main/java/com/adjust/testapp/Command.java | 32 + .../com/adjust/testapp/CommandListener.java | 44 ++ .../java/com/adjust/testapp/MainActivity.java | 47 ++ .../drawable-v24/ic_launcher_foreground.xml | 34 + .../res/drawable/ic_launcher_background.xml | 170 +++++ .../src/main/res/layout/activity_main.xml | 18 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes Adjust/testapp/src/main/res/values/colors.xml | 6 + .../testapp/src/main/res/values/strings.xml | 4 + Adjust/testapp/src/main/res/values/styles.xml | 11 + 27 files changed, 1023 insertions(+), 1 deletion(-) create mode 100644 Adjust/testapp/.gitignore create mode 100644 Adjust/testapp/build.gradle create mode 100644 Adjust/testapp/proguard-rules.pro create mode 100644 Adjust/testapp/src/main/AndroidManifest.xml create mode 100644 Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java create mode 100644 Adjust/testapp/src/main/java/com/adjust/testapp/Command.java create mode 100644 Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java create mode 100644 Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java create mode 100644 Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml create mode 100644 Adjust/testapp/src/main/res/layout/activity_main.xml create mode 100644 Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 Adjust/testapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 Adjust/testapp/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 Adjust/testapp/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 Adjust/testapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 Adjust/testapp/src/main/res/values/colors.xml create mode 100644 Adjust/testapp/src/main/res/values/strings.xml create mode 100644 Adjust/testapp/src/main/res/values/styles.xml diff --git a/Adjust/settings.gradle b/Adjust/settings.gradle index 02218b9e3..1cb0de5c5 100644 --- a/Adjust/settings.gradle +++ b/Adjust/settings.gradle @@ -1 +1 @@ -include ':adjust', ':test', ':example', ':testlibrary' +include ':adjust', ':test', ':example', ':testlibrary', ':testapp' diff --git a/Adjust/testapp/.gitignore b/Adjust/testapp/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/Adjust/testapp/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Adjust/testapp/build.gradle b/Adjust/testapp/build.gradle new file mode 100644 index 000000000..d5abf0906 --- /dev/null +++ b/Adjust/testapp/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion '27.0.3' + + defaultConfig { + applicationId "com.adjust.testapp" + minSdkVersion 9 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + compile project(":testlibrary") + compile project (":adjust") + + compile 'com.android.support:appcompat-v7:25.2.0' + compile 'com.android.support.constraint:constraint-layout:1.0.2' +} diff --git a/Adjust/testapp/proguard-rules.pro b/Adjust/testapp/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/testapp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/Adjust/testapp/src/main/AndroidManifest.xml b/Adjust/testapp/src/main/AndroidManifest.xml new file mode 100644 index 000000000..df3f9c9b8 --- /dev/null +++ b/Adjust/testapp/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java b/Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java new file mode 100644 index 000000000..20019dea6 --- /dev/null +++ b/Adjust/testapp/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java @@ -0,0 +1,579 @@ +package com.adjust.testapp; + +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustAttribution; +import com.adjust.sdk.AdjustConfig; +import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.AdjustEventFailure; +import com.adjust.sdk.AdjustEventSuccess; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; +import com.adjust.sdk.AdjustTestOptions; +import com.adjust.sdk.LogLevel; +import com.adjust.sdk.OnAttributionChangedListener; +import com.adjust.sdk.OnDeeplinkResponseListener; +import com.adjust.sdk.OnEventTrackingFailedListener; +import com.adjust.sdk.OnEventTrackingSucceededListener; +import com.adjust.sdk.OnSessionTrackingFailedListener; +import com.adjust.sdk.OnSessionTrackingSucceededListener; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.adjust.testapp.MainActivity.TAG; +import static com.adjust.testapp.MainActivity.baseUrl; + +/** + * Created by nonelse on 10.03.17. + */ + +public class AdjustCommandExecutor { + Context context; + String basePath; + private static final String DefaultConfigName = "defaultConfig"; + private static final String DefaultEventName = "defaultEvent"; + private Map savedEvents = new HashMap(); + private Map savedConfigs = new HashMap(); + Command command; + + public AdjustCommandExecutor(Context context) { + this.context = context; + } + + public void executeCommand(Command command) { + this.command = command; + try { + switch (command.methodName) { + // case "factory": factory(); break; + case "testOptions": testOptions(); break; + case "config": config(); break; + case "start": start(); break; + case "event": event(); break; + case "trackEvent": trackEvent(); break; + case "resume": resume(); break; + case "pause": pause(); break; + case "setEnabled": setEnabled(); break; + case "setReferrer": setReferrer(); break; + case "setOfflineMode": setOfflineMode(); break; + case "sendFirstPackages": sendFirstPackages(); break; + case "addSessionCallbackParameter": addSessionCallbackParameter(); break; + case "addSessionPartnerParameter": addSessionPartnerParameter(); break; + case "removeSessionCallbackParameter": removeSessionCallbackParameter(); break; + case "removeSessionPartnerParameter": removeSessionPartnerParameter(); break; + case "resetSessionCallbackParameters": resetSessionCallbackParameters(); break; + case "resetSessionPartnerParameters": resetSessionPartnerParameters(); break; + case "setPushToken": setPushToken(); break; + // case "teardown": teardown(); break; + case "openDeeplink": openDeeplink(); break; + case "sendReferrer": sendReferrer(); break; + //case "testBegin": testBegin(); break; + // case "testEnd": testEnd(); break; + } + } catch (NullPointerException ex) { + ex.printStackTrace(); + Log.e(TAG, "executeCommand: failed to parse command. Check commands' syntax"); + } + } +/* + private void factory() { + if (command.containsParameter("basePath")) { + this.basePath = command.getFirstParameterValue("basePath"); + } + if (command.containsParameter("timerInterval")) { + long timerInterval = Long.parseLong(command.getFirstParameterValue("timerInterval")); + AdjustFactory.setTimerInterval(timerInterval); + } + if (command.containsParameter("timerStart")) { + long timerStart = Long.parseLong(command.getFirstParameterValue("timerStart")); + AdjustFactory.setTimerStart(timerStart); + } + if (command.containsParameter("sessionInterval")) { + long sessionInterval = Long.parseLong(command.getFirstParameterValue("sessionInterval")); + AdjustFactory.setSessionInterval(sessionInterval); + } + if (command.containsParameter("subsessionInterval")) { + long subsessionInterval = Long.parseLong(command.getFirstParameterValue("subsessionInterval")); + AdjustFactory.setSubsessionInterval(subsessionInterval); + } + } +*/ + + private void testOptions() { + AdjustTestOptions testOptions = new AdjustTestOptions(); + testOptions.baseUrl = baseUrl; + if (command.containsParameter("basePath")) { + testOptions.basePath = command.getFirstParameterValue("basePath"); + } + if (command.containsParameter("useTestConnectionOptions")) { + boolean useTestConnectionOptions = Boolean.valueOf(command.getFirstParameterValue("useTestConnectionOptions")); + testOptions.useTestConnectionOptions = useTestConnectionOptions; + } + if (command.containsParameter("timerInterval")) { + long timerInterval = Long.parseLong(command.getFirstParameterValue("timerInterval")); + testOptions.timerIntervalInMilliseconds = timerInterval; + } + if (command.containsParameter("timerStart")) { + long timerStart = Long.parseLong(command.getFirstParameterValue("timerStart")); + testOptions.timerStartInMilliseconds = timerStart; + } + if (command.containsParameter("sessionInterval")) { + long sessionInterval = Long.parseLong(command.getFirstParameterValue("sessionInterval")); + testOptions.sessionIntervalInMilliseconds = sessionInterval; + } + if (command.containsParameter("subsessionInterval")) { + long subsessionInterval = Long.parseLong(command.getFirstParameterValue("subsessionInterval")); + testOptions.subsessionIntervalInMilliseconds = subsessionInterval; + } + if (command.containsParameter("teardownSdk")) { + boolean teardown = Boolean.valueOf(command.getFirstParameterValue("teardownSdk")); + testOptions.teardown = teardown; + } + if (command.containsParameter("deleteState")) { + boolean deleteState = Boolean.valueOf(command.getFirstParameterValue("deleteState")); + if (deleteState) { + testOptions.context = this.context; + } + } + if (command.containsParameter("teardownTest")) { + boolean teardownTest = Boolean.valueOf(command.getFirstParameterValue("teardownTest")); + if (teardownTest) { + savedEvents = new HashMap(); + savedConfigs = new HashMap(); + testOptions.timerIntervalInMilliseconds = (long) -1; + testOptions.timerStartInMilliseconds = (long) -1; + testOptions.sessionIntervalInMilliseconds = (long) -1; + testOptions.subsessionIntervalInMilliseconds = (long) -1; + } + } + Adjust.setTestOptions(testOptions); + } + + private void config() { + int configNumber = 0; + if (command.parameters.containsKey("configName")) { + String configName = command.getFirstParameterValue("configName"); + configNumber = Integer.parseInt(configName.substring(configName.length() - 1)); + } + + AdjustConfig adjustConfig = null; + + if (savedConfigs.containsKey(configNumber)) { + adjustConfig = savedConfigs.get(configNumber); + } else { + String environment = command.getFirstParameterValue("environment"); + String appToken = command.getFirstParameterValue("appToken"); + Context context = this.context; + if ("null".equalsIgnoreCase(command.getFirstParameterValue("context"))) { + context = null; + } + adjustConfig = new AdjustConfig(context, appToken, environment); + String logLevel = command.getFirstParameterValue("logLevel"); +// adjustConfig.setLogLevel(LogLevel.valueOf(logLevel)); + adjustConfig.setLogLevel(LogLevel.VERBOSE); + + savedConfigs.put(configNumber, adjustConfig); + } + + if (command.containsParameter("logLevel")) { + String logLevelS = command.getFirstParameterValue("logLevel"); + LogLevel logLevel = null; + switch (logLevelS) { + case "verbose": logLevel = LogLevel.VERBOSE; + break; + case "debug": logLevel = LogLevel.DEBUG; + break; + case "info": logLevel = LogLevel.INFO; + break; + case "warn": logLevel = LogLevel.WARN; + break; + case "error": logLevel = LogLevel.ERROR; + break; + case "assert": logLevel = LogLevel.ASSERT; + break; + case "suppress": logLevel = LogLevel.SUPRESS; + break; + } + Log.d("TestApp", logLevel.toString()); + adjustConfig.setLogLevel(logLevel); + } + + if (command.containsParameter("sdkPrefix")) { + String sdkPrefix = command.getFirstParameterValue("sdkPrefix"); + adjustConfig.setSdkPrefix(sdkPrefix); + } + + if (command.containsParameter("defaultTracker")) { + String defaultTracker = command.getFirstParameterValue("defaultTracker"); + adjustConfig.setDefaultTracker(defaultTracker); + } + +// if (command.containsParameter("externalDeviceId")) { +// String externalDeviceId = command.getFirstParameterValue("externalDeviceId"); +// adjustConfig.setExternalDeviceId(externalDeviceId); +// } + + + if (command.parameters.containsKey("appSecret")) { + List appSecretArray = command.parameters.get("appSecret"); + try { + long secretId = Long.parseLong(appSecretArray.get(0)); + long info1 = Long.parseLong(appSecretArray.get(1)); + long info2 = Long.parseLong(appSecretArray.get(2)); + long info3 = Long.parseLong(appSecretArray.get(3)); + long info4 = Long.parseLong(appSecretArray.get(4)); + adjustConfig.setAppSecret(secretId, info1, info2, info3, info4); + } catch (Exception e) { + + } + } + + if (command.containsParameter("delayStart")) { + String delayStartS = command.getFirstParameterValue("delayStart"); + double delayStart = Double.parseDouble(delayStartS); + adjustConfig.setDelayStart(delayStart); + } + + if (command.containsParameter("deviceKnown")) { + String deviceKnownS = command.getFirstParameterValue("deviceKnown"); + boolean deviceKnown = "true".equals(deviceKnownS); + adjustConfig.setDeviceKnown(deviceKnown); + } + + if (command.containsParameter("eventBufferingEnabled")) { + String eventBufferingEnabledS = command.getFirstParameterValue("eventBufferingEnabled"); + boolean eventBufferingEnabled = "true".equals(eventBufferingEnabledS); + adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); + } + + if (command.containsParameter("sendInBackground")) { + String sendInBackgroundS = command.getFirstParameterValue("sendInBackground"); + boolean sendInBackground = "true".equals(sendInBackgroundS); + adjustConfig.setSendInBackground(sendInBackground); + } + + if (command.containsParameter("userAgent")) { + String userAgent = command.getFirstParameterValue("userAgent"); + adjustConfig.setUserAgent(userAgent); + } + + if(command.containsParameter("deferredDeeplinkCallback")) { + adjustConfig.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (deeplink == null) { + Log.d("TestApp", "Deeplink Response, uri = null"); + return false; + } + + Log.d("TestApp", "Deeplink Response, uri = " + deeplink.toString()); + + if (!deeplink.toString().startsWith("adjusttest")) { + return false; + } + + return true; + } + }); + } + + if (command.containsParameter("attributionCallbackSendAll")) { + adjustConfig.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + Log.d("TestApp", "attribution = " + attribution.toString()); + + MainActivity.testLibrary.addInfoToSend("trackerToken", attribution.trackerToken); + MainActivity.testLibrary.addInfoToSend("trackerName", attribution.trackerName); + MainActivity.testLibrary.addInfoToSend("network", attribution.network); + MainActivity.testLibrary.addInfoToSend("campaign", attribution.campaign); + MainActivity.testLibrary.addInfoToSend("adgroup", attribution.adgroup); + MainActivity.testLibrary.addInfoToSend("creative", attribution.creative); + MainActivity.testLibrary.addInfoToSend("clickLabel", attribution.clickLabel); + MainActivity.testLibrary.addInfoToSend("adid", attribution.adid); + MainActivity.testLibrary.sendInfoToServer(); + } + }); + } + + if (command.containsParameter("sessionCallbackSendSuccess")) { + adjustConfig.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + Log.d("TestApp", "session_success = " + sessionSuccessResponseData.toString()); + + MainActivity.testLibrary.addInfoToSend("message", sessionSuccessResponseData.message); + MainActivity.testLibrary.addInfoToSend("timestamp", sessionSuccessResponseData.timestamp); + MainActivity.testLibrary.addInfoToSend("adid", sessionSuccessResponseData.adid); + if (sessionSuccessResponseData.jsonResponse != null) { + MainActivity.testLibrary.addInfoToSend("jsonResponse", sessionSuccessResponseData.jsonResponse.toString()); + } + MainActivity.testLibrary.sendInfoToServer(); + } + }); + } + + if (command.containsParameter("sessionCallbackSendFailure")) { + adjustConfig.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + Log.d("TestApp", "session_fail = " + sessionFailureResponseData.toString()); + + MainActivity.testLibrary.addInfoToSend("message", sessionFailureResponseData.message); + MainActivity.testLibrary.addInfoToSend("timestamp", sessionFailureResponseData.timestamp); + MainActivity.testLibrary.addInfoToSend("adid", sessionFailureResponseData.adid); + MainActivity.testLibrary.addInfoToSend("willRetry", String.valueOf(sessionFailureResponseData.willRetry)); + if (sessionFailureResponseData.jsonResponse != null) { + MainActivity.testLibrary.addInfoToSend("jsonResponse", sessionFailureResponseData.jsonResponse.toString()); + } + MainActivity.testLibrary.sendInfoToServer(); + } + }); + } + + if (command.containsParameter("eventCallbackSendSuccess")) { + adjustConfig.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + @Override + public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + Log.d("TestApp", "event_success = " + eventSuccessResponseData.toString()); + + MainActivity.testLibrary.addInfoToSend("message", eventSuccessResponseData.message); + MainActivity.testLibrary.addInfoToSend("timestamp", eventSuccessResponseData.timestamp); + MainActivity.testLibrary.addInfoToSend("adid", eventSuccessResponseData.adid); + MainActivity.testLibrary.addInfoToSend("eventToken", eventSuccessResponseData.eventToken); + if (eventSuccessResponseData.jsonResponse != null ) { + MainActivity.testLibrary.addInfoToSend("jsonResponse", eventSuccessResponseData.jsonResponse.toString()); + } + MainActivity.testLibrary.sendInfoToServer(); + } + }); + } + + if (command.containsParameter("eventCallbackSendFailure")) { + adjustConfig.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + @Override + public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + Log.d("TestApp", "event_fail = " + eventFailureResponseData.toString()); + + MainActivity.testLibrary.addInfoToSend("message", eventFailureResponseData.message); + MainActivity.testLibrary.addInfoToSend("timestamp", eventFailureResponseData.timestamp); + MainActivity.testLibrary.addInfoToSend("adid", eventFailureResponseData.adid); + MainActivity.testLibrary.addInfoToSend("eventToken", eventFailureResponseData.eventToken); + MainActivity.testLibrary.addInfoToSend("willRetry", String.valueOf(eventFailureResponseData.willRetry)); + if (eventFailureResponseData.jsonResponse != null) { + MainActivity.testLibrary.addInfoToSend("jsonResponse", eventFailureResponseData.jsonResponse.toString()); + } + MainActivity.testLibrary.sendInfoToServer(); + } + }); + } + } + + private void start() { + config(); + int configNumber = 0; + if (command.parameters.containsKey("configName")) { + String configName = command.getFirstParameterValue("configName"); + configNumber = Integer.parseInt(configName.substring(configName.length() - 1)); + } + + AdjustConfig adjustConfig = savedConfigs.get(configNumber); + + //adjustConfig.setBasePath(basePath); + Adjust.onCreate(adjustConfig); + + this.savedConfigs.remove(0); + } + + private void event() throws NullPointerException { + int eventNumber = 0; + if (command.parameters.containsKey("eventName")) { + String eventName = command.getFirstParameterValue("eventName"); + eventNumber = Integer.parseInt(eventName.substring(eventName.length() - 1)); + } + + AdjustEvent adjustEvent = null; + if (savedEvents.containsKey(eventNumber)) { + adjustEvent = savedEvents.get(eventNumber); + } else { + String eventToken = command.getFirstParameterValue("eventToken"); + adjustEvent = new AdjustEvent(eventToken); + savedEvents.put(eventNumber, adjustEvent); + } + + if (command.parameters.containsKey("revenue")) { + List revenueParams = command.parameters.get("revenue"); + String currency = revenueParams.get(0); + double revenue = Double.parseDouble(revenueParams.get(1)); + adjustEvent.setRevenue(revenue, currency); + } + + if (command.parameters.containsKey("callbackParams")) { + List callbackParams = command.parameters.get("callbackParams"); + for (int i = 0; i < callbackParams.size(); i = i + 2) { + String key = callbackParams.get(i); + String value = callbackParams.get(i + 1); + adjustEvent.addCallbackParameter(key, value); + } + } + if (command.parameters.containsKey("partnerParams")) { + List partnerParams = command.parameters.get("partnerParams"); + for (int i = 0; i < partnerParams.size(); i = i + 2) { + String key = partnerParams.get(i); + String value = partnerParams.get(i + 1); + adjustEvent.addPartnerParameter(key, value); + } + } + if (command.parameters.containsKey("orderId")) { + String orderId = command.getFirstParameterValue("orderId"); + adjustEvent.setOrderId(orderId); + } + +// Adjust.trackEvent(adjustEvent); + } + + private void trackEvent() { + event(); + int eventNumber = 0; + if (command.parameters.containsKey("eventName")) { + String eventName = command.getFirstParameterValue("eventName"); + eventNumber = Integer.parseInt(eventName.substring(eventName.length() - 1)); + } + + AdjustEvent adjustEvent = savedEvents.get(eventNumber); + Adjust.trackEvent(adjustEvent); + + this.savedEvents.remove(0); + } + + private void setReferrer() { + String referrer = command.getFirstParameterValue("referrer"); + Adjust.setReferrer(referrer, this.context); + } + + private void pause() { + Adjust.onPause(); + } + + private void resume() { + Adjust.onResume(); + } + + private void setEnabled() { + Boolean enabled = Boolean.valueOf(command.getFirstParameterValue("enabled")); + Adjust.setEnabled(enabled); + } + + private void setOfflineMode() { + Boolean enabled = Boolean.valueOf(command.getFirstParameterValue("enabled")); + Adjust.setOfflineMode(enabled); + } + + private void sendFirstPackages() { + Adjust.sendFirstPackages(); + } + + private void addSessionCallbackParameter() { + if (command.containsParameter("KeyValue")) { + List keyValuePairs = command.parameters.get("KeyValue"); + for (int i = 0; i keyValuePairs = command.parameters.get("KeyValue"); + for (int i = 0; i keys = command.parameters.get("key"); + for (int i = 0; i keys = command.parameters.get("key"); + for (int i = 0; i(); + savedConfigs = new HashMap(); + } + + private void testEnd() { + AdjustFactory.teardown(this.context, true); + } + */ +} diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/Command.java b/Adjust/testapp/src/main/java/com/adjust/testapp/Command.java new file mode 100644 index 000000000..e9ed2b688 --- /dev/null +++ b/Adjust/testapp/src/main/java/com/adjust/testapp/Command.java @@ -0,0 +1,32 @@ +package com.adjust.testapp; + +import java.util.List; +import java.util.Map; + +/** + * Created by nonelse on 10.03.17. + */ + +public class Command { + String className; + String methodName; + Map> parameters; + + public Command(String className, String methodName, Map> parameters) { + this.className = className; + this.methodName = methodName; + this.parameters = parameters; + } + + public String getFirstParameterValue(String parameterKey) { + List parameterValues = this.parameters.get(parameterKey); + if (parameterValues == null || parameterValues.size() == 0) { + return null; + } + return parameterValues.get(0); + } + + public boolean containsParameter(String parameterKey) { + return this.parameters.get(parameterKey) != null; + } +} diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java b/Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java new file mode 100644 index 000000000..9290145b9 --- /dev/null +++ b/Adjust/testapp/src/main/java/com/adjust/testapp/CommandListener.java @@ -0,0 +1,44 @@ +package com.adjust.testapp; + +import android.content.Context; +import android.util.Log; + +import com.adjust.testlibrary.ICommandListener; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Created by nonelse on 09.03.17. + */ + +public class CommandListener implements ICommandListener { + AdjustCommandExecutor adjustCommandExecutor; + + public CommandListener(Context context) { + adjustCommandExecutor = new AdjustCommandExecutor(context); + } + + @Override + public void executeCommand(String className, String methodName, Map> parameters) { + switch (className) { + case "Adjust": + adjustCommandExecutor.executeCommand(new Command(className, methodName, parameters)); + break; + default: + debug("Could not find %s class to execute", className); + break; + } + } + + static void debug(String message, Object... parameters) { + try { + Log.d("TestApp", String.format(Locale.US, message, parameters)); + } catch (Exception e) { + Log.e("TestApp", String.format(Locale.US, "Error formating log message: %s, with params: %s" + , message, Arrays.toString(parameters))); + } + } +} diff --git a/Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java b/Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java new file mode 100644 index 000000000..192b53e08 --- /dev/null +++ b/Adjust/testapp/src/main/java/com/adjust/testapp/MainActivity.java @@ -0,0 +1,47 @@ +package com.adjust.testapp; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import com.adjust.sdk.Adjust; +import com.adjust.testlibrary.TestLibrary; + +public class MainActivity extends AppCompatActivity { + public static TestLibrary testLibrary; + private CommandListener commandListener; + public static final String TAG = "TestApp"; + public static final String baseUrl = "https://10.0.2.2:8443"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // check if deferred deeplink was received + Intent intent = getIntent(); + Uri deeplinkData = intent.getData(); + if (deeplinkData != null) { + Adjust.appWillOpenUrl(deeplinkData); + return; + } + + commandListener = new CommandListener(this.getApplicationContext()); + testLibrary = new TestLibrary(baseUrl, commandListener); + startTestSession(); + } + + private void startTestSession() { + //testLibrary.setTests("current/appSecret/Test_AppSecret_no_secret"); + //testLibrary.setTests("current/Test_Nothing"); + //testLibrary.setTests("current/attributionCallback/Test_AttributionCallback_no_ask_in"); + testLibrary.doNotExitAfterEnd(); + testLibrary.initTestSession("android4.12.0"); + } + + public void onStartTestSession(View v) { + startTestSession(); + } +} diff --git a/Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..c7bd21dbd --- /dev/null +++ b/Adjust/testapp/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml b/Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..d5fccc538 --- /dev/null +++ b/Adjust/testapp/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Adjust/testapp/src/main/res/layout/activity_main.xml b/Adjust/testapp/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..18ffd1ccd --- /dev/null +++ b/Adjust/testapp/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + +