diff --git a/Adjust/build.gradle b/Adjust/build.gradle index e81755ce2..2526273fd 100644 --- a/Adjust/build.gradle +++ b/Adjust/build.gradle @@ -1,18 +1,33 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext { + agp_version = '9.2.1' + kotlin_version = '2.0.21' + } + repositories { + mavenCentral() + google() + } + dependencies { + classpath "com.android.tools.build:gradle:$agp_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + // common in all sub-projects subprojects { } ext { // Android config. - coreMinSdkVersion = 9 - coreCompileSdkVersion = 34 - coreTargetSdkVersion = 34 - coreVersionName = '4.38.5' + coreMinSdkVersion = 21 + coreCompileSdkVersion = 37 + coreTargetSdkVersion = 37 + coreVersionName = '5.8.0' defaultVersionCode = 1 - webbridgeMinSdkVersion = 17 - samsungReferrerMinSdkVersion = 18 + webbridgeMinSdkVersion = 21 + samsungReferrerMinSdkVersion = 21 vivoReferrerMinSdkVersion = 23 samsungCloudDevMinSdkVersion = 23 @@ -20,21 +35,6 @@ ext { adjustGroupId = 'com.adjust.sdk' } -buildscript { - ext.kotlin_version = '1.7.10' - - repositories { - mavenCentral() - google() - } - dependencies { - classpath 'com.android.tools.build:gradle:8.1.4' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files. - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } -} - allprojects { repositories { mavenCentral() diff --git a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt b/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt deleted file mode 100644 index c72ffad12..000000000 --- a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.adjust.examples - -import android.app.Activity -import android.app.Application -import android.os.Bundle -import android.util.Log -import com.adjust.sdk.Adjust -import com.adjust.sdk.AdjustConfig -import com.adjust.sdk.LogLevel - -class GlobalApplication : Application() { - override fun onCreate() { - super.onCreate() - - // Configure adjust SDK. - val appToken = "2fm9gkqubvpc" - val environment = AdjustConfig.ENVIRONMENT_SANDBOX - - val config = AdjustConfig(this, appToken, environment) - - // Change the log level. - config.setLogLevel(LogLevel.VERBOSE) - - // Set attribution delegate. - config.setOnAttributionChangedListener { attribution -> - Log.d("example", "Attribution callback called!") - Log.d("example", "Attribution: $attribution") - } - - // Set event success tracking delegate. - config.setOnEventTrackingSucceededListener { eventSuccessResponseData -> - Log.d("example", "Event success callback called!") - Log.d("example", "Event success data: $eventSuccessResponseData") - } - - // Set event failure tracking delegate. - config.setOnEventTrackingFailedListener { eventFailureResponseData -> - Log.d("example", "Event failure callback called!") - Log.d("example", "Event failure data: $eventFailureResponseData") - } - - // Set session success tracking delegate. - config.setOnSessionTrackingSucceededListener { sessionSuccessResponseData -> - Log.d("example", "Session success callback called!") - Log.d("example", "Session success data: $sessionSuccessResponseData") - } - - // Set session failure tracking delegate. - config.setOnSessionTrackingFailedListener { sessionFailureResponseData -> - Log.d("example", "Session failure callback called!") - Log.d("example", "Session failure data: $sessionFailureResponseData") - } - - // Evaluate deferred deep link to be launched. - config.setOnDeeplinkResponseListener { deeplink -> - Log.d("example", "Deferred deep link callback called!") - Log.d("example", "Deep link URL: $deeplink") - - true - } - - // Set default tracker. - // config.setDefaultTracker("{YourDefaultTracker}"); - - // Set process name. - // config.setProcessName("com.adjust.examples"); - - // Allow to send in the background. - config.setSendInBackground(true) - - // Enable event buffering. - // config.setEventBufferingEnabled(true); - - // Delay first session. - // config.setDelayStart(7); - - // Allow tracking preinstall - // config.setPreinstallTrackingEnabled(true); - - // Add session callback parameters. - Adjust.addSessionCallbackParameter("sc_foo", "sc_bar") - Adjust.addSessionCallbackParameter("sc_key", "sc_value") - - // Add session partner parameters. - Adjust.addSessionPartnerParameter("sp_foo", "sp_bar") - Adjust.addSessionPartnerParameter("sp_key", "sp_value") - - // Remove session callback parameters. - Adjust.removeSessionCallbackParameter("sc_foo") - - // Remove session partner parameters. - Adjust.removeSessionPartnerParameter("sp_key") - - // Remove all session callback parameters. - Adjust.resetSessionCallbackParameters() - - // Remove all session partner parameters. - Adjust.resetSessionPartnerParameters() - - // Enable IMEI reading ONLY IF: - // - IMEI plugin is added to your app. - // - Your app is NOT distributed in Google Play Store. - // AdjustImei.readImei() - - // Enable OAID reading ONLY IF: - // - OAID plugin is added to your app. - // - Your app is NOT distributed in Google Play Store & supports OAID. - // AdjustOaid.readOaid() - - // Initialise the adjust SDK. - Adjust.onCreate(config) - - // Abort delay for the first session introduced with setDelayStart method. - // Adjust.sendFirstPackages(); - - // Register onResume and onPause events of all activities - // for applications with minSdkVersion >= 14. - registerActivityLifecycleCallbacks(AdjustLifecycleCallbacks()) - - // Put the SDK in offline mode. - // Adjust.setOfflineMode(true); - - // Disable the SDK - // Adjust.setEnabled(false); - - // Send push notification token. - // Adjust.setPushToken("token"); - - } - - // You can use this class if your app is for Android 4.0 or higher - private class AdjustLifecycleCallbacks : Application.ActivityLifecycleCallbacks { - override fun onActivityResumed(activity: Activity) { - Adjust.onResume() - } - - override fun onActivityPaused(activity: Activity) { - Adjust.onPause() - } - - override fun onActivityStopped(activity: Activity) {} - - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} - - override fun onActivityDestroyed(activity: Activity) {} - - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} - - override fun onActivityStarted(activity: Activity) {} - } -} diff --git a/Adjust/example-app-fbpixel/.gitignore b/Adjust/examples/example-app-fbpixel/.gitignore similarity index 100% rename from Adjust/example-app-fbpixel/.gitignore rename to Adjust/examples/example-app-fbpixel/.gitignore diff --git a/Adjust/example-app-kotlin/build.gradle b/Adjust/examples/example-app-fbpixel/build.gradle similarity index 80% rename from Adjust/example-app-kotlin/build.gradle rename to Adjust/examples/example-app-fbpixel/build.gradle index 73c671771..76f6b8cf7 100644 --- a/Adjust/example-app-kotlin/build.gradle +++ b/Adjust/examples/example-app-fbpixel/build.gradle @@ -1,15 +1,14 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' + android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.examples" - minSdkVersion 14 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" - } buildTypes { @@ -30,9 +29,11 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') + implementation project(':plugins:sdk-plugin-webbridge') + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-fbpixel/proguard-rules.pro b/Adjust/examples/example-app-fbpixel/proguard-rules.pro similarity index 100% rename from Adjust/example-app-fbpixel/proguard-rules.pro rename to Adjust/examples/example-app-fbpixel/proguard-rules.pro diff --git a/Adjust/example-app-fbpixel/src/main/AndroidManifest.xml b/Adjust/examples/example-app-fbpixel/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-fbpixel/src/main/AndroidManifest.xml diff --git a/Adjust/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html b/Adjust/examples/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html similarity index 96% rename from Adjust/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html rename to Adjust/examples/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html index 25ee126d7..4a4e2cd0e 100755 --- a/Adjust/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html +++ b/Adjust/examples/example-app-fbpixel/src/main/assets/AdjustExample-FbPixel.html @@ -53,7 +53,7 @@

Adjust Facebook Pixel Dem adjustConfig.setFbPixelDefaultEventToken('34vgg9'); // Start Adjust SDK. - Adjust.onCreate(adjustConfig); + Adjust.initSdk(adjustConfig); window.onload = function() { var btnTrackSearchEvent = document.getElementById('btnTrackSearchEvent') @@ -87,25 +87,25 @@

Adjust Facebook Pixel Dem var btnEnableOfflineMode = document.getElementById('btnEnableOfflineMode') btnEnableOfflineMode.onclick = function(e) { e.preventDefault(); - Adjust.setOfflineMode(true); + Adjust.switchToOfflineMode(); } var btnDisableOfflineMode = document.getElementById('btnDisableOfflineMode') btnDisableOfflineMode.onclick = function(e) { e.preventDefault(); - Adjust.setOfflineMode(false); + Adjust.switchBackToOnlineMode(); } var btnEnableSdk = document.getElementById('btnEnableSdk') btnEnableSdk.onclick = function(e) { e.preventDefault() - Adjust.setEnabled(true) + Adjust.enable() } var btnDisableSdk = document.getElementById('btnDisableSdk') btnDisableSdk.onclick = function(e) { e.preventDefault(); - Adjust.setEnabled(false); + Adjust.disable(); } var btnIsSdkEnabled = document.getElementById('btnIsSdkEnabled') diff --git a/Adjust/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/examples/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java similarity index 100% rename from Adjust/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/examples/example-app-fbpixel/src/main/java/com/adjust/examples/MainActivity.java diff --git a/Adjust/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/examples/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml b/Adjust/examples/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-fbpixel/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-fbpixel/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-fbpixel/src/main/res/values/colors.xml b/Adjust/examples/example-app-fbpixel/src/main/res/values/colors.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/values/colors.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/values/colors.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/values/strings.xml b/Adjust/examples/example-app-fbpixel/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/values/strings.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/values/strings.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/values/styles.xml b/Adjust/examples/example-app-fbpixel/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/values/styles.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/values/styles.xml diff --git a/Adjust/example-app-fbpixel/src/main/res/xml/network_security_config.xml b/Adjust/examples/example-app-fbpixel/src/main/res/xml/network_security_config.xml similarity index 100% rename from Adjust/example-app-fbpixel/src/main/res/xml/network_security_config.xml rename to Adjust/examples/example-app-fbpixel/src/main/res/xml/network_security_config.xml diff --git a/Adjust/example-app-tv/build.gradle b/Adjust/examples/example-app-java/build.gradle old mode 100755 new mode 100644 similarity index 78% rename from Adjust/example-app-tv/build.gradle rename to Adjust/examples/example-app-java/build.gradle index 31dcdb40d..918a9e395 --- a/Adjust/example-app-tv/build.gradle +++ b/Adjust/examples/example-app-java/build.gradle @@ -2,24 +2,24 @@ apply plugin: 'com.android.application' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.examples" minSdkVersion 21 - targetSdkVersion 34 + targetSdkVersion 37 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { @@ -33,9 +33,10 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-java/proguard-rules.pro b/Adjust/examples/example-app-java/proguard-rules.pro similarity index 100% rename from Adjust/example-app-java/proguard-rules.pro rename to Adjust/examples/example-app-java/proguard-rules.pro diff --git a/Adjust/example-app-java/src/main/AndroidManifest.xml b/Adjust/examples/example-app-java/src/main/AndroidManifest.xml similarity index 94% rename from Adjust/example-app-java/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-java/src/main/AndroidManifest.xml index 3e10e6500..e8ed52227 100644 --- a/Adjust/example-app-java/src/main/AndroidManifest.xml +++ b/Adjust/examples/example-app-java/src/main/AndroidManifest.xml @@ -16,7 +16,9 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + tools:remove="android:appComponentFactory" + tools:targetApi="p" > = 14. - registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); - - // Put the SDK in offline mode. - // Adjust.setOfflineMode(true); - - // Disable the SDK - // Adjust.setEnabled(false); - - // Send push notification token. - // Adjust.setPushToken("token"); - } - - // You can use this class if your app is for Android 4.0 or higher - private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { - @Override - public void onActivityResumed(Activity activity) { - Adjust.onResume(); - } - - @Override - public void onActivityPaused(Activity activity) { - Adjust.onPause(); - } - - @Override - public void onActivityStopped(Activity activity) { - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - } - - @Override - public void onActivityDestroyed(Activity activity) { - } - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - } - - @Override - public void onActivityStarted(Activity activity) { - } + Adjust.initSdk(config); } } diff --git a/Adjust/example-app-java/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/MainActivity.java similarity index 68% rename from Adjust/example-app-java/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/examples/example-app-java/src/main/java/com/adjust/examples/MainActivity.java index 5ca6f5bd5..563da0638 100644 --- a/Adjust/example-app-java/src/main/java/com/adjust/examples/MainActivity.java +++ b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/MainActivity.java @@ -6,7 +6,6 @@ import androidx.appcompat.app.AppCompatActivity; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -14,10 +13,9 @@ import android.widget.Toast; import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustPurchase; -import com.adjust.sdk.AdjustPurchaseVerificationResult; -import com.adjust.sdk.OnPurchaseVerificationFinishedListener; +import com.adjust.sdk.OnIsEnabledListener; public class MainActivity extends AppCompatActivity { private static final String EVENT_TOKEN_SIMPLE = "g3mfiw"; @@ -34,7 +32,8 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); // Adjust UI according to SDK state. btnEnableDisableSDK = (Button) findViewById(R.id.btnEnableDisableSDK); @@ -44,11 +43,17 @@ protected void onCreate(Bundle savedInstanceState) { public void onResume() { super.onResume(); - if (Adjust.isEnabled()) { - btnEnableDisableSDK.setText(R.string.txt_disable_sdk); - } else { - btnEnableDisableSDK.setText(R.string.txt_enable_sdk); - } + Adjust.isEnabled(this, new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + btnEnableDisableSDK.setText(R.string.txt_disable_sdk); + } else { + btnEnableDisableSDK.setText(R.string.txt_enable_sdk); + } + } + }); + } @Override @@ -108,32 +113,46 @@ public void onTrackPartnerEventClick(View v) { public void onEnableDisableOfflineModeClick(View v) { if (((Button) v).getText().equals( getApplicationContext().getResources().getString(R.string.txt_enable_offline_mode))) { - Adjust.setOfflineMode(true); + Adjust.switchToOfflineMode(); ((Button) v).setText(R.string.txt_disable_offline_mode); } else { - Adjust.setOfflineMode(false); + Adjust.switchBackToOnlineMode(); ((Button) v).setText(R.string.txt_enable_offline_mode); } } public void onEnableDisableSDKClick(View v) { - if (Adjust.isEnabled()) { - Adjust.setEnabled(false); - ((Button) v).setText(R.string.txt_enable_sdk); - } else { - Adjust.setEnabled(true); - ((Button) v).setText(R.string.txt_disable_sdk); - } + Adjust.isEnabled(this, new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + Adjust.disable(); + ((Button) v).setText(R.string.txt_enable_sdk); + } else { + Adjust.enable(); + ((Button) v).setText(R.string.txt_disable_sdk); + } + } + }); + } public void onIsSDKEnabledClick(View v) { - if (Adjust.isEnabled()) { - Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_enabled, - Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_disabled, - Toast.LENGTH_SHORT).show(); - } + + Adjust.isEnabled(this, new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_enabled, + Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_disabled, + Toast.LENGTH_SHORT).show(); + } + } + }); + + } public void onFireIntentClick(View v) { diff --git a/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java similarity index 80% rename from Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java rename to Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java index fe363b5d0..7a80bdc19 100644 --- a/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java +++ b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceActivity.java @@ -9,6 +9,7 @@ import android.view.View; import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; public class ServiceActivity extends AppCompatActivity { @@ -19,7 +20,8 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); } public void onServiceClick(View v) { diff --git a/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java similarity index 96% rename from Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java rename to Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java index 4dfad7ded..6df8a69ed 100644 --- a/Adjust/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java +++ b/Adjust/examples/example-app-java/src/main/java/com/adjust/examples/ServiceExample.java @@ -42,10 +42,10 @@ public int onStartCommand(Intent intent, int flags, int startId) { Log.d("example", "ServiceExample onStartCommand"); if (flip) { - Adjust.setEnabled(false); + Adjust.disable(); flip = false; } else { - Adjust.setEnabled(true); + Adjust.enable(); flip = true; } diff --git a/Adjust/example-app-java/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-java/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-java/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-java/src/main/res/layout/activity_service.xml b/Adjust/examples/example-app-java/src/main/res/layout/activity_service.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/layout/activity_service.xml rename to Adjust/examples/example-app-java/src/main/res/layout/activity_service.xml diff --git a/Adjust/example-app-java/src/main/res/menu/menu_main.xml b/Adjust/examples/example-app-java/src/main/res/menu/menu_main.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/menu/menu_main.xml rename to Adjust/examples/example-app-java/src/main/res/menu/menu_main.xml diff --git a/Adjust/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-java/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-java/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-java/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-java/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-java/src/main/res/values-w820dp/dimens.xml b/Adjust/examples/example-app-java/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/values-w820dp/dimens.xml rename to Adjust/examples/example-app-java/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example-app-java/src/main/res/values/dimens.xml b/Adjust/examples/example-app-java/src/main/res/values/dimens.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/values/dimens.xml rename to Adjust/examples/example-app-java/src/main/res/values/dimens.xml diff --git a/Adjust/example-app-java/src/main/res/values/strings.xml b/Adjust/examples/example-app-java/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/values/strings.xml rename to Adjust/examples/example-app-java/src/main/res/values/strings.xml diff --git a/Adjust/example-app-java/src/main/res/values/styles.xml b/Adjust/examples/example-app-java/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-java/src/main/res/values/styles.xml rename to Adjust/examples/example-app-java/src/main/res/values/styles.xml diff --git a/Adjust/example-app-keyboard/build.gradle b/Adjust/examples/example-app-keyboard/build.gradle similarity index 77% rename from Adjust/example-app-keyboard/build.gradle rename to Adjust/examples/example-app-keyboard/build.gradle index 839e17c16..7e012a2bd 100644 --- a/Adjust/example-app-keyboard/build.gradle +++ b/Adjust/examples/example-app-keyboard/build.gradle @@ -2,24 +2,24 @@ apply plugin: 'com.android.application' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.examples.keyboard" - minSdkVersion 14 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { @@ -33,9 +33,10 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-keyboard/proguard-rules.pro b/Adjust/examples/example-app-keyboard/proguard-rules.pro similarity index 100% rename from Adjust/example-app-keyboard/proguard-rules.pro rename to Adjust/examples/example-app-keyboard/proguard-rules.pro diff --git a/Adjust/example-app-keyboard/src/main/AndroidManifest.xml b/Adjust/examples/example-app-keyboard/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-keyboard/src/main/AndroidManifest.xml diff --git a/Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java b/Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java similarity index 58% rename from Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java rename to Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java index 2b90a7d97..32ecd81da 100644 --- a/Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java +++ b/Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/GlobalApplication.java @@ -1,9 +1,7 @@ package com.adjust.examples.keyboard; -import android.app.Activity; import android.app.Application; import android.net.Uri; -import android.os.Bundle; import android.util.Log; import com.adjust.sdk.Adjust; @@ -11,15 +9,15 @@ import com.adjust.sdk.AdjustConfig; import com.adjust.sdk.AdjustEventFailure; import com.adjust.sdk.AdjustEventSuccess; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; import com.adjust.sdk.LogLevel; import com.adjust.sdk.OnAttributionChangedListener; -import com.adjust.sdk.OnDeeplinkResponseListener; +import com.adjust.sdk.OnDeferredDeeplinkResponseListener; import com.adjust.sdk.OnEventTrackingFailedListener; import com.adjust.sdk.OnEventTrackingSucceededListener; import com.adjust.sdk.OnSessionTrackingFailedListener; import com.adjust.sdk.OnSessionTrackingSucceededListener; -import com.adjust.sdk.AdjustSessionFailure; -import com.adjust.sdk.AdjustSessionSuccess; /** * Created by pfms on 17/12/14. @@ -50,7 +48,7 @@ public void onAttributionChanged(AdjustAttribution attribution) { // Set event success tracking delegate. config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { @Override - public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + public void onEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { Log.d("example", "Event success callback called!"); Log.d("example", "Event success data: " + eventSuccessResponseData.toString()); } @@ -59,7 +57,7 @@ public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResp // Set event failure tracking delegate. config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { @Override - public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + public void onEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { Log.d("example", "Event failure callback called!"); Log.d("example", "Event failure data: " + eventFailureResponseData.toString()); } @@ -68,7 +66,7 @@ public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureRespons // Set session success tracking delegate. config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { @Override - public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + public void onSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { Log.d("example", "Session success callback called!"); Log.d("example", "Session success data: " + sessionSuccessResponseData.toString()); } @@ -77,18 +75,18 @@ public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSucce // Set session failure tracking delegate. config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { @Override - public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + public void onSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { Log.d("example", "Session failure callback called!"); Log.d("example", "Session failure data: " + sessionFailureResponseData.toString()); } }); - // Evaluate deferred deep link to be launched. - config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + // Evaluate deferred deeplink to be launched. + config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { @Override public boolean launchReceivedDeeplink(Uri deeplink) { - Log.d("example", "Deferred deep link callback called!"); - Log.d("example", "Deep link URL: " + deeplink); + Log.d("example", "Deferred deeplink callback called!"); + Log.d("example", "Deeplink URL: " + deeplink); return true; } @@ -101,33 +99,27 @@ public boolean launchReceivedDeeplink(Uri deeplink) { // config.setProcessName("com.adjust.examples"); // Allow to send in the background. - config.setSendInBackground(true); - - // Enable event buffering. - // config.setEventBufferingEnabled(true); - - // Delay first session. - // config.setDelayStart(7); + config.enableSendingInBackground(); // Add session callback parameters. - Adjust.addSessionCallbackParameter("sc_foo", "sc_bar"); - Adjust.addSessionCallbackParameter("sc_key", "sc_value"); + Adjust.addGlobalCallbackParameter("sc_foo", "sc_bar"); + Adjust.addGlobalCallbackParameter("sc_key", "sc_value"); - // Add session partner parameters. - Adjust.addSessionPartnerParameter("sp_foo", "sp_bar"); - Adjust.addSessionPartnerParameter("sp_key", "sp_value"); + // Add global partner parameters. + Adjust.addGlobalPartnerParameter("sp_foo", "sp_bar"); + Adjust.addGlobalPartnerParameter("sp_key", "sp_value"); // Remove session callback parameters. - Adjust.removeSessionCallbackParameter("sc_foo"); + Adjust.removeGlobalCallbackParameter("sc_foo"); - // Remove session partner parameters. - Adjust.removeSessionPartnerParameter("sp_key"); + // Remove global partner parameters. + Adjust.removeGlobalPartnerParameter("sp_key"); // Remove all session callback parameters. - Adjust.resetSessionCallbackParameters(); + Adjust.removeGlobalCallbackParameters(); - // Remove all session partner parameters. - Adjust.resetSessionPartnerParameters(); + // Remove all global partner parameters. + Adjust.removeGlobalPartnerParameters(); // Enable IMEI reading ONLY IF: // - IMEI plugin is added to your app. @@ -140,55 +132,15 @@ public boolean launchReceivedDeeplink(Uri deeplink) { // AdjustOaid.readOaid(); // Initialise the adjust SDK. - Adjust.onCreate(config); - - // Abort delay for the first session introduced with setDelayStart method. - // Adjust.sendFirstPackages(); - - // Register onResume and onPause events of all activities - // for applications with minSdkVersion >= 14. - registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + Adjust.initSdk(config); // Put the SDK in offline mode. - // Adjust.setOfflineMode(true); + // Adjust.switchToOfflineMode(); // Disable the SDK - // Adjust.setEnabled(false); + // Adjust.disable(); // Send push notification token. // Adjust.setPushToken("token"); } - - // You can use this class if your app is for Android 4.0 or higher - private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { - @Override - public void onActivityResumed(Activity activity) { - Adjust.onResume(); - } - - @Override - public void onActivityPaused(Activity activity) { - Adjust.onPause(); - } - - @Override - public void onActivityStopped(Activity activity) { - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - } - - @Override - public void onActivityDestroyed(Activity activity) { - } - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - } - - @Override - public void onActivityStarted(Activity activity) { - } - } } diff --git a/Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/KeyboardInputMethodService.java b/Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/KeyboardInputMethodService.java similarity index 100% rename from Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/KeyboardInputMethodService.java rename to Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/KeyboardInputMethodService.java diff --git a/Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java b/Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java similarity index 94% rename from Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java rename to Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java index 65a15b090..dcb022905 100644 --- a/Adjust/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java +++ b/Adjust/examples/example-app-keyboard/src/main/java/com/adjust/examples/keyboard/MainActivity.java @@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatActivity; import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; import com.adjust.sdk.AdjustEvent; public class MainActivity extends AppCompatActivity { @@ -24,7 +25,8 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); } @Override diff --git a/Adjust/example-app-keyboard/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-keyboard/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-keyboard/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-keyboard/src/main/res/layout/key_preview.xml b/Adjust/examples/example-app-keyboard/src/main/res/layout/key_preview.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/layout/key_preview.xml rename to Adjust/examples/example-app-keyboard/src/main/res/layout/key_preview.xml diff --git a/Adjust/example-app-keyboard/src/main/res/layout/keyboard_view.xml b/Adjust/examples/example-app-keyboard/src/main/res/layout/keyboard_view.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/layout/keyboard_view.xml rename to Adjust/examples/example-app-keyboard/src/main/res/layout/keyboard_view.xml diff --git a/Adjust/example-app-keyboard/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-keyboard/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-keyboard/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-keyboard/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-keyboard/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-keyboard/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-keyboard/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-keyboard/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-keyboard/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-keyboard/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-keyboard/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-keyboard/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-keyboard/src/main/res/values-w820dp/dimens.xml b/Adjust/examples/example-app-keyboard/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/values-w820dp/dimens.xml rename to Adjust/examples/example-app-keyboard/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example-app-keyboard/src/main/res/values/colors.xml b/Adjust/examples/example-app-keyboard/src/main/res/values/colors.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/values/colors.xml rename to Adjust/examples/example-app-keyboard/src/main/res/values/colors.xml diff --git a/Adjust/example-app-keyboard/src/main/res/values/dimens.xml b/Adjust/examples/example-app-keyboard/src/main/res/values/dimens.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/values/dimens.xml rename to Adjust/examples/example-app-keyboard/src/main/res/values/dimens.xml diff --git a/Adjust/example-app-keyboard/src/main/res/values/strings.xml b/Adjust/examples/example-app-keyboard/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/values/strings.xml rename to Adjust/examples/example-app-keyboard/src/main/res/values/strings.xml diff --git a/Adjust/example-app-keyboard/src/main/res/values/styles.xml b/Adjust/examples/example-app-keyboard/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/values/styles.xml rename to Adjust/examples/example-app-keyboard/src/main/res/values/styles.xml diff --git a/Adjust/example-app-keyboard/src/main/res/xml/keyboard.xml b/Adjust/examples/example-app-keyboard/src/main/res/xml/keyboard.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/xml/keyboard.xml rename to Adjust/examples/example-app-keyboard/src/main/res/xml/keyboard.xml diff --git a/Adjust/example-app-keyboard/src/main/res/xml/method.xml b/Adjust/examples/example-app-keyboard/src/main/res/xml/method.xml similarity index 100% rename from Adjust/example-app-keyboard/src/main/res/xml/method.xml rename to Adjust/examples/example-app-keyboard/src/main/res/xml/method.xml diff --git a/Adjust/example-app-kotlin/.gitignore b/Adjust/examples/example-app-kotlin/.gitignore similarity index 100% rename from Adjust/example-app-kotlin/.gitignore rename to Adjust/examples/example-app-kotlin/.gitignore diff --git a/Adjust/example-app-fbpixel/build.gradle b/Adjust/examples/example-app-kotlin/build.gradle similarity index 69% rename from Adjust/example-app-fbpixel/build.gradle rename to Adjust/examples/example-app-kotlin/build.gradle index c29018403..70c52e9ce 100644 --- a/Adjust/example-app-fbpixel/build.gradle +++ b/Adjust/examples/example-app-kotlin/build.gradle @@ -1,20 +1,23 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.android.application' +} android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.examples" - minSdkVersion 17 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" + } buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } @@ -22,17 +25,25 @@ android { sourceCompatibility 1.8 targetCompatibility 1.8 } + namespace 'com.adjust.examples' } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 + } +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') - implementation project(':sdk-plugin-webbridge') + + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-kotlin/proguard-rules.pro b/Adjust/examples/example-app-kotlin/proguard-rules.pro similarity index 100% rename from Adjust/example-app-kotlin/proguard-rules.pro rename to Adjust/examples/example-app-kotlin/proguard-rules.pro diff --git a/Adjust/example-app-kotlin/src/main/AndroidManifest.xml b/Adjust/examples/example-app-kotlin/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-kotlin/src/main/AndroidManifest.xml diff --git a/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt new file mode 100644 index 000000000..982bbd175 --- /dev/null +++ b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/GlobalApplication.kt @@ -0,0 +1,96 @@ +package com.adjust.examples + +import android.app.Application +import android.util.Log +import com.adjust.sdk.Adjust +import com.adjust.sdk.AdjustConfig +import com.adjust.sdk.LogLevel + +class GlobalApplication : Application() { + override fun onCreate() { + super.onCreate() + + // Configure adjust SDK. + val appToken = "2fm9gkqubvpc" + val environment = AdjustConfig.ENVIRONMENT_SANDBOX + + val config = AdjustConfig(this, appToken, environment) + + // Change the log level. + config.setLogLevel(LogLevel.VERBOSE) + + // Set attribution delegate. + config.setOnAttributionChangedListener { attribution -> + Log.d("example", "Attribution callback called!") + Log.d("example", "Attribution: $attribution") + } + + // Set event success tracking delegate. + config.setOnEventTrackingSucceededListener { eventSuccessResponseData -> + Log.d("example", "Event success callback called!") + Log.d("example", "Event success data: $eventSuccessResponseData") + } + + // Set event failure tracking delegate. + config.setOnEventTrackingFailedListener { eventFailureResponseData -> + Log.d("example", "Event failure callback called!") + Log.d("example", "Event failure data: $eventFailureResponseData") + } + + // Set session success tracking delegate. + config.setOnSessionTrackingSucceededListener { sessionSuccessResponseData -> + Log.d("example", "Session success callback called!") + Log.d("example", "Session success data: $sessionSuccessResponseData") + } + + // Set session failure tracking delegate. + config.setOnSessionTrackingFailedListener { sessionFailureResponseData -> + Log.d("example", "Session failure callback called!") + Log.d("example", "Session failure data: $sessionFailureResponseData") + } + + // Evaluate deferred deeplink to be launched. + config.setOnDeferredDeeplinkResponseListener { deeplink -> + Log.d("example", "Deferred deeplink callback called!") + Log.d("example", "Deeplink URL: $deeplink") + + true + } + + // Allow to send in the background. + config.enableSendingInBackground() + + // Add session callback parameters. + Adjust.addGlobalCallbackParameter("sc_foo", "sc_bar") + Adjust.addGlobalCallbackParameter("sc_key", "sc_value") + + // Add global partner parameters. + Adjust.addGlobalPartnerParameter("sp_foo", "sp_bar") + Adjust.addGlobalPartnerParameter("sp_key", "sp_value") + + // Remove session callback parameters. + Adjust.removeGlobalCallbackParameter("sc_foo") + + // Remove global partner parameters. + Adjust.removeGlobalPartnerParameter("sp_key") + + // Remove all session callback parameters. + Adjust.removeGlobalCallbackParameters() + + // Remove all global partner parameters. + Adjust.removeGlobalPartnerParameters() + + // Enable IMEI reading ONLY IF: + // - IMEI plugin is added to your app. + // - Your app is NOT distributed in Google Play Store. + // AdjustImei.readImei() + + // Enable OAID reading ONLY IF: + // - OAID plugin is added to your app. + // - Your app is NOT distributed in Google Play Store & supports OAID. + // AdjustOaid.readOaid() + + // Initialise the adjust SDK. + Adjust.initSdk(config) + } +} diff --git a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt similarity index 74% rename from Adjust/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt rename to Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt index 7124f3fab..4fe43edf0 100644 --- a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt +++ b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/MainActivity.kt @@ -10,7 +10,9 @@ import android.widget.Button import android.widget.Toast import com.adjust.sdk.Adjust +import com.adjust.sdk.AdjustDeeplink import com.adjust.sdk.AdjustEvent +import com.adjust.sdk.OnIsEnabledListener class MainActivity : AppCompatActivity() { @@ -22,7 +24,8 @@ class MainActivity : AppCompatActivity() { val intent = intent val data = intent.data - Adjust.appWillOpenUrl(data, applicationContext) + val adjustDeeplink = AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, applicationContext) // Adjust UI according to SDK state. btnEnableDisableSDK = findViewById(R.id.btnEnableDisableSDK) as Button @@ -31,11 +34,13 @@ class MainActivity : AppCompatActivity() { public override fun onResume() { super.onResume() - if (Adjust.isEnabled()) { - btnEnableDisableSDK!!.setText(R.string.txt_disable_sdk) - } else { - btnEnableDisableSDK!!.setText(R.string.txt_enable_sdk) - } + Adjust.isEnabled(this, OnIsEnabledListener { + if (it) { + btnEnableDisableSDK!!.setText(R.string.txt_disable_sdk) + } else { + btnEnableDisableSDK!!.setText(R.string.txt_enable_sdk) + } + }) } override fun onCreateOptionsMenu(menu: Menu): Boolean { @@ -94,32 +99,36 @@ class MainActivity : AppCompatActivity() { fun onEnableDisableOfflineModeClick(v: View) { if ((v as Button).text == applicationContext.resources.getString(R.string.txt_enable_offline_mode)) { - Adjust.setOfflineMode(true) + Adjust.switchToOfflineMode() v.setText(R.string.txt_disable_offline_mode) } else { - Adjust.setOfflineMode(false) + Adjust.switchBackToOnlineMode() v.setText(R.string.txt_enable_offline_mode) } } fun onEnableDisableSDKClick(v: View) { - if (Adjust.isEnabled()) { - Adjust.setEnabled(false) - (v as Button).setText(R.string.txt_enable_sdk) - } else { - Adjust.setEnabled(true) - (v as Button).setText(R.string.txt_disable_sdk) - } + Adjust.isEnabled(this, OnIsEnabledListener { + if (it) { + Adjust.disable() + (v as Button).setText(R.string.txt_enable_sdk) + } else { + Adjust.enable() + (v as Button).setText(R.string.txt_disable_sdk) + } + }) } fun onIsSDKEnabledClick(v: View) { - if (Adjust.isEnabled()) { - Toast.makeText(applicationContext, R.string.txt_sdk_is_enabled, - Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(applicationContext, R.string.txt_sdk_is_disabled, - Toast.LENGTH_SHORT).show() - } + Adjust.isEnabled(this, OnIsEnabledListener { + if (it) { + Toast.makeText(applicationContext, R.string.txt_sdk_is_enabled, + Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(applicationContext, R.string.txt_sdk_is_disabled, + Toast.LENGTH_SHORT).show() + } + }) } fun onFireIntentClick(v: View) { diff --git a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt similarity index 80% rename from Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt rename to Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt index 279274bd1..cca535f9e 100644 --- a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt +++ b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceActivity.kt @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity import android.view.View import com.adjust.sdk.Adjust +import com.adjust.sdk.AdjustDeeplink class ServiceActivity : AppCompatActivity() { @@ -15,7 +16,8 @@ class ServiceActivity : AppCompatActivity() { val intent = intent val data = intent.data - Adjust.appWillOpenUrl(data, applicationContext) + val adjustDeeplink = AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, applicationContext) } fun onServiceClick(v: View) { diff --git a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt similarity index 96% rename from Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt rename to Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt index b5dea7831..2b661b707 100644 --- a/Adjust/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt +++ b/Adjust/examples/example-app-kotlin/src/main/java/com/adjust/examples/ServiceExample.kt @@ -31,10 +31,10 @@ class ServiceExample : Service() { Log.d("example", "ServiceExample onStartCommand") if (flip) { - Adjust.setEnabled(false) + Adjust.disable() flip = false } else { - Adjust.setEnabled(true) + Adjust.enable() flip = true } diff --git a/Adjust/example-app-kotlin/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-kotlin/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-kotlin/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-kotlin/src/main/res/layout/activity_service.xml b/Adjust/examples/example-app-kotlin/src/main/res/layout/activity_service.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/layout/activity_service.xml rename to Adjust/examples/example-app-kotlin/src/main/res/layout/activity_service.xml diff --git a/Adjust/example-app-kotlin/src/main/res/menu/menu_main.xml b/Adjust/examples/example-app-kotlin/src/main/res/menu/menu_main.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/menu/menu_main.xml rename to Adjust/examples/example-app-kotlin/src/main/res/menu/menu_main.xml diff --git a/Adjust/example-app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-kotlin/src/main/res/values-w820dp/dimens.xml b/Adjust/examples/example-app-kotlin/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/values-w820dp/dimens.xml rename to Adjust/examples/example-app-kotlin/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example-app-kotlin/src/main/res/values/dimens.xml b/Adjust/examples/example-app-kotlin/src/main/res/values/dimens.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/values/dimens.xml rename to Adjust/examples/example-app-kotlin/src/main/res/values/dimens.xml diff --git a/Adjust/example-app-kotlin/src/main/res/values/strings.xml b/Adjust/examples/example-app-kotlin/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/values/strings.xml rename to Adjust/examples/example-app-kotlin/src/main/res/values/strings.xml diff --git a/Adjust/example-app-kotlin/src/main/res/values/styles.xml b/Adjust/examples/example-app-kotlin/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-kotlin/src/main/res/values/styles.xml rename to Adjust/examples/example-app-kotlin/src/main/res/values/styles.xml diff --git a/Adjust/example-app-java/build.gradle b/Adjust/examples/example-app-tv/build.gradle old mode 100644 new mode 100755 similarity index 76% rename from Adjust/example-app-java/build.gradle rename to Adjust/examples/example-app-tv/build.gradle index 5566d0799..918a9e395 --- a/Adjust/example-app-java/build.gradle +++ b/Adjust/examples/example-app-tv/build.gradle @@ -2,24 +2,24 @@ apply plugin: 'com.android.application' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.examples" - minSdkVersion 14 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { @@ -33,9 +33,10 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-tv/proguard-rules.pro b/Adjust/examples/example-app-tv/proguard-rules.pro similarity index 100% rename from Adjust/example-app-tv/proguard-rules.pro rename to Adjust/examples/example-app-tv/proguard-rules.pro diff --git a/Adjust/example-app-tv/src/main/AndroidManifest.xml b/Adjust/examples/example-app-tv/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-app-tv/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-tv/src/main/AndroidManifest.xml diff --git a/Adjust/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java b/Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java similarity index 55% rename from Adjust/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java rename to Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java index d5512d289..27ad680c2 100755 --- a/Adjust/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java +++ b/Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/GlobalApplication.java @@ -1,9 +1,7 @@ package com.adjust.examples; -import android.app.Activity; import android.app.Application; import android.net.Uri; -import android.os.Bundle; import android.util.Log; import com.adjust.sdk.Adjust; @@ -11,15 +9,15 @@ import com.adjust.sdk.AdjustConfig; import com.adjust.sdk.AdjustEventFailure; import com.adjust.sdk.AdjustEventSuccess; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; import com.adjust.sdk.LogLevel; import com.adjust.sdk.OnAttributionChangedListener; -import com.adjust.sdk.OnDeeplinkResponseListener; +import com.adjust.sdk.OnDeferredDeeplinkResponseListener; import com.adjust.sdk.OnEventTrackingFailedListener; import com.adjust.sdk.OnEventTrackingSucceededListener; import com.adjust.sdk.OnSessionTrackingFailedListener; import com.adjust.sdk.OnSessionTrackingSucceededListener; -import com.adjust.sdk.AdjustSessionFailure; -import com.adjust.sdk.AdjustSessionSuccess; public class GlobalApplication extends Application { @Override @@ -47,7 +45,7 @@ public void onAttributionChanged(AdjustAttribution attribution) { // Set event success tracking delegate. config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { @Override - public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + public void onEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { Log.d("example", "Event success callback called!"); Log.d("example", "Event success data: " + eventSuccessResponseData.toString()); } @@ -56,7 +54,7 @@ public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResp // Set event failure tracking delegate. config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { @Override - public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + public void onEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { Log.d("example", "Event failure callback called!"); Log.d("example", "Event failure data: " + eventFailureResponseData.toString()); } @@ -65,7 +63,7 @@ public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureRespons // Set session success tracking delegate. config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { @Override - public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + public void onSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { Log.d("example", "Session success callback called!"); Log.d("example", "Session success data: " + sessionSuccessResponseData.toString()); } @@ -74,18 +72,18 @@ public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSucce // Set session failure tracking delegate. config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { @Override - public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + public void onSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { Log.d("example", "Session failure callback called!"); Log.d("example", "Session failure data: " + sessionFailureResponseData.toString()); } }); - // Evaluate deferred deep link to be launched. - config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + // Evaluate deferred deeplink to be launched. + config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { @Override public boolean launchReceivedDeeplink(Uri deeplink) { - Log.d("example", "Deferred deep link callback called!"); - Log.d("example", "Deep link URL: " + deeplink); + Log.d("example", "Deferred deeplink callback called!"); + Log.d("example", "Deeplink URL: " + deeplink); return true; } @@ -98,84 +96,39 @@ public boolean launchReceivedDeeplink(Uri deeplink) { // config.setProcessName("com.adjust.examples"); // Allow to send in the background. - config.setSendInBackground(true); - - // Enable event buffering. - // config.setEventBufferingEnabled(true); - - // Delay first session. - // config.setDelayStart(7); + config.enableSendingInBackground(); // Add session callback parameters. - Adjust.addSessionCallbackParameter("sc_foo", "sc_bar"); - Adjust.addSessionCallbackParameter("sc_key", "sc_value"); + Adjust.addGlobalCallbackParameter("sc_foo", "sc_bar"); + Adjust.addGlobalCallbackParameter("sc_key", "sc_value"); - // Add session partner parameters. - Adjust.addSessionPartnerParameter("sp_foo", "sp_bar"); - Adjust.addSessionPartnerParameter("sp_key", "sp_value"); + // Add global partner parameters. + Adjust.addGlobalPartnerParameter("sp_foo", "sp_bar"); + Adjust.addGlobalPartnerParameter("sp_key", "sp_value"); // Remove session callback parameters. - Adjust.removeSessionCallbackParameter("sc_foo"); + Adjust.removeGlobalCallbackParameter("sc_foo"); - // Remove session partner parameters. - Adjust.removeSessionPartnerParameter("sp_key"); + // Remove global partner parameters. + Adjust.removeGlobalPartnerParameter("sp_key"); // Remove all session callback parameters. - Adjust.resetSessionCallbackParameters(); + Adjust.removeGlobalCallbackParameters(); - // Remove all session partner parameters. - Adjust.resetSessionPartnerParameters(); + // Remove all global partner parameters. + Adjust.removeGlobalPartnerParameters(); // Initialise the adjust SDK. - Adjust.onCreate(config); - - // Abort delay for the first session introduced with setDelayStart method. - // Adjust.sendFirstPackages(); - - // Register onResume and onPause events of all activities - // for applications with minSdkVersion >= 14. - registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); + Adjust.initSdk(config); // Put the SDK in offline mode. - // Adjust.setOfflineMode(true); + // Adjust.switchToOfflineMode(); // Disable the SDK - // Adjust.setEnabled(false); + // Adjust.disable(); // Send push notification token. // Adjust.setPushToken("token"); } - // You can use this class if your app is for Android 4.0 or higher - private static final class AdjustLifecycleCallbacks implements ActivityLifecycleCallbacks { - @Override - public void onActivityResumed(Activity activity) { - Adjust.onResume(); - } - - @Override - public void onActivityPaused(Activity activity) { - Adjust.onPause(); - } - - @Override - public void onActivityStopped(Activity activity) { - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - } - - @Override - public void onActivityDestroyed(Activity activity) { - } - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - } - - @Override - public void onActivityStarted(Activity activity) { - } - } } diff --git a/Adjust/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java b/Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java similarity index 60% rename from Adjust/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java rename to Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java index f97bb6c06..8c92c0971 100755 --- a/Adjust/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java +++ b/Adjust/examples/example-app-tv/src/main/java/com/adjust/examples/MainActivity.java @@ -11,7 +11,9 @@ import android.widget.Toast; import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; import com.adjust.sdk.AdjustEvent; +import com.adjust.sdk.OnIsEnabledListener; public class MainActivity extends AppCompatActivity { private static final String EVENT_TOKEN_SIMPLE = "g3mfiw"; @@ -28,7 +30,8 @@ protected void onCreate(Bundle savedInstanceState) { Intent intent = getIntent(); Uri data = intent.getData(); - Adjust.appWillOpenUrl(data, getApplicationContext()); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); // Adjust UI according to SDK state. btnEnableDisableSDK = (Button) findViewById(R.id.btnEnableDisableSDK); @@ -37,12 +40,17 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); + Adjust.isEnabled(this, new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + btnEnableDisableSDK.setText(R.string.txt_disable_sdk); + } else { + btnEnableDisableSDK.setText(R.string.txt_enable_sdk); + } + } + }); - if (Adjust.isEnabled()) { - btnEnableDisableSDK.setText(R.string.txt_disable_sdk); - } else { - btnEnableDisableSDK.setText(R.string.txt_enable_sdk); - } } public void onTrackSimpleEventClick(View v) { @@ -81,32 +89,44 @@ public void onTrackPartnerEventClick(View v) { public void onEnableDisableOfflineModeClick(View v) { if (((Button) v).getText().equals( getApplicationContext().getResources().getString(R.string.txt_enable_offline_mode))) { - Adjust.setOfflineMode(true); + Adjust.switchToOfflineMode(); ((Button) v).setText(R.string.txt_disable_offline_mode); } else { - Adjust.setOfflineMode(false); + Adjust.switchBackToOnlineMode(); ((Button) v).setText(R.string.txt_enable_offline_mode); } } public void onEnableDisableSDKClick(View v) { - if (Adjust.isEnabled()) { - Adjust.setEnabled(false); - ((Button) v).setText(R.string.txt_enable_sdk); - } else { - Adjust.setEnabled(true); - ((Button) v).setText(R.string.txt_disable_sdk); - } + Adjust.isEnabled( getApplicationContext(),new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + Adjust.disable(); + ((Button) v).setText(R.string.txt_enable_sdk); + } else { + Adjust.enable(); + ((Button) v).setText(R.string.txt_disable_sdk); + } + } + }); + } public void onIsSDKEnabledClick(View v) { - if (Adjust.isEnabled()) { - Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_enabled, - Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_disabled, - Toast.LENGTH_SHORT).show(); - } + Adjust.isEnabled(getApplicationContext(),new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + if (isEnabled) { + Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_enabled, + Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getApplicationContext(), R.string.txt_sdk_is_disabled, + Toast.LENGTH_SHORT).show(); + } + } + }); + } public void onServiceActivityClick(View v) { diff --git a/Adjust/example-app-tv/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-tv/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-tv/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-tv/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-tv/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-tv/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-tv/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-tv/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-tv/src/main/res/values-w820dp/dimens.xml b/Adjust/examples/example-app-tv/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from Adjust/example-app-tv/src/main/res/values-w820dp/dimens.xml rename to Adjust/examples/example-app-tv/src/main/res/values-w820dp/dimens.xml diff --git a/Adjust/example-app-tv/src/main/res/values/dimens.xml b/Adjust/examples/example-app-tv/src/main/res/values/dimens.xml similarity index 100% rename from Adjust/example-app-tv/src/main/res/values/dimens.xml rename to Adjust/examples/example-app-tv/src/main/res/values/dimens.xml diff --git a/Adjust/example-app-tv/src/main/res/values/strings.xml b/Adjust/examples/example-app-tv/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-tv/src/main/res/values/strings.xml rename to Adjust/examples/example-app-tv/src/main/res/values/strings.xml diff --git a/Adjust/example-app-tv/src/main/res/values/styles.xml b/Adjust/examples/example-app-tv/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-tv/src/main/res/values/styles.xml rename to Adjust/examples/example-app-tv/src/main/res/values/styles.xml diff --git a/Adjust/example-app-webbridge/.gitignore b/Adjust/examples/example-app-webbridge/.gitignore similarity index 100% rename from Adjust/example-app-webbridge/.gitignore rename to Adjust/examples/example-app-webbridge/.gitignore diff --git a/Adjust/example-app-webbridge/build.gradle b/Adjust/examples/example-app-webbridge/build.gradle similarity index 76% rename from Adjust/example-app-webbridge/build.gradle rename to Adjust/examples/example-app-webbridge/build.gradle index 839abf3ea..34b253fc5 100644 --- a/Adjust/example-app-webbridge/build.gradle +++ b/Adjust/examples/example-app-webbridge/build.gradle @@ -1,19 +1,19 @@ apply plugin: 'com.android.application' android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.example.examples" - minSdkVersion 17 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { @@ -27,10 +27,11 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' - implementation 'com.google.android.gms:play-services-appset:16.0.2' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') - implementation project(':sdk-plugin-webbridge') + implementation project(':plugins:sdk-plugin-webbridge') + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' } diff --git a/Adjust/example-app-webbridge/proguard-rules.pro b/Adjust/examples/example-app-webbridge/proguard-rules.pro similarity index 100% rename from Adjust/example-app-webbridge/proguard-rules.pro rename to Adjust/examples/example-app-webbridge/proguard-rules.pro diff --git a/Adjust/example-app-webbridge/src/main/AndroidManifest.xml b/Adjust/examples/example-app-webbridge/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/AndroidManifest.xml rename to Adjust/examples/example-app-webbridge/src/main/AndroidManifest.xml diff --git a/Adjust/example-app-webbridge/src/main/assets/AdjustExample-WebView.html b/Adjust/examples/example-app-webbridge/src/main/assets/AdjustExample-WebView.html similarity index 72% rename from Adjust/example-app-webbridge/src/main/assets/AdjustExample-WebView.html rename to Adjust/examples/example-app-webbridge/src/main/assets/AdjustExample-WebView.html index d4f4995c9..a9954282f 100755 --- a/Adjust/example-app-webbridge/src/main/assets/AdjustExample-WebView.html +++ b/Adjust/examples/example-app-webbridge/src/main/assets/AdjustExample-WebView.html @@ -25,7 +25,8 @@

Adjust Web View SDK Demo 'Campaign = ' + attribution.campaign + '\n' + 'Adgroup = ' + attribution.adgroup + '\n' + 'Creative = ' + attribution.creative + '\n' + - 'Click label = ' + attribution.clickLabel); + 'Click label = ' + attribution.clickLabel + '\n' + + 'Json response = ' + JSON.stringify(attribution.jsonResponse)); } function eventSuccessCallback(eventSuccess) { @@ -62,9 +63,6 @@

Adjust Web View SDK Demo var adjustConfig = new AdjustConfig('2fm9gkqubvpc', AdjustConfig.EnvironmentSandbox); adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); - // adjustConfig.setOpenDeferredDeeplink(true); - // adjustConfig.setSendInBackground(true); - // adjustConfig.setEventBufferingEnabled(false); adjustConfig.setAttributionCallback(attributionCallback); adjustConfig.setEventSuccessCallback(eventSuccessCallback); @@ -73,7 +71,7 @@

Adjust Web View SDK Demo adjustConfig.setSessionFailureCallback(sessionFailureCallback); adjustConfig.setDeferredDeeplinkCallback(deferredDeeplinkCallback); - Adjust.onCreate(adjustConfig); + Adjust.initSdk(adjustConfig); window.onload = function() { var btnTrackSimpleEvent = document.getElementById('btnTrackSimpleEvent') @@ -115,31 +113,33 @@

Adjust Web View SDK Demo var btnEnableOfflineMode = document.getElementById('btnEnableOfflineMode') btnEnableOfflineMode.onclick = function(e) { e.preventDefault(); - Adjust.setOfflineMode(true); + Adjust.switchToOfflineMode(); } var btnDisableOfflineMode = document.getElementById('btnDisableOfflineMode') btnDisableOfflineMode.onclick = function(e) { e.preventDefault(); - Adjust.setOfflineMode(false); + Adjust.switchBackToOnlineMode(); } var btnEnableSdk = document.getElementById('btnEnableSdk') btnEnableSdk.onclick = function(e) { e.preventDefault() - Adjust.setEnabled(true) + Adjust.enable(); } var btnDisableSdk = document.getElementById('btnDisableSdk') btnDisableSdk.onclick = function(e) { e.preventDefault(); - Adjust.setEnabled(false); + Adjust.disable(); } var btnIsSdkEnabled = document.getElementById('btnIsSdkEnabled') btnIsSdkEnabled.onclick = function(e) { e.preventDefault(); - alert('Is SDK enabled? ' + Adjust.isEnabled()); + Adjust.isEnabled(function (isEnabled){ + alert('Is SDK enabled? ' + isEnabled); + }); } var btnGetGoogleAdId = document.getElementById('btnGetGoogleAdId') @@ -149,6 +149,48 @@

Adjust Web View SDK Demo alert('Google Play Ad Id:\n' + gpsAdid); }); } + + var btnGetAmazonId = document.getElementById('btnGetAmazonId') + btnGetAmazonId.onclick = function(e) { + e.preventDefault(); + Adjust.getAmazonAdId(function (amazonAdid) { + alert('Amazon Ad Id:\n' + amazonAdid); + }, + function (message) { + alert('Message:\n' + message); + }); + } + + var btnGetAdId = document.getElementById('btnGetAdId') + btnGetAdId.onclick = function(e) { + e.preventDefault(); + Adjust.getAdid(function (adid) { + alert('Ad Id:\n' + adid); + }); + } + + var btnGetSdkVersion = document.getElementById('btnGetSdkVersion') + btnGetSdkVersion.onclick = function(e) { + e.preventDefault(); + Adjust.getSdkVersion(function (sdkVersion) { + alert('SDK version:\n' + sdkVersion); + }); + } + + var btnGetAttribution = document.getElementById('btnGetAttribution') + btnGetAttribution.onclick = function(e) { + e.preventDefault(); + Adjust.getAttribution(function (attribution) { + alert('Tracker token = ' + attribution.trackerToken + '\n' + + 'Tracker name = ' + attribution.trackerName + '\n' + + 'Network = ' + attribution.network + '\n' + + 'Campaign = ' + attribution.campaign + '\n' + + 'Adgroup = ' + attribution.adgroup + '\n' + + 'Creative = ' + attribution.creative + '\n' + + 'Click label = ' + attribution.clickLabel + '\n' + + 'Json response = ' + JSON.stringify(attribution.jsonResponse)); + }); + } }
@@ -182,6 +224,18 @@

Adjust Web View SDK Demo
+
+ +
+
+ +
+
+ +
+
+ +

diff --git a/Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java b/Adjust/examples/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java similarity index 87% rename from Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java rename to Adjust/examples/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java index 5329d1af3..5e25d256a 100644 --- a/Adjust/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java +++ b/Adjust/examples/example-app-webbridge/src/main/java/com/example/examples/MainActivity.java @@ -23,8 +23,8 @@ protected void onCreate(Bundle savedInstanceState) { AdjustBridge.registerAndGetInstance(getApplication(), webView); try { -// webView.loadUrl("file:///android_asset/AdjustExample-WebView.html"); - webView.loadUrl("https://adjustweb.neocities.org"); + webView.loadUrl("file:///android_asset/AdjustExample-WebView.html"); +// webView.loadUrl("https://adjustweb.neocities.org"); } catch (Exception e) { e.printStackTrace(); } diff --git a/Adjust/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/examples/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/examples/example-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml b/Adjust/examples/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/examples/example-app-webbridge/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/example-app-webbridge/src/main/res/layout/activity_main.xml b/Adjust/examples/example-app-webbridge/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/layout/activity_main.xml rename to Adjust/examples/example-app-webbridge/src/main/res/layout/activity_main.xml diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/examples/example-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/example-app-webbridge/src/main/res/values/colors.xml b/Adjust/examples/example-app-webbridge/src/main/res/values/colors.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/values/colors.xml rename to Adjust/examples/example-app-webbridge/src/main/res/values/colors.xml diff --git a/Adjust/example-app-webbridge/src/main/res/values/strings.xml b/Adjust/examples/example-app-webbridge/src/main/res/values/strings.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/values/strings.xml rename to Adjust/examples/example-app-webbridge/src/main/res/values/strings.xml diff --git a/Adjust/example-app-webbridge/src/main/res/values/styles.xml b/Adjust/examples/example-app-webbridge/src/main/res/values/styles.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/values/styles.xml rename to Adjust/examples/example-app-webbridge/src/main/res/values/styles.xml diff --git a/Adjust/example-app-webbridge/src/main/res/xml/network_security_config.xml b/Adjust/examples/example-app-webbridge/src/main/res/xml/network_security_config.xml similarity index 100% rename from Adjust/example-app-webbridge/src/main/res/xml/network_security_config.xml rename to Adjust/examples/example-app-webbridge/src/main/res/xml/network_security_config.xml diff --git a/Adjust/gradle.properties b/Adjust/gradle.properties index 4d0cdb1f3..50d3d4fd9 100644 --- a/Adjust/gradle.properties +++ b/Adjust/gradle.properties @@ -21,6 +21,4 @@ org.gradle.daemon=true org.gradle.parallel=true org.gradle.configureondemand=true android.useAndroidX=true -android.enableJetifier=true -android.defaults.buildfeatures.buildconfig=true -android.enableR8.fullMode=false \ No newline at end of file +android.enableR8.fullMode=true \ No newline at end of file diff --git a/Adjust/gradle/wrapper/gradle-wrapper.properties b/Adjust/gradle/wrapper/gradle-wrapper.properties index 353db86d0..52a427713 100644 --- a/Adjust/gradle/wrapper/gradle-wrapper.properties +++ b/Adjust/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Oct 06 12:16:52 CEST 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/Adjust/plugin/Criteo/com/adjust/sdk/plugin/AdjustCriteo.java b/Adjust/plugin/Criteo/com/adjust/sdk/plugin/AdjustCriteo.java deleted file mode 100644 index 024cd678f..000000000 --- a/Adjust/plugin/Criteo/com/adjust/sdk/plugin/AdjustCriteo.java +++ /dev/null @@ -1,236 +0,0 @@ -package com.adjust.sdk.plugin; - -import android.net.Uri; - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** - * Created by pfms on 24/02/15. - */ -public class AdjustCriteo { - private static ILogger logger = AdjustFactory.getLogger(); - private static int MAX_VIEW_LISTING_PRODUCTS = 3; - private static String hashEmailInternal; - private static String checkInDateInternal; - private static String checkOutDateInternal; - private static String partnerIdInternal; - private static String userSegmentInternal; - private static String customerIdInternal; - - public static void injectViewListingIntoEvent(AdjustEvent event, List productIds) { - String jsonProducts = createCriteoVLFromProducts(productIds); - event.addPartnerParameter("criteo_p", jsonProducts); - - injectOptionalParams(event); - } - - public static void injectViewProductIntoEvent(AdjustEvent event, String productId) { - event.addPartnerParameter("criteo_p", productId); - - injectOptionalParams(event); - } - - public static void injectCartIntoEvent(AdjustEvent event, List products) { - String jsonProducts = createCriteoVBFromProducts(products); - - event.addPartnerParameter("criteo_p", jsonProducts); - - injectOptionalParams(event); - } - - public static void injectTransactionConfirmedIntoEvent(AdjustEvent event, List products, String transactionId, String newCustomer) { - String jsonProducts = createCriteoVBFromProducts(products); - - event.addPartnerParameter("transaction_id", transactionId); - event.addPartnerParameter("criteo_p", jsonProducts); - event.addPartnerParameter("new_customer", newCustomer); - - injectOptionalParams(event); - } - - public static void injectUserLevelIntoEvent(AdjustEvent event, long uiLevel) { - event.addPartnerParameter("ui_level", String.valueOf(uiLevel)); - - injectOptionalParams(event); - } - - public static void injectUserStatusIntoEvent(AdjustEvent event, String uiStatus) { - event.addPartnerParameter("ui_status", uiStatus); - - injectOptionalParams(event); - } - - public static void injectAchievementUnlockedIntoEvent(AdjustEvent event, String uiAchievement) { - event.addPartnerParameter("ui_achievmnt", uiAchievement); - - injectOptionalParams(event); - } - - public static void injectCustomEventIntoEvent(AdjustEvent event, String uiData) { - event.addPartnerParameter("ui_data", uiData); - - injectOptionalParams(event); - } - - public static void injectCustomEvent2IntoEvent(AdjustEvent event, String uiData2, long uiData3) { - event.addPartnerParameter("ui_data2", uiData2); - event.addPartnerParameter("ui_data3", String.valueOf(uiData3)); - - injectOptionalParams(event); - } - - public static void injectHashedEmailIntoCriteoEvents(String hashEmail) { - hashEmailInternal = hashEmail; - } - - public static void injectViewSearchDatesIntoCriteoEvents(String checkInDate, String checkOutDate) { - checkInDateInternal = checkInDate; - checkOutDateInternal = checkOutDate; - } - - public static void injectPartnerIdIntoCriteoEvents(String partnerId) { - partnerIdInternal = partnerId; - } - - public static void injectUserSegmentIntoCriteoEvents(String userSegment) { - userSegmentInternal = userSegment; - } - - public static void injectCustomerIdIntoCriteoEvents(String customerId) { - customerIdInternal = customerId; - } - - public static void injectDeeplinkIntoEvent(AdjustEvent event, Uri url) { - if (url == null) { - return; - } - - event.addPartnerParameter("criteo_deeplink", url.toString()); - - injectOptionalParams(event); - } - - private static void injectOptionalParams(AdjustEvent event) { - injectHashEmail(event); - injectSearchDates(event); - injectPartnerId(event); - injectUserSegment(event); - injectCustomerId(event); - } - - private static void injectHashEmail(AdjustEvent event) { - if (hashEmailInternal == null || hashEmailInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("criteo_email_hash", hashEmailInternal); - } - - private static void injectSearchDates(AdjustEvent event) { - if (checkInDateInternal == null || checkInDateInternal.isEmpty() || - checkOutDateInternal == null || checkOutDateInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("din", checkInDateInternal); - event.addPartnerParameter("dout", checkOutDateInternal); - } - - private static void injectPartnerId(AdjustEvent event) { - if (partnerIdInternal == null || partnerIdInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("criteo_partner_id", partnerIdInternal); - } - - private static void injectUserSegment(AdjustEvent event) { - if (userSegmentInternal == null || userSegmentInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("user_segment", userSegmentInternal); - } - - private static void injectCustomerId(AdjustEvent event) { - if (customerIdInternal == null || customerIdInternal.isEmpty()) { - return; - } - event.addPartnerParameter("customer_id", customerIdInternal); - } - - private static String createCriteoVLFromProducts(List productIds) { - if (productIds == null) { - logger.warn("Criteo View Listing product ids list is null. It will sent as empty."); - productIds = new ArrayList(); - } - StringBuffer criteoVLValue = new StringBuffer("["); - int productIdsSize = productIds.size(); - - if (productIdsSize > MAX_VIEW_LISTING_PRODUCTS) { - logger.warn("Criteo View Listing should only have at most 3 product ids. The rest will be discarded."); - } - for (int i = 0; i < productIdsSize; ) { - String productID = productIds.get(i); - String productString = String.format(Locale.US, "\"%s\"", productID); - criteoVLValue.append(productString); - - i++; - - if (i == productIdsSize || i >= MAX_VIEW_LISTING_PRODUCTS) { - break; - } - - criteoVLValue.append(","); - } - criteoVLValue.append("]"); - String result = null; - try { - result = URLEncoder.encode(criteoVLValue.toString(),"UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.error("error converting criteo product ids (%s)", e.getMessage()); - } - return result; - } - - private static String createCriteoVBFromProducts(List products) { - if (products == null) { - logger.warn("Criteo Event product list is empty. It will sent as empty."); - products = new ArrayList(); - } - StringBuffer criteoVBValue = new StringBuffer("["); - int productsSize = products.size(); - for (int i = 0; i < productsSize; ) { - CriteoProduct criteoProduct = products.get(i); - String productString = String.format(Locale.US, "{\"i\":\"%s\",\"pr\":%f,\"q\":%d}", - criteoProduct.productID, - criteoProduct.price, - criteoProduct.quantity); - criteoVBValue.append(productString); - - i++; - - if (i == productsSize) { - break; - } - - criteoVBValue.append(","); - } - criteoVBValue.append("]"); - String result = null; - try { - result = URLEncoder.encode(criteoVBValue.toString(),"UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.error("error converting criteo products (%s)", e.getMessage()); - } - return result; - } -} diff --git a/Adjust/plugin/Criteo/com/adjust/sdk/plugin/CriteoProduct.java b/Adjust/plugin/Criteo/com/adjust/sdk/plugin/CriteoProduct.java deleted file mode 100644 index d85746c03..000000000 --- a/Adjust/plugin/Criteo/com/adjust/sdk/plugin/CriteoProduct.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.plugin; - -/** - * Created by pfms on 24/02/15. - */ -public class CriteoProduct { - float price; - int quantity; - String productID; - - public CriteoProduct(float price, int quantity, String productID) { - this.price = price; - this.quantity = quantity; - this.productID = productID; - } -} diff --git a/Adjust/plugin/Sociomantic/com/adjust/sdk/plugin/AdjustSociomantic.java b/Adjust/plugin/Sociomantic/com/adjust/sdk/plugin/AdjustSociomantic.java deleted file mode 100644 index b9ef8e43b..000000000 --- a/Adjust/plugin/Sociomantic/com/adjust/sdk/plugin/AdjustSociomantic.java +++ /dev/null @@ -1,425 +0,0 @@ -package com.adjust.sdk.plugin; - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * AdjustSociomantic Class - * Created by Nicolas Brugneaux nicolas.brugneaux@sociomantic.com on 01/04/15. - */ -public abstract class AdjustSociomantic { - - public final static String SCMCategory = "category"; - public final static String SCMProducts = "products"; - public final static String SCMProductName = "fn"; - public final static String SCMSalePrice = "price"; - public final static String SCMAmount = "amount"; - public final static String SCMCurrency = "currency"; - public final static String SCMProductURL = "url"; - public final static String SCMProductImageURL = "photo"; - public final static String SCMBrand = "brand"; - public final static String SCMDescription = "description"; - public final static String SCMTimestamp = "date"; - public final static String SCMValidityTimestamp = "valid"; - public final static String SCMQuantity = "quantity"; - public final static String SCMScore = "score"; - public final static String SCMProductID = "identifier"; - public final static String SCMActionConfirmed = "confirmed"; - public final static String SCMCustomerAgeGroup = "agegroup"; - public final static String SCMCustomerEducation = "education"; - public final static String SCMCustomerGender = "gender"; - public final static String SCMCustomerID = "identifier"; - public final static String SCMCustomerMHash = "mhash"; - public final static String SCMCustomerSegment = "segment"; - public final static String SCMCustomerTargeting = "targeting"; - public final static String SCMTransaction = "transaction"; - - private final static List productAliases = Arrays.asList( - SCMCategory, - SCMProductName, - SCMSalePrice, - SCMAmount, - SCMCurrency, - SCMProductURL, - SCMProductImageURL, - SCMBrand, - SCMDescription, - SCMTimestamp, - SCMValidityTimestamp, - SCMQuantity, - SCMScore - ); - - private final static List basketAliases = Arrays.asList( - SCMProductID, - SCMAmount, - SCMCurrency, - SCMQuantity - ); - - private final static List saleAliases = Arrays.asList( - SCMAmount, - SCMCurrency - ); - - private final static List customerAliases = Arrays.asList( - SCMCustomerAgeGroup, - SCMCustomerEducation, - SCMCustomerGender, - SCMCustomerID, - SCMCustomerMHash, - SCMCustomerSegment, - SCMCustomerTargeting - ); - - private static String adpanId; - - private static ILogger logger = AdjustFactory.getLogger(); - - public static void injectPartnerIdInSociomanticEvents(String newAdpanId) { - adpanId = newAdpanId; - } - - public static void injectCustomerDataIntoEvent(AdjustEvent event, Map customerData) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == customerData) { - logger.error("Customer data is required."); - return; - } - - Map data = new HashMap(); - - for (Entry entry: customerData.entrySet()) { - if (!customerAliases.contains(entry.getKey())) { - logger.warn("Key must belong to the customer Aliases, entry: %s was discarded", entry.getKey()); - } - else { - data.put(entry.getKey(), entry.getValue()); - } - } - - String dob = stringify(data); - - addPartnerParameter(event, "socio_dob", dob); - } - - public static void injectHomePageIntoEvent(AdjustEvent event) { - if (null == event) { - logger.error("Event object is required."); - } - addPartnerParameter(event); - } - - public static void injectViewListingIntoEvent(AdjustEvent event, List categories) { - injectViewListingIntoEvent(event, categories, null); - } - public static void injectViewListingIntoEvent(AdjustEvent event, List categories, String date) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == categories) { - logger.error("Categories list is required."); - return; - } - - Map co = new HashMap(); - - if (null != date) { - co.put(SCMTimestamp, date); - } - - co.put(SCMCategory, categories); - - addPartnerParameter(event, "socio_co", stringify(co)); - } - - public static void injectProductIntoEvent(AdjustEvent event, String productId) { - injectProductIntoEvent(event, productId, null); - } - public static void injectProductIntoEvent(AdjustEvent event, String productId, Map parameters) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == productId || "".equals(productId)) { - logger.error("Product ID is required."); - return; - } - - Map>> po = new HashMap>>(1); - List> productList; - Map product; - - if (null != parameters) { - product = filter(parameters, productAliases); - } - else { - product = new HashMap(); - } - - product.put(SCMProductID, productId); - productList = Arrays.asList(product); - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - - public static void injectCartIntoEvent(AdjustEvent event, List products) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == products) { - logger.error("Products list is required."); - return; - } - - Map>> po = new HashMap>>(1); - List> productList = new ArrayList>(); - - for (Object product: products) { - Map _product = new HashMap(); - - if (product instanceof String) { - _product.put(SCMProductID, product); - } - else if (product instanceof Map) { - _product = filter((Map) product, basketAliases); - } - - if (!_product.isEmpty()) { - productList.add(_product); - } - } - - if (!productList.isEmpty()) { - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - } - - public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { - injectTransactionIntoEvent(event, transactionID, products, null, Boolean.TRUE); - } - public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { - injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.TRUE); - } - - public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { - injectTransactionIntoEvent(event, transactionID, products, null, Boolean.FALSE); - } - public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { - injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.FALSE); - } - private static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters, Boolean confirmed) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == transactionID || "".equals(transactionID)) { - logger.error("Transaction ID is required."); - return; - } - if (null == products) { - logger.error("Products list is required."); - return; - } - - Map> to = new HashMap>(1); - Map>> po = new HashMap>>(1); - List> productList = new ArrayList>(); - - for (Object product: products) { - Map _product = new HashMap(); - - if (product instanceof String) { - _product.put(SCMProductID, product); - } - else if (product instanceof Map) { - _product = filter((Map) product, basketAliases); - } - - if (!_product.isEmpty()) { - productList.add(_product); - } - } - - if (!productList.isEmpty()) { - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - - if (null != parameters) { - to.put(SCMTransaction, filter(parameters, saleAliases)); - } - else { - to.put(SCMTransaction, new HashMap()); - } - - if (confirmed) { - to.get(SCMTransaction).put(SCMActionConfirmed, "true"); - } - - to.get(SCMTransaction).put(SCMTransaction, transactionID); - - addPartnerParameter(event, "socio_to", stringify(to)); - } - - public static void injectLeadIntoEvent(AdjustEvent event, String leadID) { - injectLeadIntoEvent(event, leadID, Boolean.FALSE); - } - public static void injectLeadIntoEvent(AdjustEvent event, String leadID, Boolean confirmed) { - - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == leadID || "".equals(leadID)) { - logger.error("Lead ID is required."); - return; - } - - Map> to = new HashMap>(1); - to.put(SCMTransaction, new HashMap()); - - if (confirmed) { - to.get(SCMTransaction).put(SCMActionConfirmed, "true"); - } - - to.get(SCMTransaction).put(SCMTransaction, leadID); - - addPartnerParameter(event, "socio_to", stringify(to)); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - // private methods used internally - //////////////////////////////////////////////////////////////////////////////////////////////// - - private static void addPartnerParameter(AdjustEvent event) { - addPartnerParameter(event, null, null); - } - private static void addPartnerParameter(AdjustEvent event, String parameter, String json) { - if (null == adpanId) { - logger.error("The adpanId must be set before sending any sociomantic event. No parameter has been added."); - return; - } - - if (null != parameter && null != json) - { - event.addPartnerParameter(parameter, json); - } - - event.addPartnerParameter("socio_aid", adpanId); - } - - private static Map filter(Map parameters, List aliases) { - - Map filtered = new HashMap(); - - for(Entry entry: parameters.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (!aliases.contains(key)) { - logger.error("Key must correspond to as Sociomantic alias => ".concat(key)); - } - else { - if (key.equals(SCMCategory)) { - if (value instanceof String || value instanceof String[]) { - filtered.put(key, Arrays.asList(value)); - } else if (value instanceof List) { - filtered.put(key, filterStringArray((List) value)); - } - } - else { - filtered.put(key, value); - } - } - } - return filtered; - } - - private static List filterStringArray(List list) { - - List filtered = new ArrayList(); - for (Object item: list) { - if (item instanceof String) { - filtered.add((String) item); - } - else { - logger.error("All values should be strings"); - } - } - return filtered; - } - - private static String stringify(Object o) { - if (o == null) { - return "null"; - } - - if (o instanceof String) { - return "\"".concat((String) o).concat("\""); - } - - if (o instanceof Integer || o instanceof Long || o instanceof Double) { - return o.toString(); - } - - if (o instanceof Boolean) { - return (Boolean) o ? "true" : "false"; - } - - if (o instanceof List) { - String res = "["; - List list = (List) o; - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - Object item = iterator.next(); - res = res.concat(stringify(item)); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("]"); - } - - if (o instanceof Map) { - String res = "{"; - Map map = (Map) o; - Iterator> iterator = map.entrySet().iterator(); - - while(iterator.hasNext()) { - Entry entry = iterator.next(); - - res = res.concat(stringify(entry.getKey())) - .concat(":") - .concat(stringify(entry.getValue())); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("}"); - } - - logger.error("Could not parse the object ".concat(o.toString().concat(" into a JSON string, returned empty string."))); - return ""; - - } -} diff --git a/Adjust/plugin/Trademob/com/adjust/sdk/plugin/AdjustTrademob.java b/Adjust/plugin/Trademob/com/adjust/sdk/plugin/AdjustTrademob.java deleted file mode 100644 index 24e7bf0d1..000000000 --- a/Adjust/plugin/Trademob/com/adjust/sdk/plugin/AdjustTrademob.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.adjust.sdk.plugin; - - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - - -public class AdjustTrademob { - - private static int MAX_LISTING_ITEMS_COUNT = 5; - - private static ILogger logger = AdjustFactory.getLogger(); - - public static void injectViewItemIntoEvent(AdjustEvent event, String itemId, Map metadata) { - event.addPartnerParameter("tm_item", itemId); - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - } - - public static void injectViewListingIntoEvent(AdjustEvent event, List itemIds, Map metadata) { - String jsonItems = stringifyItemIds(itemIds); - event.addPartnerParameter("tm_item", jsonItems); - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - } - - public static void injectAddToBasketIntoEvent(AdjustEvent event, List items, Map metadata) { - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - String jsonItems = stringifyItems(items); - event.addPartnerParameter("tm_item", jsonItems); - } - - public static void injectCheckoutIntoEvent(AdjustEvent event, List items, Map metadata) { - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - String jsonItems = stringifyItems(items); - event.addPartnerParameter("tm_item", jsonItems); - } - - private static String stringifyItemIds(List itemIds) { - if (itemIds == null) { - logger.warn("TM View Listing item ids list is null. Empty ids array will be sent."); - itemIds = new ArrayList(); - } - StringBuffer tmViewList = new StringBuffer("["); - int itemsSize = itemIds.size(); - int i = 0; - - while (i < itemsSize) { - String itemId = itemIds.get(i); - String itemString = String.format(Locale.US, "\"%s\"", itemId); - tmViewList.append(itemString); - - i++; - - if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { - break; - } - - tmViewList.append(","); - } - - tmViewList.append("]"); - - return tmViewList.toString(); - } - - private static String stringifyItems(List items) { - if (items == null) { - logger.warn("TM View Listing item ids list is empty. Empty items will be sent."); - items = new ArrayList(); - } - - StringBuffer itemsStrBuffer = new StringBuffer("["); - int itemsSize = items.size(); - - for (int i = 0; i < itemsSize; ) { - TrademobItem item = items.get(i); - String itemString = String.format(Locale.US, "{\"id\":\"%s\",\"price\":%f,\"quantity\":%d}", - item.itemId, - item.price, - item.quantity); - itemsStrBuffer.append(itemString); - - i++; - - if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { - break; - } - - itemsStrBuffer.append(","); - } - - itemsStrBuffer.append("]"); - - return itemsStrBuffer.toString(); - } - - private static String stringifyMetadata(Map metadata) { - - if(null == metadata) { - return "{}"; - } - String res = "{"; - - Iterator> iterator = metadata.entrySet().iterator(); - - while(iterator.hasNext()) { - Map.Entry entry = iterator.next(); - String key = "\"".concat(entry.getKey()).concat("\""); - String value = "\"".concat(entry.getValue()).concat("\""); - res = res.concat(key).concat(":").concat(value); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("}"); - } -} diff --git a/Adjust/plugin/Trademob/com/adjust/sdk/plugin/TrademobItem.java b/Adjust/plugin/Trademob/com/adjust/sdk/plugin/TrademobItem.java deleted file mode 100644 index c9897fa6f..000000000 --- a/Adjust/plugin/Trademob/com/adjust/sdk/plugin/TrademobItem.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adjust.sdk.plugin; - -public class TrademobItem { - float price; - int quantity; - String itemId; - - public TrademobItem(String itemId, int quantity, float price) { - this.price = price; - this.quantity = quantity; - this.itemId = itemId; - } -} diff --git a/Adjust/test-options/.gitignore b/Adjust/plugins/sdk-plugin-google-lvl/.gitignore similarity index 100% rename from Adjust/test-options/.gitignore rename to Adjust/plugins/sdk-plugin-google-lvl/.gitignore diff --git a/Adjust/plugins/sdk-plugin-google-lvl/LICENSE b/Adjust/plugins/sdk-plugin-google-lvl/LICENSE new file mode 100644 index 000000000..50b720ae3 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----------------------------------- +Third-Party Components and Licenses +----------------------------------- + +This project includes code from the following third-party component(s): + +- Google Licensing Service + Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + +The Apache 2.0 license and any required NOTICE file are located in src/main/aidl/com/android/vending/licensing directory diff --git a/Adjust/plugins/sdk-plugin-google-lvl/build.gradle b/Adjust/plugins/sdk-plugin-google-lvl/build.gradle new file mode 100644 index 000000000..f10c4c6ba --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/build.gradle @@ -0,0 +1,250 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } +} + +android { + compileSdk rootProject.ext.coreCompileSdkVersion + publishing { + multipleVariants { + allVariants() + withJavadocJar() + } + } + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } + } + namespace 'com.adjust.sdk.google.lvl' + sourceSets { + main { + aidl { + srcDirs 'src/main/aidl' + } + } + } + buildFeatures { + aidl true + } + testOptions { + unitTests.includeAndroidResources = true + } +} + +dependencies { + + // Add SDK via module. + compileOnly project(':sdk-core') + // Unit testing + // For unit tests + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.mockito:mockito-core:5.10.0' + +// For integration tests + testImplementation 'org.robolectric:robolectric:4.11.1' + + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:5.3.0' +} + +// read local properties +File localPropsFile = project.rootProject.file('local.properties') +if (localPropsFile.exists()) { + Properties p = new Properties() + new FileInputStream(localPropsFile).withCloseable { is -> + p.load(is) + } + p.each { name, value -> + ext[name] = value + } +} + +task adjustLvlPluginAar(type: Copy) { + dependsOn 'assembleRelease' + + from('build/outputs/aar/') + include 'sdk-plugin-google-lvl-release.aar' + destinationDir file('build/libs/') + rename 'sdk-plugin-google-lvl-release.aar', "${project.name}.aar" + +} + +task adjustLvlPluginJar(type: Jar) { + dependsOn 'packageReleaseAssets' + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/library_assets/release/packageReleaseAssets/out/') { + into('assets') + } + from('build/intermediates/javac/release/classes/') + + archiveFileName = project.provider { "${project.name}.jar" } +} + + +task adjustLvlPluginSourcesJar(type: Jar) { + setArchiveClassifier('sources') + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustLvlPluginJar + archives adjustLvlPluginSourcesJar +} + +afterEvaluate { + publishing { + publications { +/* + mavenAndroidLvlJar(MavenPublication) { + customizePomForJar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-license-verification' + version rootProject.ext.coreVersionName + + artifact adjustLvlPluginJar + artifact adjustLvlPluginSourcesJar + } +*/ + mavenAndroidLvlAar(MavenPublication) { + customizePomForAar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-google-lvl' + version rootProject.ext.coreVersionName + + artifact("$buildDir/outputs/aar/sdk-plugin-google-lvl-release.aar") { + builtBy tasks.getByPath("adjustLvlPluginAar") + } + artifact adjustLvlPluginSourcesJar + } + } + + repositories { + maven { + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } + } + signing { +// sign publishing.publications.mavenAndroidLvlJar + sign publishing.publications.mavenAndroidLvlAar + } +} + +def customizePomForJar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The License Verification plugin for Adjust SDK for Android' + name 'Adjust Android SDK License Verification plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'Adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugi@adjust.com' + } + } + } + } +} + +def customizePomForAar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The License Verification plugin for Adjust SDK for Android' + name 'Adjust Android SDK License Verification plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'Adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugi@adjust.com' + } + } + } + } +} + +model { +// tasks.generatePomFileForMavenAndroidLvlJarPublication { +// destination = file("${project.buildDir}/generated-pom.xml") +// } + /* TODO check if/how to replace this tasks + tasks.publishMavenAndroidLvlPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidLvlPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } + */ + tasks.generatePomFileForMavenAndroidLvlAarPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } +} + + diff --git a/Adjust/plugins/sdk-plugin-google-lvl/proguard-rules.pro b/Adjust/plugins/sdk-plugin-google-lvl/proguard-rules.pro new file mode 100644 index 000000000..4a9685c4a --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/proguard-rules.pro @@ -0,0 +1,29 @@ +# 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 + +# Keep all classes in the LVL licensing AIDL package +-keep class com.android.vending.licensing.** { *; } + +# Prevent obfuscation of the stub classes used for IPC +-keepclassmembers class * implements android.os.IInterface { + ; +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-google-lvl/src/main/AndroidManifest.xml new file mode 100644 index 000000000..00053e6bc --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/AdjustLicenseVerification.java b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/AdjustLicenseVerification.java new file mode 100644 index 000000000..6a147cfda --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/AdjustLicenseVerification.java @@ -0,0 +1,35 @@ +package com.adjust.sdk.google.lvl; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.LicenseData; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class AdjustLicenseVerification { + + public static LicenseData fetchLicenseDate(Context context, ILogger logger, long timestamp) { + try { + BlockingQueue licenseHolder = new LinkedBlockingQueue(1); + LicenseChecker checker = new LicenseChecker(context, new LicenseRawCallback() { + @Override + public void onLicenseDataReceived(int responseCode, String signedData, String signature) { + licenseHolder.offer(new LicenseData(signedData, signature, responseCode)); + } + + @Override + public void onError(int errorCode) { + licenseHolder.offer(new LicenseData(null, null, errorCode)); + } + }, logger, timestamp); + checker.checkAccess(); + return licenseHolder.poll(3000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + logger.error("LVL License checker interrupted: ", e.getMessage()); + return null; + } + } +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseChecker.java b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseChecker.java new file mode 100644 index 000000000..ed645943a --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseChecker.java @@ -0,0 +1,209 @@ +package com.adjust.sdk.google.lvl; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +import com.adjust.sdk.ILogger; + +public class LicenseChecker { + private static final String GOOGLE_PLAY_PACKAGE = "com.android.vending"; + private static final String LICENSING_SERVICE_DESCRIPTOR = "com.android.vending.licensing.ILicensingService"; + private static final String RESULT_LISTENER_DESCRIPTOR = "com.android.vending.licensing.ILicenseResultListener"; + private static final int TRANSACTION_CHECK_LICENSE = IBinder.FIRST_CALL_TRANSACTION; + + // Error codes for better diagnostics + private static final int ERROR_GENERIC = -1; + private static final int ERROR_BIND_FAILED = -5; + private static final int ERROR_NO_BINDER = -3; + private static final int ERROR_TRANSACT_FAILED = -2; + private static final int ERROR_REMOTE_EXCEPTION = -4; + private static final int ERROR_BINDER_DIED = -6; + + private final Context mContext; + private final LicenseRawCallback mCallback; + private final ILogger logger; + private final long timestamp; + private final ResultListenerBinder resultListenerBinder; + + private IBinder mServiceBinder; + private boolean mBound; + private int retryCount = 0; + private static final int MAX_RETRIES = 3; + + public LicenseChecker(Context context, LicenseRawCallback callback, ILogger logger, long timestamp) { + this.mContext = context; + this.mCallback = callback; + this.logger = logger; + this.timestamp = timestamp; + this.resultListenerBinder = new ResultListenerBinder(); + } + + public synchronized void checkAccess() { + if (mBound) { + return; + } + logger.debug("LVL License check starts"); + + Intent serviceIntent = new Intent("com.android.vending.licensing.ILicensingService"); + serviceIntent.setPackage(GOOGLE_PLAY_PACKAGE); + boolean isBind = mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); + logger.debug("LVL bindService result: " + isBind); + + if (!isBind) { + logger.error("LVL failed to bind licensing service"); + mCallback.onError(ERROR_BIND_FAILED); + } + } + + public void onDestroy() { + logger.debug("LVL license checker destroyed"); + if (mBound) { + mContext.unbindService(mServiceConnection); + mBound = false; + } + // Ensure binder reference is cleared even if unbind fails + mServiceBinder = null; + } + + private final ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + logger.debug("LVL service connected"); + mServiceBinder = service; + mBound = true; + retryCount = 0; + + // Detect binder death proactively + try { + mServiceBinder.linkToDeath(() -> { + logger.error("LVL binder died unexpectedly"); + mCallback.onError(ERROR_BINDER_DIED); + onDestroy(); + }, 0); + } catch (RemoteException e) { + logger.error("LVL failed to link binder death recipient", e); + } + + executeLicenseCheck(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + logger.debug("LVL service disconnected"); + mServiceBinder = null; + mBound = false; + } + }; + + private void executeLicenseCheck() { + try { + if (mServiceBinder == null) { + logger.error("LVL binder unavailable for license check"); + mCallback.onError(ERROR_NO_BINDER); + return; + } + + String packageName = mContext.getPackageName(); + long nonce = generateNonce(timestamp); + logger.debug("LVL generated nonce: " + nonce); + + Parcel data = Parcel.obtain(); + try { + data.writeInterfaceToken(LICENSING_SERVICE_DESCRIPTOR); + data.writeLong(nonce); + data.writeString(packageName); + data.writeStrongBinder(resultListenerBinder); + boolean transacted = mServiceBinder.transact( + TRANSACTION_CHECK_LICENSE, + data, + null, + IBinder.FLAG_ONEWAY + ); + logger.debug("LVL binder transact sent (code " + TRANSACTION_CHECK_LICENSE + "): " + transacted); + if (!transacted) { + logger.error("LVL binder transact failed to enqueue"); + mCallback.onError(ERROR_TRANSACT_FAILED); + } + } finally { + data.recycle(); + } + } catch (RemoteException e) { + logger.error("LVL remote exception during license check: ", e); + mCallback.onError(ERROR_REMOTE_EXCEPTION); + } catch (Exception e) { + logger.error("LVL license check failed: ", e); + mCallback.onError(ERROR_GENERIC); + } + } + + private class ResultListenerBinder extends Binder implements IInterface { + ResultListenerBinder() { + attachInterface(this, RESULT_LISTENER_DESCRIPTOR); + } + + @Override + public IBinder asBinder() { + return this; + } + + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + if (code == IBinder.INTERFACE_TRANSACTION) { + if (reply != null) { + reply.writeString(RESULT_LISTENER_DESCRIPTOR); + } + return true; + } + + if (code == IBinder.FIRST_CALL_TRANSACTION) { + try { + data.enforceInterface(RESULT_LISTENER_DESCRIPTOR); + int responseCode = data.readInt(); + String signedData = data.readString(); + String signature = data.readString(); + + logger.debug("LVL received license response: " + responseCode); + + LicenseResponseHandler handler = new LicenseResponseHandler(mCallback, logger, MAX_RETRIES); + boolean shouldRetry = handler.handleResponse(responseCode, signedData, signature, retryCount); + if (shouldRetry) { + retryCount++; + logger.debug("LVL retrying license check... Attempt: " + retryCount); + executeLicenseCheck(); + } else { + onDestroy(); + } + return true; + } catch (Exception ex) { + logger.error("LVL failed to process license response: ", ex); + mCallback.onError(ERROR_GENERIC); + onDestroy(); + return true; + } + } + + return super.onTransact(code, data, reply, flags); + } + } + + /** + * Generates a 64-bit nonce with: + * - 56-bit reduced timestamp (in milliseconds) stored in bits 8–63 + * - 8-bit reserved field in bits 0–7 (currently using 0x01 as version marker) + */ + public static long generateNonce(long timestamp) { + // Mask to ensure we only keep the lowest 56 bits + long MASK_56_BITS = 0x00FFFFFFFFFFFFFFL; + long reducedTimestamp = timestamp & MASK_56_BITS; + + // Shift timestamp to occupy bits 8–63, reserve LSB for flags/version + return (reducedTimestamp << 8) | 0x01; + } +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseRawCallback.java b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseRawCallback.java new file mode 100644 index 000000000..c3e58dafe --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseRawCallback.java @@ -0,0 +1,6 @@ +package com.adjust.sdk.google.lvl; + +public interface LicenseRawCallback { + void onLicenseDataReceived(int responseCode, String signedData, String signature); + void onError(int errorCode); +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseResponseHandler.java b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseResponseHandler.java new file mode 100644 index 000000000..13b7825c1 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/LicenseResponseHandler.java @@ -0,0 +1,63 @@ +package com.adjust.sdk.google.lvl; + +import com.adjust.sdk.ILogger; + +public class LicenseResponseHandler { + private final LicenseRawCallback callback; + private final ILogger logger; + private final int maxRetries; + // Server response codes. + private static final int LICENSED = 0x0; + private static final int NOT_LICENSED = 0x1; + private static final int LICENSED_OLD_KEY = 0x2; + private static final int ERROR_NOT_MARKET_MANAGED = 0x3; + private static final int ERROR_SERVER_FAILURE = 0x4; + private static final int ERROR_OVER_QUOTA = 0x5; + + private static final int ERROR_CONTACTING_SERVER = 0x101; + private static final int ERROR_INVALID_PACKAGE_NAME = 0x102; + private static final int ERROR_NON_MATCHING_UID = 0x103; + + public LicenseResponseHandler(LicenseRawCallback callback, ILogger logger, int maxRetries) { + this.callback = callback; + this.logger = logger; + this.maxRetries = maxRetries; + } + + public boolean handleResponse(int responseCode, String signedData, String signature, int retryCount) { + switch (responseCode) { + case NOT_LICENSED: // NOT_LICENSED + case ERROR_INVALID_PACKAGE_NAME: // INVALID_PACKAGE_NAME + case ERROR_NON_MATCHING_UID: // NON_MATCHING_UID + case ERROR_NOT_MARKET_MANAGED: // NOT_MARKET_MANAGED + logger.warn("LVL license check failed: " + responseCode); + callback.onError(responseCode); + return false; + + case ERROR_CONTACTING_SERVER: // CONTACTING_SERVER_ERROR + case ERROR_SERVER_FAILURE: // SERVER_FAILURE + case ERROR_OVER_QUOTA: // refusing to talk to this device, over quota + if (retryCount < maxRetries) { + logger.warn("LVL retry attempt [" + (retryCount + 1) + "]: ", responseCode); + return true; // signal to retry + } else { + logger.error("LVL retry attempt [" + retryCount + "] failed after max retries: ", responseCode); + callback.onError(responseCode); + return false; + } + case LICENSED: // LICENSED + case LICENSED_OLD_KEY: // LICENSED_OLD_KEY + if (signedData != null && signature != null) { + callback.onLicenseDataReceived(responseCode, signedData, signature); + } else { + logger.error("LVL missing signed data or signature"); + callback.onError(responseCode); + } + return false; + default: + logger.error("LVL unexpected response code: ", responseCode); + callback.onError(responseCode); + return false; + } + } +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/Util.java b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/Util.java new file mode 100644 index 000000000..9053673af --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/main/java/com/adjust/sdk/google/lvl/Util.java @@ -0,0 +1,13 @@ +package com.adjust.sdk.google.lvl; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.LicenseData; + +public class Util { + + public synchronized static LicenseData getLicenseRequiredData(Context context, ILogger logger, long timestamp) { + return AdjustLicenseVerification.fetchLicenseDate(context, logger, timestamp); + } +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/ILogger.java b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/ILogger.java new file mode 100644 index 000000000..1dce371ab --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/ILogger.java @@ -0,0 +1,9 @@ +package com.adjust.sdk; + +public interface ILogger { + void debug(String message, Object... params); + void info(String message, Object... params); + void warn(String message, Object... params); + void error(String message, Object... params); +} + diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerIntegrationTest.java b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerIntegrationTest.java new file mode 100644 index 000000000..41c1ad61b --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerIntegrationTest.java @@ -0,0 +1,85 @@ +package com.adjust.sdk.google.lvl; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.content.ServiceConnection; +import android.os.Parcel; +import android.os.RemoteException; + +import com.adjust.sdk.ILogger; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.mockito.Mockito.*; + +@RunWith(RobolectricTestRunner.class) +@Config(sdk = 33) // or 34, must be <= 34 +public class LicenseCheckerIntegrationTest { + + private Context context; + private LicenseRawCallback mockCallback; + private ILogger mockLogger; + private LicenseChecker licenseChecker; + + @Before + public void setUp() { + context = mock(Context.class); + mockCallback = mock(LicenseRawCallback.class); + mockLogger = mock(ILogger.class); + licenseChecker = new LicenseChecker(context, mockCallback, mockLogger, System.currentTimeMillis()); + } + + @Test + public void testSuccessfulLicenseCheck_shouldCallCallback() { + doAnswer(invocation -> { + ServiceConnection conn = invocation.getArgument(1); + IBinder binder = new Binder() { + private static final String SERVICE_DESCRIPTOR = "com.android.vending.licensing.ILicensingService"; + private static final String LISTENER_DESCRIPTOR = "com.android.vending.licensing.ILicenseResultListener"; + + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + if (code == IBinder.INTERFACE_TRANSACTION) { + if (reply != null) { + reply.writeString(SERVICE_DESCRIPTOR); + } + return true; + } + + if (code == IBinder.FIRST_CALL_TRANSACTION) { + data.enforceInterface(SERVICE_DESCRIPTOR); + long nonce = data.readLong(); + String packageName = data.readString(); + IBinder listenerBinder = data.readStrongBinder(); + + Parcel response = Parcel.obtain(); + try { + response.writeInterfaceToken(LISTENER_DESCRIPTOR); + response.writeInt(0); + response.writeString("signedData"); + response.writeString("signature"); + listenerBinder.transact(IBinder.FIRST_CALL_TRANSACTION, response, null, IBinder.FLAG_ONEWAY); + } finally { + response.recycle(); + } + return true; + } + return super.onTransact(code, data, reply, flags); + } + }; + conn.onServiceConnected(new ComponentName("com.android.vending", "LicensingService"), binder); + return true; + }).when(context).bindService(any(Intent.class), any(), anyInt()); + + licenseChecker.checkAccess(); + verify(mockCallback, timeout(1000)).onLicenseDataReceived(eq(0), eq("signedData"), eq("signature")); + } +} diff --git a/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerNonceTest.java b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerNonceTest.java new file mode 100644 index 000000000..78ab6faf2 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-google-lvl/src/test/java/com/adjust/sdk/google/lvl/LicenseCheckerNonceTest.java @@ -0,0 +1,63 @@ +package com.adjust.sdk.google.lvl; + +import org.junit.Test; + +import static org.junit.Assert.*; + +import com.adjust.sdk.google.lvl.LicenseChecker; + +public class LicenseCheckerNonceTest { + + @Test + public void testGenerateNonce_containsVersionByte() { + long timestamp = System.currentTimeMillis(); + long nonce = LicenseChecker.generateNonce(timestamp); + assertEquals("LSB should be 0x01 (version/flag)", 0x01, nonce & 0xFF); + } + + @Test + public void testGenerateNonce_timestampPacking_isCorrect() { + long timestamp = 1720000000000L; // Epoch in ms + long expectedSeconds =timestamp & 0x00FFFFFFFFFFFFFFL; + long nonce = LicenseChecker.generateNonce(timestamp); + + long extractedSeconds = (nonce >>> 8); // remove version byte + assertEquals("Timestamp in nonce should match expected seconds", expectedSeconds, extractedSeconds); + } + + @Test + public void testGenerateNonce_zeroTimestamp_shouldStillWork() { + long nonce = LicenseChecker.generateNonce(0L); + assertEquals("Should only have version byte set", 0x01, nonce); + } + + @Test + public void testGenerateNonce_nearLimit_doesNotOverflowSafe() { + // Use a timestamp that still fits in millis without overflowing long + long safeMillis = (1L << 53); // 53 bits (won't overflow when *1000) + + long nonce = LicenseChecker.generateNonce(safeMillis); + long extractedMillis = nonce >>> 8; + + assertEquals("Should safely extract 53-bit timestamp", safeMillis, extractedMillis); + } + + + + @Test + public void testGenerateNonce_truncatesIfAbove56Bits() { + long overMaxTimestampMs = ((1L << 56) + 9999L); // milliseconds that overflow 56-bit seconds + + long nonce = LicenseChecker.generateNonce(overMaxTimestampMs); + long extracted = (nonce >>> 8); + + assertTrue("Extracted timestamp must be less than 2^56", extracted < (1L << 56)); + } + + @Test + public void testGenerateNonce_multipleCalls_differentResults() { + long t1 = LicenseChecker.generateNonce(System.currentTimeMillis()); + long t2 = LicenseChecker.generateNonce(System.currentTimeMillis() + 2000); + assertNotEquals("Nonces from different times should differ", t1, t2); + } +} diff --git a/Adjust/sdk-plugin-samsung-clouddev/.gitignore b/Adjust/plugins/sdk-plugin-huawei-referrer/.gitignore similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/.gitignore rename to Adjust/plugins/sdk-plugin-huawei-referrer/.gitignore diff --git a/MIT-LICENSE b/Adjust/plugins/sdk-plugin-huawei-referrer/LICENSE similarity index 94% rename from MIT-LICENSE rename to Adjust/plugins/sdk-plugin-huawei-referrer/LICENSE index f4d1af881..242e5d555 100644 --- a/MIT-LICENSE +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/LICENSE @@ -1,5 +1,4 @@ -Copyright (c) 2012-2017 adjust GmbH, -http://www.adjust.com +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/build.gradle b/Adjust/plugins/sdk-plugin-huawei-referrer/build.gradle new file mode 100644 index 000000000..5465d684f --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/build.gradle @@ -0,0 +1,228 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } +} + +android { + compileSdk rootProject.ext.coreCompileSdkVersion + publishing { + multipleVariants { + allVariants() + withJavadocJar() + } + } + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } + } + namespace 'com.adjust.sdk.huawei' +} + +dependencies { + // Add SDK via module. + compileOnly project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:5.8.0' +} + +// read local properties +File localPropsFile = project.rootProject.file('local.properties') +if (localPropsFile.exists()) { + Properties p = new Properties() + new FileInputStream(localPropsFile).withCloseable { is -> + p.load(is) + } + p.each { name, value -> + ext[name] = value + } +} + +task adjustHuaweiReferrerPluginAar(type: Copy) { + dependsOn 'assembleRelease' + + from('build/outputs/aar/') + include 'sdk-plugin-huawei-referrer-release.aar' + destinationDir file('build/libs/') + rename 'sdk-plugin-huawei-referrer-release.aar', "${project.name}.aar" + +} + +task adjustHuaweiReferrerPluginJar(type: Jar) { + dependsOn 'packageReleaseAssets' + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/library_assets/release/packageReleaseAssets/out/') { + into('assets') + } + from('build/intermediates/javac/release/classes/') + + archiveFileName = project.provider { "${project.name}.jar" } +} + + +task adjustHuaweiReferrerPluginSourcesJar(type: Jar) { + setArchiveClassifier('sources') + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustHuaweiReferrerPluginJar + archives adjustHuaweiReferrerPluginSourcesJar +} + +afterEvaluate { + publishing { + publications { +/* + mavenAndroidHuaweiReferrerJar(MavenPublication) { + customizePomForJar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-huawei-referrer' + version rootProject.ext.coreVersionName + + artifact adjustHuaweiReferrerPluginJar + artifact adjustHuaweiReferrerPluginSourcesJar + } +*/ + mavenAndroidHuaweiReferrerAar(MavenPublication) { + customizePomForAar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-huawei-referrer' + version rootProject.ext.coreVersionName + + artifact("$buildDir/outputs/aar/sdk-plugin-huawei-referrer-release.aar") { + builtBy tasks.getByPath("adjustHuaweiReferrerPluginAar") + } + artifact adjustHuaweiReferrerPluginSourcesJar + } + } + + repositories { + maven { + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } + } + signing { +// sign publishing.publications.mavenAndroidHuaweiReferrerJar + sign publishing.publications.mavenAndroidHuaweiReferrerAar + } +} + +def customizePomForJar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Huawei Referrer plugin for Adjust SDK for Android' + name 'Adjust Android SDK Huawei Referrer plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +def customizePomForAar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Huawei Referrer plugin for Adjust SDK for Android' + name 'Adjust Android SDK Huawei Referrer plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { +// tasks.generatePomFileForMavenAndroidHuaweiReferrerJarPublication { +// destination = file("${project.buildDir}/generated-pom.xml") +// } + /* TODO check if/how to replace this tasks + tasks.publishMavenAndroidHuaweiReferrerPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidHuaweiReferrerPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } + */ + tasks.generatePomFileForMavenAndroidHuaweiReferrerAarPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } +} + + diff --git a/Adjust/sdk-plugin-imei/proguard-rules.pro b/Adjust/plugins/sdk-plugin-huawei-referrer/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-imei/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-huawei-referrer/proguard-rules.pro diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/AndroidManifest.xml new file mode 100644 index 000000000..38548e7f2 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/AdjustHuaweiReferrer.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/AdjustHuaweiReferrer.java new file mode 100644 index 000000000..fe4ed5da5 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/AdjustHuaweiReferrer.java @@ -0,0 +1,90 @@ +package com.adjust.sdk.huawei; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; + +public class AdjustHuaweiReferrer { + + static boolean shouldReadHuaweiReferrer = true; + + /** + * Called to get Huawei Install Referrer. + * + * @param context Application context + * @param onHuaweiInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getHuaweiAppGalleryInstallReferrer(final Context context, final OnHuaweiInstallReferrerReadListener onHuaweiInstallReferrerReadListener) { + if (onHuaweiInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onHuaweiInstallReferrerReadListener can not be null"); + return; + } + new AsyncTaskExecutor() { + @Override + protected HuaweiInstallReferrerResult doInBackground(Context[] contexts) { + try { + return HuaweiReferrerClient.getHuaweiAppGalleryInstallReferrer(context, AdjustFactory.getLogger()); + } catch (Exception exception) { + return new HuaweiInstallReferrerResult(exception.getMessage()); + } + } + + @Override + protected void onPostExecute(HuaweiInstallReferrerResult huaweiInstallReferrerResult) { + if (huaweiInstallReferrerResult != null) { + if (huaweiInstallReferrerResult.huaweiInstallReferrerDetails != null) { + onHuaweiInstallReferrerReadListener.onInstallReferrerDetailsRead(huaweiInstallReferrerResult.huaweiInstallReferrerDetails); + } else if (huaweiInstallReferrerResult.error != null) { + onHuaweiInstallReferrerReadListener.onFail(huaweiInstallReferrerResult.error); + }else { + onHuaweiInstallReferrerReadListener.onFail("HuaweiReferrer getInstallReferrer: huaweiInstallReferrerDetails is null"); + } + }else { + onHuaweiInstallReferrerReadListener.onFail("HuaweiReferrer getInstallReferrer: huaweiInstallReferrerResult is null"); + } + } + }.execute(context); + } + + public static void getHuaweiAdsInstallReferrer(final Context context, final OnHuaweiInstallReferrerReadListener onHuaweiInstallReferrerReadListener) { + if (onHuaweiInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onHuaweiInstallReferrerReadListener can not be null"); + return; + } + new AsyncTaskExecutor() { + @Override + protected HuaweiInstallReferrerResult doInBackground(Context[] contexts) { + try { + return HuaweiReferrerClient.getHuaweiAdsInstallReferrer(context, AdjustFactory.getLogger()); + } catch (Exception exception) { + return new HuaweiInstallReferrerResult(exception.getMessage()); + } + } + @Override + protected void onPostExecute(HuaweiInstallReferrerResult huaweiInstallReferrerResult) { + if (huaweiInstallReferrerResult != null) { + if (huaweiInstallReferrerResult.huaweiInstallReferrerDetails != null) { + onHuaweiInstallReferrerReadListener.onInstallReferrerDetailsRead(huaweiInstallReferrerResult.huaweiInstallReferrerDetails); + } else if (huaweiInstallReferrerResult.error != null) { + onHuaweiInstallReferrerReadListener.onFail(huaweiInstallReferrerResult.error); + }else { + onHuaweiInstallReferrerReadListener.onFail("HuaweiReferrer getInstallReferrer: huaweiInstallReferrerDetails is null"); + } + }else { + onHuaweiInstallReferrerReadListener.onFail("HuaweiReferrer getInstallReferrer: huaweiInstallReferrerResult is null"); + } + } + }.execute(context); + + } + + public static void readHuaweiReferrer(Context context) { + shouldReadHuaweiReferrer = true; + } + + public static void doNotReadHuaweiReferrer() { + shouldReadHuaweiReferrer = false; + } +} diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerDetails.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerDetails.java new file mode 100644 index 000000000..40410b966 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerDetails.java @@ -0,0 +1,26 @@ +package com.adjust.sdk.huawei; + +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.Util; + +public class HuaweiInstallReferrerDetails { + public String installReferrer; // The referrer URL of the installed package. + public long referrerClickTimestampSeconds; // The client-side timestamp, when the referrer click happened. + public long installBeginTimestampSeconds; // The client-side timestamp, when app installation began. + + HuaweiInstallReferrerDetails(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds) { + this.installReferrer = installReferrer; + this.referrerClickTimestampSeconds = referrerClickTimestampSeconds; + this.installBeginTimestampSeconds = installBeginTimestampSeconds; + } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " referrerClickTimestampSeconds : %d" + + " installBeginTimestampSeconds : %d", + installReferrer, + referrerClickTimestampSeconds, + installBeginTimestampSeconds); + } +} diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerResult.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerResult.java new file mode 100644 index 000000000..fa3aa9fc7 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiInstallReferrerResult.java @@ -0,0 +1,14 @@ +package com.adjust.sdk.huawei; + +public class HuaweiInstallReferrerResult { + public String error; + public HuaweiInstallReferrerDetails huaweiInstallReferrerDetails; + + HuaweiInstallReferrerResult(HuaweiInstallReferrerDetails huaweiInstallReferrerDetails) { + this.huaweiInstallReferrerDetails = huaweiInstallReferrerDetails; + } + + public HuaweiInstallReferrerResult(String error) { + this.error = error; + } +} \ No newline at end of file diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiReferrerClient.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiReferrerClient.java new file mode 100644 index 000000000..787df3f16 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/HuaweiReferrerClient.java @@ -0,0 +1,229 @@ +package com.adjust.sdk.huawei; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.Util; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class HuaweiReferrerClient { + + /** + * Huawei install referrer provider content authority. + */ + private static final String REFERRER_PROVIDER_AUTHORITY = "com.huawei.appmarket.commondata"; + + /** + * Huawei install referrer provider content uri. + */ + private static final String REFERRER_PROVIDER_URI = "content://" + REFERRER_PROVIDER_AUTHORITY + "/item/5"; + + /** + * Huawei install referrer provider column index referrer. + */ + private static final int COLUMN_INDEX_REFERRER = 0; + + /** + * Huawei install referrer provider column index click time. + */ + private static final int COLUMN_INDEX_CLICK_TIME = 1; + + /** + * Huawei install referrer provider column index install time. + */ + private static final int COLUMN_INDEX_INSTALL_TIME = 2; + + /** + * Huawei install referrer provider column index track ID. + */ + private static final int COLUMN_INDEX_TRACK_ID = 4; + + /** + * Boolean indicating whether to read HuaweiAdsReferrer. + * Either because it has not yet tried, + * or it did and it was successful + * or it did, was not successful, but it should not retry + */ + private static final AtomicBoolean shouldTryToReadHuaweiAdsReferrer = new AtomicBoolean(true); + + /** + * Boolean indicating whether to read HuaweiAdsReferrer. + * Either because it has not yet tried, + * or it did and it was successful + * or it did, was not successful, but it should not retry + */ + private static final AtomicBoolean shouldTryToReadHuaweiAppGalleryReferrer = new AtomicBoolean(true); + + public static HuaweiInstallReferrerResult getHuaweiAdsInstallReferrer(Context context, final ILogger logger) { + + String errorMessage = null; + if (!shouldTryToReadHuaweiAdsReferrer.get()) { + errorMessage = "Should not try to read HuaweiAdsInstallReferrer"; + logger.info(errorMessage); + return new HuaweiInstallReferrerResult(errorMessage); + } + + if (!resolveContentProvider(context, REFERRER_PROVIDER_AUTHORITY)) { + errorMessage = "HuaweiAdsInstallReferrer fail to resolve content provider"; + return new HuaweiInstallReferrerResult(errorMessage); + } + + Cursor cursor = null; + + try { + Uri uri = Uri.parse(REFERRER_PROVIDER_URI); + ContentResolver contentResolver = context.getContentResolver(); + String[] packageName = new String[] { context.getPackageName() }; + cursor = contentResolver.query(uri, null, null, packageName, null); + + if (cursor != null && cursor.moveToFirst()) { + + String referrerHuaweiAds = cursor.getString(COLUMN_INDEX_REFERRER); + + logger.debug("HuaweiAdsInstallReferrer index_referrer[%s]", referrerHuaweiAds); + + String clickTime = cursor.getString(COLUMN_INDEX_CLICK_TIME); + String installTime = cursor.getString(COLUMN_INDEX_INSTALL_TIME); + + logger.debug("HuaweiAdsInstallReferrer " + + "clickTime[%s] installTime[%s]", clickTime, installTime ); + + long referrerClickTimestampSeconds = Long.parseLong(clickTime); + long installBeginTimestampSeconds = Long.parseLong(installTime); + + if (isValidHuaweiAdsInstallReferrer(referrerHuaweiAds)) { + HuaweiInstallReferrerDetails huaweiInstallReferrerDetails = new HuaweiInstallReferrerDetails(referrerHuaweiAds, + referrerClickTimestampSeconds, + installBeginTimestampSeconds); + return new HuaweiInstallReferrerResult(huaweiInstallReferrerDetails); + }else { + return new HuaweiInstallReferrerResult("Invalid HuaweiAdsInstallReferrer"); + } + + } else { + errorMessage = Util.formatString("HuaweiAdsInstallReferrer fail to read referrer for " + + "package [%s] and content uri [%s]", + context.getPackageName(), uri.toString()); + logger.debug(errorMessage); + } + + shouldTryToReadHuaweiAdsReferrer.set(false); + + } catch (Exception e) { + errorMessage = "HuaweiAdsInstallReferrer error [" + e.getMessage() + "]"; + logger.debug(errorMessage); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return new HuaweiInstallReferrerResult(errorMessage); + } + + public static HuaweiInstallReferrerResult getHuaweiAppGalleryInstallReferrer(Context context, final ILogger logger) { + String errorMessage = null; + if (!shouldTryToReadHuaweiAppGalleryReferrer.get()) { + errorMessage = "Should not try to read HuaweiAppGalleryInstallReferrer"; + logger.debug(errorMessage); + return new HuaweiInstallReferrerResult(errorMessage); + } + + if (!resolveContentProvider(context, REFERRER_PROVIDER_AUTHORITY)) { + errorMessage = "HuaweiAppGalleryInstallReferrer fail to resolve content provider"; + return new HuaweiInstallReferrerResult(errorMessage); + } + + Cursor cursor = null; + + try { + Uri uri = Uri.parse(REFERRER_PROVIDER_URI); + ContentResolver contentResolver = context.getContentResolver(); + String[] packageName = new String[] { context.getPackageName() }; + cursor = contentResolver.query(uri, null, null, packageName, null); + + if (cursor != null && cursor.moveToFirst()) { + + String referrerHuaweiAppGallery = cursor.getString(COLUMN_INDEX_TRACK_ID); + + logger.debug("HuaweiAppGalleryInstallReferrer index_track_id[%s]", referrerHuaweiAppGallery); + + String clickTime = cursor.getString(COLUMN_INDEX_CLICK_TIME); + String installTime = cursor.getString(COLUMN_INDEX_INSTALL_TIME); + + logger.debug("HuaweiAppGalleryInstallReferrer " + + "clickTime[%s] installTime[%s]", clickTime, installTime ); + + long referrerClickTimestampSeconds = Long.parseLong(clickTime); + long installBeginTimestampSeconds = Long.parseLong(installTime); + + if (isValidHuaweiAppGalleryInstallReferrer(referrerHuaweiAppGallery)) { + HuaweiInstallReferrerDetails huaweiInstallReferrerDetails = new HuaweiInstallReferrerDetails(referrerHuaweiAppGallery, + referrerClickTimestampSeconds, + installBeginTimestampSeconds); + return new HuaweiInstallReferrerResult(huaweiInstallReferrerDetails); + }else { + new HuaweiInstallReferrerResult("Invalid HuaweiAppGalleryInstallReferrer"); + } + + } else { + errorMessage = Util.formatString( + "HuaweiAppGalleryInstallReferrer fail to read referrer for " + + "package [%s] and content uri [%s]", + context.getPackageName(), uri.toString()); + logger.debug(errorMessage); + } + + shouldTryToReadHuaweiAppGalleryReferrer.set(false); + + } catch (Exception e) { + errorMessage = "HuaweiAppGalleryInstallReferrer error [" + e.getMessage() + "]"; + logger.debug(errorMessage); + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return new HuaweiInstallReferrerResult(errorMessage); + } + + private static boolean resolveContentProvider(final Context applicationContext, + final String authority) { + try { + return (applicationContext.getPackageManager() + .resolveContentProvider(authority, 0) != null); + + } catch (Exception e) { + return false; + } + } + + private static boolean isValidHuaweiAdsInstallReferrer(String referrerHuaweiAds) { + if (referrerHuaweiAds == null) { + return false; + } + + if (referrerHuaweiAds.isEmpty()) { + return false; + } + + return true; + } + + private static boolean isValidHuaweiAppGalleryInstallReferrer(String referrerHuaweiAppGallery) { + if (referrerHuaweiAppGallery == null) { + return false; + } + + if (referrerHuaweiAppGallery.isEmpty()) { + return false; + } + + return true; + } +} diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/OnHuaweiInstallReferrerReadListener.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/OnHuaweiInstallReferrerReadListener.java new file mode 100644 index 000000000..eefdfe942 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/OnHuaweiInstallReferrerReadListener.java @@ -0,0 +1,8 @@ +package com.adjust.sdk.huawei; + +import com.adjust.sdk.ReferrerDetails; + +public interface OnHuaweiInstallReferrerReadListener { + void onInstallReferrerDetailsRead(HuaweiInstallReferrerDetails referrerDetails); + void onFail(String message); +} diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/Util.java b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/Util.java new file mode 100644 index 000000000..6006660a1 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/java/com/adjust/sdk/huawei/Util.java @@ -0,0 +1,52 @@ +package com.adjust.sdk.huawei; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; + +public class Util { + public synchronized static ReferrerDetails getHuaweiAdsInstallReferrerDetails(Context context, ILogger logger) { + if (!AdjustHuaweiReferrer.shouldReadHuaweiReferrer) { + return null; + } + + logger.info("getHuaweiAdsInstallReferrerDetails invoked"); + + HuaweiInstallReferrerResult huaweiInstallReferrerResult = HuaweiReferrerClient.getHuaweiAdsInstallReferrer(context, logger); + if (huaweiInstallReferrerResult == null) { + return null; + } + if (huaweiInstallReferrerResult.huaweiInstallReferrerDetails == null) { + return null; + } + HuaweiInstallReferrerDetails huaweiInstallReferrerDetails = huaweiInstallReferrerResult.huaweiInstallReferrerDetails; + return new ReferrerDetails( + huaweiInstallReferrerDetails.installReferrer, + huaweiInstallReferrerDetails.referrerClickTimestampSeconds, + huaweiInstallReferrerDetails.installBeginTimestampSeconds); + } + + public synchronized static ReferrerDetails getHuaweiAppGalleryInstallReferrerDetails(Context context, ILogger logger) { + if (!AdjustHuaweiReferrer.shouldReadHuaweiReferrer) { + return null; + } + + logger.info("getHuaweiAppGalleryInstallReferrerDetails invoked"); + + HuaweiInstallReferrerResult huaweiInstallReferrerResult = HuaweiReferrerClient.getHuaweiAppGalleryInstallReferrer(context, logger); + if (huaweiInstallReferrerResult == null) { + return null; + } + if (huaweiInstallReferrerResult.huaweiInstallReferrerDetails == null) { + return null; + } + + HuaweiInstallReferrerDetails huaweiInstallReferrerDetails = huaweiInstallReferrerResult.huaweiInstallReferrerDetails; + return new ReferrerDetails( + huaweiInstallReferrerDetails.installReferrer, + huaweiInstallReferrerDetails.referrerClickTimestampSeconds, + huaweiInstallReferrerDetails.installBeginTimestampSeconds + ); + } +} diff --git a/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/res/values/strings.xml new file mode 100644 index 000000000..56100320c --- /dev/null +++ b/Adjust/plugins/sdk-plugin-huawei-referrer/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + AdjustPluginHuaweiReferrer + diff --git a/Adjust/sdk-plugin-criteo/.gitignore b/Adjust/plugins/sdk-plugin-imei/.gitignore similarity index 100% rename from Adjust/sdk-plugin-criteo/.gitignore rename to Adjust/plugins/sdk-plugin-imei/.gitignore diff --git a/Adjust/plugins/sdk-plugin-imei/LICENSE b/Adjust/plugins/sdk-plugin-imei/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-imei/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-imei/build.gradle b/Adjust/plugins/sdk-plugin-imei/build.gradle similarity index 91% rename from Adjust/sdk-plugin-imei/build.gradle rename to Adjust/plugins/sdk-plugin-imei/build.gradle index 328af7e38..54ff5e84d 100644 --- a/Adjust/sdk-plugin-imei/build.gradle +++ b/Adjust/plugins/sdk-plugin-imei/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } @@ -21,6 +21,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.coreMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.imei' } @@ -30,7 +33,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' } // read local properties @@ -106,7 +109,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/sdk-plugin-samsung-referrer/proguard-rules.pro b/Adjust/plugins/sdk-plugin-imei/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-samsung-referrer/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-imei/proguard-rules.pro diff --git a/Adjust/sdk-plugin-imei/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-imei/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-imei/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-imei/src/main/AndroidManifest.xml diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java b/Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java similarity index 100% rename from Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java rename to Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/AdjustImei.java diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java b/Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java similarity index 100% rename from Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java rename to Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/TelephonyIdsUtil.java diff --git a/Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java b/Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java similarity index 100% rename from Adjust/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java rename to Adjust/plugins/sdk-plugin-imei/src/main/java/com/adjust/sdk/imei/Util.java diff --git a/Adjust/sdk-plugin-imei/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-imei/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-imei/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-imei/src/main/res/values/strings.xml diff --git a/Adjust/sdk-plugin-samsung-referrer/.gitignore b/Adjust/plugins/sdk-plugin-meta-referrer/.gitignore similarity index 100% rename from Adjust/sdk-plugin-samsung-referrer/.gitignore rename to Adjust/plugins/sdk-plugin-meta-referrer/.gitignore diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/LICENSE b/Adjust/plugins/sdk-plugin-meta-referrer/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/build.gradle b/Adjust/plugins/sdk-plugin-meta-referrer/build.gradle new file mode 100644 index 000000000..cf9db099b --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/build.gradle @@ -0,0 +1,228 @@ +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' +apply plugin: 'signing' + +repositories { + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } +} + +android { + compileSdk rootProject.ext.coreCompileSdkVersion + publishing { + multipleVariants { + allVariants() + withJavadocJar() + } + } + defaultConfig { + minSdkVersion rootProject.ext.coreMinSdkVersion + targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } + } + namespace 'com.adjust.sdk.meta' +} + +dependencies { + // Add SDK via module. + compileOnly project(':sdk-core') + // Add SDK via Maven. + // implementation 'com.adjust.sdk:adjust-android:5.8.0' +} + +// read local properties +File localPropsFile = project.rootProject.file('local.properties') +if (localPropsFile.exists()) { + Properties p = new Properties() + new FileInputStream(localPropsFile).withCloseable { is -> + p.load(is) + } + p.each { name, value -> + ext[name] = value + } +} + +task adjustMetaReferrerPluginAar(type: Copy) { + dependsOn 'assembleRelease' + + from('build/outputs/aar/') + include 'sdk-plugin-meta-referrer-release.aar' + destinationDir file('build/libs/') + rename 'sdk-plugin-meta-referrer-release.aar', "${project.name}.aar" + +} + +task adjustMetaReferrerPluginJar(type: Jar) { + dependsOn 'packageReleaseAssets' + dependsOn 'compileReleaseJavaWithJavac' + + from('build/intermediates/library_assets/release/packageReleaseAssets/out/') { + into('assets') + } + from('build/intermediates/javac/release/classes/') + + archiveFileName = project.provider { "${project.name}.jar" } +} + + +task adjustMetaReferrerPluginSourcesJar(type: Jar) { + setArchiveClassifier('sources') + from android.sourceSets.main.java.srcDirs +} + +artifacts { + archives adjustMetaReferrerPluginJar + archives adjustMetaReferrerPluginSourcesJar +} + +afterEvaluate { + publishing { + publications { +/* + mavenAndroidMetaReferrerJar(MavenPublication) { + customizePomForJar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-meta-referrer' + version rootProject.ext.coreVersionName + + artifact adjustMetaReferrerPluginJar + artifact adjustMetaReferrerPluginSourcesJar + } +*/ + mavenAndroidMetaReferrerAar(MavenPublication) { + customizePomForAar(pom) + groupId rootProject.ext.adjustGroupId + artifactId 'adjust-android-meta-referrer' + version rootProject.ext.coreVersionName + + artifact("$buildDir/outputs/aar/sdk-plugin-meta-referrer-release.aar") { + builtBy tasks.getByPath("adjustMetaReferrerPluginAar") + } + artifact adjustMetaReferrerPluginSourcesJar + } + } + + repositories { + maven { + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } + if (project.hasProperty("sonatypeUsername")) { + credentials { + username sonatypeUsername + password sonatypePassword + } + } + } + } + } + signing { +// sign publishing.publications.mavenAndroidMetaReferrerJar + sign publishing.publications.mavenAndroidMetaReferrerAar + } +} + +def customizePomForJar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Meta Referrer plugin for Adjust SDK for Android' + name 'Adjust Android SDK Meta Referrer plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +def customizePomForAar(pom) { + pom.withXml { + def root = asNode() + + // Add all items necessary for maven central publication. + root.children().last() + { + resolveStrategy = Closure.DELEGATE_FIRST + description 'The Meta Referrer plugin for Adjust SDK for Android' + name 'Adjust Android SDK Meta Referrer plugin' + url 'https://github.com/adjust/android_sdk' + + organization { + name 'adjust GmbH' + url 'http://www.adjust.com' + } + licenses { + license { + name 'MIT License' + url 'http://www.opensource.org/licenses/mit-license.php' + } + } + scm { + url 'git@github.com:adjust/android_sdk.git' + connection 'scm:git:git@github.com:adjust/android_sdk.git' + developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' + } + developers { + developer { + name 'Pedro Silva' + email 'pedro@adjust.com' + } + developer { + name 'Ugljesa Erceg' + email 'ugljesa@adjust.com' + } + } + } + } +} + +model { +// tasks.generatePomFileForMavenAndroidMetaReferrerJarPublication { +// destination = file("${project.buildDir}/generated-pom.xml") +// } + /* TODO check if/how to replace this tasks + tasks.publishMavenAndroidMetaReferrerPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenAndroidMetaReferrerPublicationToMavenRepository { + dependsOn project.tasks.signArchives + } + */ + tasks.generatePomFileForMavenAndroidMetaReferrerAarPublication { + destination = file("${project.buildDir}/generated-pom.xml") + } +} + + diff --git a/Adjust/sdk-plugin-vivo-referrer/proguard-rules.pro b/Adjust/plugins/sdk-plugin-meta-referrer/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-vivo-referrer/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-meta-referrer/proguard-rules.pro diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/AndroidManifest.xml new file mode 100644 index 000000000..f7a0fdec2 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/AdjustMetaReferrer.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/AdjustMetaReferrer.java new file mode 100644 index 000000000..3c3e6b3d1 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/AdjustMetaReferrer.java @@ -0,0 +1,59 @@ +package com.adjust.sdk.meta; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; + +public class AdjustMetaReferrer { + + static boolean shouldReadMetaReferrer = true; + + /** + * Called to get Meta Install Referrer. + * + * @param context Application context + * @param fbAppId FB App Id + * @param onMetaInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getMetaInstallReferrer(final Context context, final String fbAppId, + final OnMetaInstallReferrerReadListener onMetaInstallReferrerReadListener) { + if (onMetaInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onMetaInstallReferrerReadListener can not be null"); + return; + } + new AsyncTaskExecutor() { + @Override + protected MetaInstallReferrerResult doInBackground(Context[] contexts) { + try { + return MetaReferrerClient.getMetaInstallReferrer(context, fbAppId, AdjustFactory.getLogger(), false); + } catch (Exception exception) { + return new MetaInstallReferrerResult(exception.getMessage()); + } + } + + @Override + protected void onPostExecute(MetaInstallReferrerResult metaInstallReferrerResult) { + if (metaInstallReferrerResult != null) { + if (metaInstallReferrerResult.metaInstallReferrerDetails != null) { + onMetaInstallReferrerReadListener.onInstallReferrerDetailsRead(metaInstallReferrerResult.metaInstallReferrerDetails); + } else if (metaInstallReferrerResult.error != null) { + onMetaInstallReferrerReadListener.onFail(metaInstallReferrerResult.error); + } else { + onMetaInstallReferrerReadListener.onFail("Meta Install Referrer details null"); + } + } else { + onMetaInstallReferrerReadListener.onFail("Meta Install Referrer result null"); + } + } + }.execute(context); + } + + public static void readMetaReferrer(Context context) { + shouldReadMetaReferrer = true; + } + + public static void doNotReadMetaReferrer() { + shouldReadMetaReferrer = false; + } +} diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerDetails.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerDetails.java new file mode 100644 index 000000000..1c62bdece --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerDetails.java @@ -0,0 +1,24 @@ +package com.adjust.sdk.meta; + +import com.adjust.sdk.Util; + +public class MetaInstallReferrerDetails { + public String installReferrer; // The referrer URL of the installed package. + public long actualTimestampInSec; // The actual timestamp in seconds. + public boolean isClick; // Whether its click or not. + + MetaInstallReferrerDetails(String installReferrer, long actualTimestampInSec, boolean isClick) { + this.installReferrer = installReferrer; + this.actualTimestampInSec = actualTimestampInSec; + this.isClick = isClick; + } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " actualTimestampInSec : %d" + + " isClick : %b", + installReferrer, + actualTimestampInSec, + isClick); + }} diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerResult.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerResult.java new file mode 100644 index 000000000..88d579be2 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaInstallReferrerResult.java @@ -0,0 +1,14 @@ +package com.adjust.sdk.meta; + +public class MetaInstallReferrerResult { + public MetaInstallReferrerDetails metaInstallReferrerDetails; + public String error; + + MetaInstallReferrerResult(MetaInstallReferrerDetails metaInstallReferrerDetails) { + this.metaInstallReferrerDetails = metaInstallReferrerDetails; + } + + public MetaInstallReferrerResult(String error) { + this.error = error; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerMeta.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaReferrerClient.java similarity index 50% rename from Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerMeta.java rename to Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaReferrerClient.java index d7517f3bf..06851d2dd 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerMeta.java +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/MetaReferrerClient.java @@ -1,4 +1,4 @@ -package com.adjust.sdk; +package com.adjust.sdk.meta; import android.content.ContentResolver; import android.content.Context; @@ -6,9 +6,13 @@ import android.net.Uri; import android.text.TextUtils; +import com.adjust.sdk.ILogger; +import com.adjust.sdk.Util; + import java.util.concurrent.atomic.AtomicBoolean; -public class InstallReferrerMeta { +public class MetaReferrerClient { + /** * Facebook install referrer provider content authority. */ @@ -19,6 +23,11 @@ public class InstallReferrerMeta { */ private static final String INSTAGRAM_REFERRER_PROVIDER_AUTHORITY = "com.instagram.contentprovider.InstallReferrerProvider"; + /** + * FBLite install referrer provider content authority. + */ + private static final String FBLITE_REFERRER_PROVIDER_AUTHORITY = "com.facebook.lite.provider.InstallReferrerProvider"; + /** * Meta referrer content provider install referrer column name. */ @@ -34,60 +43,30 @@ public class InstallReferrerMeta { */ private static final String COLUMN_IS_CT = "is_ct"; - /** - * Adjust logger instance. - */ - private ILogger logger; - - /** - * Application context. - */ - private Context context; - - /** - * FB app ID. - */ - private String fbAppId; - - /** - * Huawei Referrer callback. - */ - private final InstallReferrerReadListener referrerCallback; - /** * Boolean indicating whether service should be tried to read. * Either because it has not yet tried, * or it did and it was successful * or it did, was not successful, but it should not retry */ - private final AtomicBoolean shouldTryToRead; + private static final AtomicBoolean shouldTryToRead = new AtomicBoolean(true); - /** - * Default constructor. - * - * @param context Application context - * @param referrerCallback Callback for referrer information - */ - public InstallReferrerMeta(final Context context, - final String fbAppId, - final InstallReferrerReadListener referrerCallback) - { - this.logger = AdjustFactory.getLogger(); - this.context = context; - this.fbAppId = fbAppId; - this.referrerCallback = referrerCallback; - this.shouldTryToRead = new AtomicBoolean(true); - } + public static MetaInstallReferrerResult getMetaInstallReferrer( + final Context context, final String fbAppId, final ILogger logger, final boolean shouldAvoidFrequentRead) { + String errorMessage = null; - public void readReferrer() { - if (!shouldTryToRead.get()) { - logger.debug("Should not retry to read Install referrer Meta"); - return; + if (shouldAvoidFrequentRead) { + if (!shouldTryToRead.get()) { + errorMessage = "Shouldn't try to read Meta Install referrer"; + logger.debug(errorMessage); + return new MetaInstallReferrerResult(errorMessage); + } } if (TextUtils.isEmpty(fbAppId)) { - logger.debug("Can't read Install referrer Meta with null or empty FB app ID"); - return; + errorMessage = "Can't read Meta Install referrer with null or empty FBAppId"; + logger.debug(errorMessage); + return new MetaInstallReferrerResult(errorMessage); } Cursor cursor = null; @@ -95,12 +74,16 @@ public void readReferrer() { try { Uri providerUri = null; - if (Util.resolveContentProvider(context, FACEBOOK_REFERRER_PROVIDER_AUTHORITY)) { + if (resolveContentProvider(context, FACEBOOK_REFERRER_PROVIDER_AUTHORITY)) { providerUri = Uri.parse("content://" + FACEBOOK_REFERRER_PROVIDER_AUTHORITY + "/" + fbAppId); - } else if (Util.resolveContentProvider(context, INSTAGRAM_REFERRER_PROVIDER_AUTHORITY)) { + } else if (resolveContentProvider(context, INSTAGRAM_REFERRER_PROVIDER_AUTHORITY)) { providerUri = Uri.parse("content://" + INSTAGRAM_REFERRER_PROVIDER_AUTHORITY + "/" + fbAppId); + } else if (resolveContentProvider(context, FBLITE_REFERRER_PROVIDER_AUTHORITY)) { + providerUri = Uri.parse("content://" + FBLITE_REFERRER_PROVIDER_AUTHORITY + "/" + fbAppId); } else { - return; + errorMessage = "Failed to find Meta Install Referrer content provider"; + logger.debug(errorMessage); + return new MetaInstallReferrerResult(errorMessage); } ContentResolver contentResolver = context.getContentResolver(); @@ -110,7 +93,9 @@ public void readReferrer() { cursor = contentResolver.query(providerUri, projection, null, null, null); if (cursor == null || !cursor.moveToFirst()) { - return; + errorMessage = Util.formatString("Fail to read Meta Install Referrer for FB AppId [%s]", fbAppId); + logger.debug(errorMessage); + return new MetaInstallReferrerResult(errorMessage); } int installReferrerIndex = cursor.getColumnIndex(COLUMN_INSTALL_REFERRER); @@ -123,41 +108,52 @@ public void readReferrer() { logger.debug("InstallReferrerMeta reads " + "installReferrer[%s] actualTimestampInSec[%d] isClick[%b]", - installReferrer, actualTimestampInSec, ctValue); + installReferrer, actualTimestampInSec, isClick); if (isValidReferrer(installReferrer)) { - ReferrerDetails referrerDetails = - new ReferrerDetails(installReferrer, - actualTimestampInSec, - isClick); + shouldTryToRead.set(false); - referrerCallback.onInstallReferrerRead(referrerDetails, - Constants.REFERRER_API_META); + MetaInstallReferrerDetails metaInstallReferrerDetails = + new MetaInstallReferrerDetails(installReferrer, actualTimestampInSec, isClick); + + return new MetaInstallReferrerResult(metaInstallReferrerDetails); } else { - logger.debug("InstallReferrerMeta invalid installReferrer"); + errorMessage = "Invalid Meta Install Referrer"; + logger.debug(errorMessage); } } catch (Exception e) { - logger.debug("InstallReferrerMeta error [%s]", e.getMessage()); + errorMessage = "Meta Install Referrer error " + e.getMessage(); + logger.debug(errorMessage); } finally { if (cursor != null) { cursor.close(); } } - shouldTryToRead.set(false); + return new MetaInstallReferrerResult(errorMessage); } - private boolean isValidReferrer(String installReferrer) { - if (installReferrer == null) { + private static boolean resolveContentProvider(final Context applicationContext, + final String authority) { + try { + return (applicationContext.getPackageManager() + .resolveContentProvider(authority, 0) != null); + + } catch (Exception e) { return false; } + } - if (installReferrer.isEmpty()) { + private static boolean isValidReferrer(String referrer) { + if (referrer == null) { + return false; + } + + if (referrer.isEmpty()) { return false; } return true; } - -} \ No newline at end of file +} diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/OnMetaInstallReferrerReadListener.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/OnMetaInstallReferrerReadListener.java new file mode 100644 index 000000000..67a211ea7 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/OnMetaInstallReferrerReadListener.java @@ -0,0 +1,6 @@ +package com.adjust.sdk.meta; + +public interface OnMetaInstallReferrerReadListener { + void onInstallReferrerDetailsRead(MetaInstallReferrerDetails referrerDetails); + void onFail(String message); +} diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/Util.java b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/Util.java new file mode 100644 index 000000000..527d61ff5 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/java/com/adjust/sdk/meta/Util.java @@ -0,0 +1,29 @@ +package com.adjust.sdk.meta; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; + +public class Util { + public synchronized static ReferrerDetails getMetaInstallReferrerDetails(Context context, String fbAppId, ILogger logger) { + if (!AdjustMetaReferrer.shouldReadMetaReferrer) { + return null; + } + + logger.info("getMetaInstallReferrerDetails invoked"); + + MetaInstallReferrerResult metaInstallReferrerResult = MetaReferrerClient.getMetaInstallReferrer(context, fbAppId, logger, true); + if (metaInstallReferrerResult == null) { + return null; + } + if (metaInstallReferrerResult.metaInstallReferrerDetails == null) { + return null; + } + MetaInstallReferrerDetails metaInstallReferrerDetails = metaInstallReferrerResult.metaInstallReferrerDetails; + return new ReferrerDetails( + metaInstallReferrerDetails.installReferrer, + metaInstallReferrerDetails.actualTimestampInSec, + metaInstallReferrerDetails.isClick); + } +} diff --git a/Adjust/plugins/sdk-plugin-meta-referrer/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/res/values/strings.xml new file mode 100644 index 000000000..d9171f865 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-meta-referrer/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + AdjustPluginMetaReferrer + diff --git a/Adjust/sdk-plugin-imei/.gitignore b/Adjust/plugins/sdk-plugin-oaid/.gitignore similarity index 100% rename from Adjust/sdk-plugin-imei/.gitignore rename to Adjust/plugins/sdk-plugin-oaid/.gitignore diff --git a/Adjust/plugins/sdk-plugin-oaid/LICENSE b/Adjust/plugins/sdk-plugin-oaid/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-oaid/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-oaid/build.gradle b/Adjust/plugins/sdk-plugin-oaid/build.gradle similarity index 91% rename from Adjust/sdk-plugin-oaid/build.gradle rename to Adjust/plugins/sdk-plugin-oaid/build.gradle index b24bc4e08..dbeb6e633 100644 --- a/Adjust/sdk-plugin-oaid/build.gradle +++ b/Adjust/plugins/sdk-plugin-oaid/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } maven { url "https://developer.huawei.com/repo/" @@ -24,6 +24,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.coreMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.oaid' } @@ -33,7 +36,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' implementation 'com.huawei.hms:ads-identifier:3.4.56.300' } @@ -110,7 +113,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/sdk-plugin-oaid/libs/oaid_sdk_2.0.0.aar b/Adjust/plugins/sdk-plugin-oaid/libs/oaid_sdk_2.0.0.aar similarity index 100% rename from Adjust/sdk-plugin-oaid/libs/oaid_sdk_2.0.0.aar rename to Adjust/plugins/sdk-plugin-oaid/libs/oaid_sdk_2.0.0.aar diff --git a/Adjust/sdk-plugin-oaid/proguard-rules.pro b/Adjust/plugins/sdk-plugin-oaid/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-oaid/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-oaid/proguard-rules.pro diff --git a/Adjust/sdk-plugin-oaid/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-oaid/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-oaid/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-oaid/src/main/AndroidManifest.xml diff --git a/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java new file mode 100644 index 000000000..c3611c4e1 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java @@ -0,0 +1,76 @@ +package com.adjust.sdk.oaid; + +import static com.adjust.sdk.oaid.Util.readCertFromAssetFile; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ILogger; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; +import com.bun.miitmdid.core.MdidSdkHelper; + +import java.util.Map; + +public class AdjustOaid { + static boolean isOaidToBeRead = false; + static boolean isMsaSdkAvailable = false; + + public static void readOaid() { + isOaidToBeRead = true; + } + + public static void readOaid(Context context) { + ILogger logger = AdjustFactory.getLogger(); + readOaid(); + + try { + System.loadLibrary("msaoaidsec"); + String certificate = readCertFromAssetFile(context, logger); + isMsaSdkAvailable = MdidSdkHelper.InitCert(context, certificate); + } catch (Throwable t) { + isMsaSdkAvailable = false; + logger.debug("Adjust", "Error during msa sdk initialization " + t.getMessage()); + } + } + + public static void getOaid(final Context context, final OnOaidReadListener listener) { + ILogger logger = AdjustFactory.getLogger(); + if (listener == null) { + logger.error("onOaidReadListener cannot be null"); + return; + } + if (context == null) { + logger.error("context cannot be null"); + return; + } + + new AsyncTaskExecutor(){ + @Override + protected OaidResult doInBackground(Context[] contexts) { + readOaid(context); + OaidResult oaidResult = new OaidResult(); + Map oaidParameters = Util.getOaidParameters(context, logger); + if (oaidParameters != null && oaidParameters.get("oaid") != null) { + oaidResult.oaid = oaidParameters.get("oaid"); + } else { + oaidResult.error = "Failed to read OAID"; + } + return oaidResult; + } + + @Override + protected void onPostExecute(OaidResult oaidResult) { + if (oaidResult.oaid != null) { + listener.onOaidRead(oaidResult.oaid); + } else { + listener.onFail(oaidResult.error); + } + } + }.execute(context); + } + + + public static void doNotReadOaid() { + isOaidToBeRead = false; + } +} diff --git a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/HmsSdkClient.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/HmsSdkClient.java similarity index 100% rename from Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/HmsSdkClient.java rename to Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/HmsSdkClient.java diff --git a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/MsaSdkClient.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/MsaSdkClient.java similarity index 100% rename from Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/MsaSdkClient.java rename to Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/MsaSdkClient.java diff --git a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidInfo.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidInfo.java similarity index 100% rename from Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidInfo.java rename to Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidInfo.java diff --git a/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidResult.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidResult.java new file mode 100644 index 000000000..ea58d71bb --- /dev/null +++ b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OaidResult.java @@ -0,0 +1,9 @@ +package com.adjust.sdk.oaid; + +import java.util.Map; + +public class OaidResult { + + public String error; + public String oaid; +} diff --git a/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OnOaidReadListener.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OnOaidReadListener.java new file mode 100644 index 000000000..feea481ef --- /dev/null +++ b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/OnOaidReadListener.java @@ -0,0 +1,8 @@ +package com.adjust.sdk.oaid; + +import java.util.Map; + +public interface OnOaidReadListener { + void onOaidRead(String oaid); + void onFail(String message); +} diff --git a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java similarity index 95% rename from Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java rename to Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java index 695669866..692a1db69 100644 --- a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java +++ b/Adjust/plugins/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/Util.java @@ -91,7 +91,7 @@ private static Map getOaidParametersUsingMsa(Context context, IL return null; } - public static String readCertFromAssetFile(Context context) { + public static String readCertFromAssetFile(Context context, ILogger logger) { try { String assetFileName = context.getPackageName() + ".cert.pem"; InputStream is = context.getAssets().open(assetFileName); @@ -104,7 +104,7 @@ public static String readCertFromAssetFile(Context context) { } return builder.toString(); } catch (Exception e) { - Log.e("Adjust", "readCertFromAssetFile failed"); + logger.error("readCertFromAssetFile Error reading asset file: " + e.getMessage()); return ""; } } diff --git a/Adjust/sdk-plugin-oaid/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-oaid/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-oaid/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-oaid/src/main/res/values/strings.xml diff --git a/Adjust/sdk-plugin-vivo-referrer/.gitignore b/Adjust/plugins/sdk-plugin-samsung-clouddev/.gitignore similarity index 100% rename from Adjust/sdk-plugin-vivo-referrer/.gitignore rename to Adjust/plugins/sdk-plugin-samsung-clouddev/.gitignore diff --git a/Adjust/plugins/sdk-plugin-samsung-clouddev/LICENSE b/Adjust/plugins/sdk-plugin-samsung-clouddev/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-clouddev/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-samsung-clouddev/build.gradle b/Adjust/plugins/sdk-plugin-samsung-clouddev/build.gradle similarity index 91% rename from Adjust/sdk-plugin-samsung-clouddev/build.gradle rename to Adjust/plugins/sdk-plugin-samsung-clouddev/build.gradle index addc30e9a..7931b0e04 100644 --- a/Adjust/sdk-plugin-samsung-clouddev/build.gradle +++ b/Adjust/plugins/sdk-plugin-samsung-clouddev/build.gradle @@ -4,12 +4,12 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } android { - compileSdkVersion rootProject.ext.coreCompileSdkVersion + compileSdk rootProject.ext.coreCompileSdkVersion publishing { multipleVariants { allVariants() @@ -19,6 +19,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.samsungCloudDevMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.samsung.clouddev' } @@ -27,7 +30,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' // Add Samsung clouddev lib. compileOnly fileTree(include: ['*.aar'], dir: 'libs') @@ -107,7 +110,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/sdk-plugin-samsung-clouddev/proguard-rules.pro b/Adjust/plugins/sdk-plugin-samsung-clouddev/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-samsung-clouddev/proguard-rules.pro diff --git a/Adjust/sdk-plugin-samsung-clouddev/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/AndroidManifest.xml diff --git a/Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/AdjustSamsungCloudDev.java b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/AdjustSamsungCloudDev.java similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/AdjustSamsungCloudDev.java rename to Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/AdjustSamsungCloudDev.java diff --git a/Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/SamsungCloudDevClient.java b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/SamsungCloudDevClient.java similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/SamsungCloudDevClient.java rename to Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/SamsungCloudDevClient.java diff --git a/Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java similarity index 72% rename from Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java rename to Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java index 44ea46614..e55148b5b 100644 --- a/Adjust/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java +++ b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/java/com/adjust/sdk/samsung/clouddev/Util.java @@ -5,11 +5,13 @@ import com.adjust.sdk.ILogger; public class Util { - public synchronized static String getGoogleAdId(Context context, ILogger logger) { + public synchronized static String getGoogleAdIdInCloudEnvironment(Context context, ILogger logger) { if (!AdjustSamsungCloudDev.shouldUseSamsungCloudDevSdk) { return null; } + logger.info("getGoogleAdIdInCloudEnvironment invoked"); + return SamsungCloudDevClient.getGoogleAdId(context, logger, 4000); } @@ -18,6 +20,8 @@ public synchronized static boolean isAppRunningInCloudEnvironment(Context contex return false; } + logger.info("isAppRunningInCloudEnvironment invoked"); + return SamsungCloudDevClient.isAppRunningInCloudEnvironment(context, logger); } } diff --git a/Adjust/sdk-plugin-samsung-clouddev/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-samsung-clouddev/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-samsung-clouddev/src/main/res/values/strings.xml diff --git a/Adjust/test-app-core/.gitignore b/Adjust/plugins/sdk-plugin-samsung-referrer/.gitignore similarity index 53% rename from Adjust/test-app-core/.gitignore rename to Adjust/plugins/sdk-plugin-samsung-referrer/.gitignore index 796b96d1c..97873191d 100644 --- a/Adjust/test-app-core/.gitignore +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/.gitignore @@ -1 +1,2 @@ /build +/libs diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/LICENSE b/Adjust/plugins/sdk-plugin-samsung-referrer/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-samsung-referrer/build.gradle b/Adjust/plugins/sdk-plugin-samsung-referrer/build.gradle similarity index 91% rename from Adjust/sdk-plugin-samsung-referrer/build.gradle rename to Adjust/plugins/sdk-plugin-samsung-referrer/build.gradle index 952dc66b2..21b995dd9 100644 --- a/Adjust/sdk-plugin-samsung-referrer/build.gradle +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/build.gradle @@ -4,12 +4,12 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } android { - compileSdkVersion rootProject.ext.coreCompileSdkVersion + compileSdk rootProject.ext.coreCompileSdkVersion publishing { multipleVariants { allVariants() @@ -19,6 +19,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.samsungReferrerMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.samsung' } @@ -27,7 +30,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' // Add Samsung referrer lib via Maven. implementation 'store.galaxy.samsung.installreferrer:samsung_galaxystore_install_referrer:3.0.1' @@ -107,7 +110,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/sdk-plugin-webbridge/proguard-rules.pro b/Adjust/plugins/sdk-plugin-samsung-referrer/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-webbridge/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-samsung-referrer/proguard-rules.pro diff --git a/Adjust/sdk-plugin-samsung-referrer/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-samsung-referrer/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-samsung-referrer/src/main/AndroidManifest.xml diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java new file mode 100644 index 000000000..fbe9ded1a --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java @@ -0,0 +1,61 @@ +package com.adjust.sdk.samsung; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; + + +public class AdjustSamsungReferrer { + + static boolean shouldReadSamsungReferrer = true; + + /** + * Called to get Samsung Install Referrer. + * + * @param context Application context + * @param onSamsungInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getSamsungInstallReferrer(final Context context, final OnSamsungInstallReferrerReadListener onSamsungInstallReferrerReadListener) { + + if (onSamsungInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onSamsungInstallReferrerReadListener can not be null"); + return; + } + + new AsyncTaskExecutor() { + @Override + protected SamsungInstallReferrerResult doInBackground(Context[] contexts) { + try { + return SamsungReferrerClient.getReferrer(context, AdjustFactory.getLogger(),2000); + } catch (Exception exception) { + return new SamsungInstallReferrerResult(exception.getMessage()); + } + } + + @Override + protected void onPostExecute(SamsungInstallReferrerResult samsungInstallReferrerResult) { + if (samsungInstallReferrerResult != null) { + if (samsungInstallReferrerResult.samsungInstallReferrerDetails != null) { + onSamsungInstallReferrerReadListener.onSamsungInstallReferrerRead(samsungInstallReferrerResult.samsungInstallReferrerDetails); + } else if (samsungInstallReferrerResult.error != null) { + onSamsungInstallReferrerReadListener.onFail(samsungInstallReferrerResult.error); + }else { + onSamsungInstallReferrerReadListener.onFail("SamsungReferrer getInstallReferrer: samsungInstallReferrerDetails is null"); + } + }else { + onSamsungInstallReferrerReadListener.onFail("SamsungReferrer getInstallReferrer: samsungInstallReferrerResult is null"); + } + } + }.execute(context); + } + + public static void readSamsungReferrer(Context context) { + shouldReadSamsungReferrer = true; + } + + public static void doNotReadSamsungReferrer() { + shouldReadSamsungReferrer = false; + } +} diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/OnSamsungInstallReferrerReadListener.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/OnSamsungInstallReferrerReadListener.java new file mode 100644 index 000000000..269ea5678 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/OnSamsungInstallReferrerReadListener.java @@ -0,0 +1,6 @@ +package com.adjust.sdk.samsung; + +public interface OnSamsungInstallReferrerReadListener { + void onSamsungInstallReferrerRead(SamsungInstallReferrerDetails referrerDetails); + void onFail(String message); +} diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerDetails.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerDetails.java new file mode 100644 index 000000000..3a02bb7c8 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerDetails.java @@ -0,0 +1,26 @@ +package com.adjust.sdk.samsung; + +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.Util; + +public class SamsungInstallReferrerDetails { + public String installReferrer; // The referrer URL of the installed package. + public long referrerClickTimestampSeconds; // The client-side timestamp, when the referrer click happened. + public long installBeginTimestampSeconds; // The client-side timestamp, when app installation began. + + SamsungInstallReferrerDetails(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds){ + this.installReferrer = installReferrer; + this.referrerClickTimestampSeconds = referrerClickTimestampSeconds; + this.installBeginTimestampSeconds = installBeginTimestampSeconds; + } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " referrerClickTimestampSeconds : %d" + + " installBeginTimestampSeconds : %d", + installReferrer, + referrerClickTimestampSeconds, + installBeginTimestampSeconds); + } +} diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerResult.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerResult.java new file mode 100644 index 000000000..91436d613 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungInstallReferrerResult.java @@ -0,0 +1,14 @@ +package com.adjust.sdk.samsung; + +public class SamsungInstallReferrerResult { + public String error; + public SamsungInstallReferrerDetails samsungInstallReferrerDetails; + + SamsungInstallReferrerResult(SamsungInstallReferrerDetails samsungInstallReferrerDetails) { + this.samsungInstallReferrerDetails = samsungInstallReferrerDetails; + } + + public SamsungInstallReferrerResult(String error) { + this.error = error; + } +} diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java new file mode 100644 index 000000000..b3aa8d332 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java @@ -0,0 +1,79 @@ +package com.adjust.sdk.samsung; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.samsung.android.sdk.sinstallreferrer.api.InstallReferrerClient; +import com.samsung.android.sdk.sinstallreferrer.api.InstallReferrerStateListener; +import com.samsung.android.sdk.sinstallreferrer.api.ReferrerDetails; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class SamsungReferrerClient { + + public static SamsungInstallReferrerResult getReferrer(Context context, final ILogger logger, long maxWaitTimeInMilli) { + try { + final InstallReferrerClient referrerClient = InstallReferrerClient.newBuilder(context).build(); + final BlockingQueue referrerDetailsHolder = new LinkedBlockingQueue(1); + referrerClient.startConnection(new InstallReferrerStateListener() { + @Override + public void onInstallReferrerSetupFinished(int responseCode) { + String error; + try { + switch (responseCode) { + case InstallReferrerClient.InstallReferrerResponse.OK: + try { + SamsungInstallReferrerDetails samsungInstallReferrerDetails = getSamsungInstallReferrerDetails(referrerClient); + referrerDetailsHolder.offer(new SamsungInstallReferrerResult(samsungInstallReferrerDetails)); + } catch (Exception e) { + error = "SamsungReferrer getInstallReferrer: " + e.getMessage(); + referrerDetailsHolder.offer(new SamsungInstallReferrerResult(error)); + logger.error(error); + + } finally { + referrerClient.endConnection(); + } + break; + case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED: + error = "SamsungReferrer onInstallReferrerSetupFinished: FEATURE_NOT_SUPPORTED"; + referrerDetailsHolder.offer(new SamsungInstallReferrerResult(error)); + logger.info(error); + break; + case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE: + error = "SamsungReferrer onInstallReferrerSetupFinished: SERVICE_UNAVAILABLE"; + referrerDetailsHolder.offer(new SamsungInstallReferrerResult(error)); + logger.info(error); + break; + } + } catch (Exception e) { + error = "SamsungReferrer onInstallReferrerSetupFinished: " + e.getMessage(); + referrerDetailsHolder.offer(new SamsungInstallReferrerResult(error)); + logger.error(error); + } + } + + @Override + public void onInstallReferrerServiceDisconnected() { + referrerClient.endConnection(); + } + }); + + return referrerDetailsHolder.poll(maxWaitTimeInMilli, TimeUnit.MILLISECONDS); + + } catch (Exception e) { + String error = "SamsungReferrer read error: " + e.getMessage(); + logger.info(error); + return new SamsungInstallReferrerResult(error); + } + } + + private static SamsungInstallReferrerDetails getSamsungInstallReferrerDetails(InstallReferrerClient referrerClient) { + ReferrerDetails details = referrerClient.getInstallReferrer(); + return new SamsungInstallReferrerDetails( + details.getInstallReferrer(), + details.getReferrerClickTimestampSeconds(), + details.getInstallBeginTimestampSeconds()); + } +} diff --git a/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java new file mode 100644 index 000000000..62ec76819 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java @@ -0,0 +1,35 @@ +package com.adjust.sdk.samsung; + +import android.content.Context; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; + +public class Util { + public synchronized static ReferrerDetails getSamsungInstallReferrerDetails(Context context, ILogger logger) { + if (!AdjustSamsungReferrer.shouldReadSamsungReferrer) { + return null; + } + + logger.info("getSamsungInstallReferrerDetails invoked"); + + SamsungInstallReferrerResult referrerResult = + SamsungReferrerClient.getReferrer(context, logger, 2000); + if (referrerResult == null) { + return null; + } + SamsungInstallReferrerDetails samsungInstallReferrerDetails = referrerResult.samsungInstallReferrerDetails; + if (samsungInstallReferrerDetails == null) { + return null; + } + return new ReferrerDetails(samsungInstallReferrerDetails.installReferrer, + samsungInstallReferrerDetails.referrerClickTimestampSeconds, + samsungInstallReferrerDetails.installBeginTimestampSeconds, + -1, + -1, + null, + null, + null); + } +} diff --git a/Adjust/sdk-plugin-samsung-referrer/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-samsung-referrer/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-samsung-referrer/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-samsung-referrer/src/main/res/values/strings.xml diff --git a/Adjust/test-app-webbridge/.gitignore b/Adjust/plugins/sdk-plugin-vivo-referrer/.gitignore similarity index 53% rename from Adjust/test-app-webbridge/.gitignore rename to Adjust/plugins/sdk-plugin-vivo-referrer/.gitignore index 796b96d1c..97873191d 100644 --- a/Adjust/test-app-webbridge/.gitignore +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/.gitignore @@ -1 +1,2 @@ /build +/libs diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/LICENSE b/Adjust/plugins/sdk-plugin-vivo-referrer/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-vivo-referrer/build.gradle b/Adjust/plugins/sdk-plugin-vivo-referrer/build.gradle similarity index 91% rename from Adjust/sdk-plugin-vivo-referrer/build.gradle rename to Adjust/plugins/sdk-plugin-vivo-referrer/build.gradle index ce1de2e67..2dfeea5d2 100644 --- a/Adjust/sdk-plugin-vivo-referrer/build.gradle +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } @@ -20,6 +20,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.vivoReferrerMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.vivo' } @@ -30,7 +33,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' } // read local properties @@ -107,7 +110,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/sdk-plugin-xiaomi-referrer/proguard-rules.pro b/Adjust/plugins/sdk-plugin-vivo-referrer/proguard-rules.pro similarity index 100% rename from Adjust/sdk-plugin-xiaomi-referrer/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-vivo-referrer/proguard-rules.pro diff --git a/Adjust/sdk-plugin-vivo-referrer/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-vivo-referrer/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-vivo-referrer/src/main/AndroidManifest.xml diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java new file mode 100644 index 000000000..e76c2933c --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java @@ -0,0 +1,60 @@ +package com.adjust.sdk.vivo; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; + +public class AdjustVivoReferrer { + + static boolean shouldReadVivoReferrer = true; + + /** + * Called to get Vivo Install Referrer. + * + * @param context Application context + * @param onVivoInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getVivoInstallReferrer(final Context context, final OnVivoInstallReferrerReadListener onVivoInstallReferrerReadListener) { + if (onVivoInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onVivoInstallReferrerReadListener can not be null"); + return; + } + + new AsyncTaskExecutor() { + @Override + protected VivoInstallReferrerResult doInBackground(Context[] contexts) { + try { + return VivoReferrerClient.getReferrer(context, AdjustFactory.getLogger()); + } catch (Exception exception) { + return new VivoInstallReferrerResult(exception.getMessage()); + } + } + + @Override + protected void onPostExecute(VivoInstallReferrerResult vivoInstallReferrerResult) { + if (vivoInstallReferrerResult != null) { + if (vivoInstallReferrerResult.vivoInstallReferrerDetails != null) { + onVivoInstallReferrerReadListener.onVivoInstallReferrerRead(vivoInstallReferrerResult.vivoInstallReferrerDetails); + } else if (vivoInstallReferrerResult.error != null) { + onVivoInstallReferrerReadListener.onFail(vivoInstallReferrerResult.error); + } else { + onVivoInstallReferrerReadListener.onFail("VivoReferrer getInstallReferrer: xiaomiInstallReferrerDetails is null"); + } + } else { + onVivoInstallReferrerReadListener.onFail("VivoReferrer getInstallReferrer: vivoInstallReferrerResult is null"); + } + } + }.execute(context); + } + + + public static void readVivoReferrer(Context context) { + shouldReadVivoReferrer = true; + } + + public static void doNotReadVivoReferrer() { + shouldReadVivoReferrer = false; + } +} diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/OnVivoInstallReferrerReadListener.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/OnVivoInstallReferrerReadListener.java new file mode 100644 index 000000000..9d2707972 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/OnVivoInstallReferrerReadListener.java @@ -0,0 +1,8 @@ +package com.adjust.sdk.vivo; + +import com.adjust.sdk.ReferrerDetails; + +public interface OnVivoInstallReferrerReadListener { + void onVivoInstallReferrerRead(VivoInstallReferrerDetails referrerDetails); + void onFail(String message); +} diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java new file mode 100644 index 000000000..2e186b021 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java @@ -0,0 +1,32 @@ +package com.adjust.sdk.vivo; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; + +public class Util { + public synchronized static ReferrerDetails getVivoInstallReferrerDetails(Context context, ILogger logger) { + if (!AdjustVivoReferrer.shouldReadVivoReferrer) { + return null; + } + + logger.info("getVivoInstallReferrerDetails invoked"); + + VivoInstallReferrerResult vivoInstallReferrerResult = VivoReferrerClient.getReferrer(context, logger); + if (vivoInstallReferrerResult.vivoInstallReferrerDetails == null) { + return null; + } + + VivoInstallReferrerDetails vivoInstallReferrerDetails = vivoInstallReferrerResult.vivoInstallReferrerDetails; + + return new ReferrerDetails(vivoInstallReferrerDetails.installReferrer, + vivoInstallReferrerDetails.referrerClickTimestampSeconds, + vivoInstallReferrerDetails.installBeginTimestampSeconds, + -1, + -1, + vivoInstallReferrerDetails.installVersion, + null, + null); + } +} diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerDetails.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerDetails.java new file mode 100644 index 000000000..7b4c6dbd8 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerDetails.java @@ -0,0 +1,41 @@ +package com.adjust.sdk.vivo; + +import com.adjust.sdk.ReferrerDetails; +import com.adjust.sdk.Util; + +public class VivoInstallReferrerDetails { + + public String installReferrer; // The referrer URL of the installed package. + public long referrerClickTimestampSeconds; // The client-side timestamp, when the referrer click happened. + public long installBeginTimestampSeconds; // The client-side timestamp, when app installation began. + public String installVersion; // The app's version at the time when the app was first installed. + + public VivoInstallReferrerDetails(String installReferrer, long referrerClickTimestampSeconds, long installBeginTimestampSeconds, String installVersion) { + this.installReferrer = installReferrer; + this.referrerClickTimestampSeconds = referrerClickTimestampSeconds; + this.installBeginTimestampSeconds = installBeginTimestampSeconds; + this.installVersion = installVersion; + } + + VivoInstallReferrerDetails(ReferrerDetails referrerDetails){ + if (referrerDetails == null){ + return; + } + this.installReferrer = referrerDetails.installReferrer; + this.referrerClickTimestampSeconds = referrerDetails.referrerClickTimestampSeconds; + this.installBeginTimestampSeconds = referrerDetails.installBeginTimestampSeconds; + this.installVersion = referrerDetails.installVersion; + } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " referrerClickTimestampSeconds : %d" + + " installBeginTimestampSeconds : %d" + + " installVersion : %s", + installReferrer, + referrerClickTimestampSeconds, + installBeginTimestampSeconds, + installVersion); + } +} diff --git a/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerResult.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerResult.java new file mode 100644 index 000000000..f3e2046f2 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoInstallReferrerResult.java @@ -0,0 +1,14 @@ +package com.adjust.sdk.vivo; + +public class VivoInstallReferrerResult { + public String error; + public VivoInstallReferrerDetails vivoInstallReferrerDetails; + + public VivoInstallReferrerResult(VivoInstallReferrerDetails vivoInstallReferrerDetails) { + this.vivoInstallReferrerDetails = vivoInstallReferrerDetails; + } + + public VivoInstallReferrerResult(String error) { + this.error = error; + } +} diff --git a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java similarity index 57% rename from Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java rename to Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java index ecffbbe4c..ed444b279 100644 --- a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java +++ b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/VivoReferrerClient.java @@ -9,27 +9,32 @@ import com.adjust.sdk.ReferrerDetails; public class VivoReferrerClient { - public static ReferrerDetails getReferrer(Context context, final ILogger logger) { + public static VivoInstallReferrerResult getReferrer(Context context, final ILogger logger) { + try { Uri url = Uri.parse("content://com.vivo.appstore.provider.referrer"); Bundle resultBundle = context.getContentResolver().call(url, "read_referrer", null, null); if (resultBundle == null) { - return null; + return new VivoInstallReferrerResult("VivoReferrer read error: resultBundle null"); } String installReferrer = resultBundle.getString("install_referrer"); if (TextUtils.isEmpty(installReferrer)) { - return null; + return new VivoInstallReferrerResult("VivoReferrer read error: referrer string null"); } long clickTime = resultBundle.getLong("referrer_click_timestamp_seconds"); long installBeginTime = resultBundle.getLong("download_begin_timestamp_seconds"); String installVersion = resultBundle.getString("install_version"); - return new ReferrerDetails(installReferrer, clickTime, installBeginTime, -1, -1, installVersion, null, null); + VivoInstallReferrerDetails vivoInstallReferrerDetails = new VivoInstallReferrerDetails( + installReferrer, clickTime, installBeginTime, installVersion); + return new VivoInstallReferrerResult(vivoInstallReferrerDetails); + } catch (Exception e) { - logger.info("VivoReferrer read error" + e.getMessage()); + String error = "VivoReferrer read error: " + e.getMessage(); + logger.info(error); + return new VivoInstallReferrerResult(error); } - return null; } } diff --git a/Adjust/sdk-plugin-vivo-referrer/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-vivo-referrer/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-vivo-referrer/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-vivo-referrer/src/main/res/values/strings.xml diff --git a/Adjust/sdk-plugin-oaid/.gitignore b/Adjust/plugins/sdk-plugin-webbridge/.gitignore similarity index 100% rename from Adjust/sdk-plugin-oaid/.gitignore rename to Adjust/plugins/sdk-plugin-webbridge/.gitignore diff --git a/Adjust/plugins/sdk-plugin-webbridge/LICENSE b/Adjust/plugins/sdk-plugin-webbridge/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-webbridge/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-webbridge/build.gradle b/Adjust/plugins/sdk-plugin-webbridge/build.gradle similarity index 94% rename from Adjust/sdk-plugin-webbridge/build.gradle rename to Adjust/plugins/sdk-plugin-webbridge/build.gradle index 7724169e5..e9798dd59 100644 --- a/Adjust/sdk-plugin-webbridge/build.gradle +++ b/Adjust/plugins/sdk-plugin-webbridge/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } @@ -21,6 +21,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.webbridgeMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.webbridge' } @@ -30,7 +33,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' } // read local properties @@ -108,9 +111,9 @@ afterEvaluate { maven { if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { println "Using Maven SNAPSHOT repository for publishing" - url "https://oss.sonatype.org/content/repositories/snapshots/" + url "https://central.sonatype.com/repository/maven-snapshots/" } else { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" } if (project.hasProperty("sonatypeUsername")) { credentials { diff --git a/Adjust/test-app-core/proguard-rules.pro b/Adjust/plugins/sdk-plugin-webbridge/proguard-rules.pro similarity index 100% rename from Adjust/test-app-core/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-webbridge/proguard-rules.pro diff --git a/Adjust/sdk-plugin-criteo/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-webbridge/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-criteo/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-webbridge/src/main/AndroidManifest.xml diff --git a/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust.js b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust.js new file mode 100644 index 000000000..85d7fea73 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust.js @@ -0,0 +1,387 @@ +// generate random callback ID with prefix (similar to iOS implementation) +window.randomCallbackIdWithPrefix = function(prefix) { + const randomString = (Math.random() + 1).toString(36).substring(7); + return prefix + "_" + randomString; +}; + +var Adjust = { + // map to store callbacks by their unique callback ID + _callbackMap: {}, + _namedCallbackMap: {}, + _bridgeToken: null, + _bridgeTokenRequested: false, + _pendingBridgeCalls: [], + + _handleGetterCallback: function(callback, callbackId) { + this._callbackMap[callbackId] = callback; + }, + + _registerNamedCallback: function(callbackName, callback) { + if (!callbackName || typeof callback !== 'function') { + return; + } + this._namedCallbackMap[callbackName] = callback; + }, + + _registerConfigCallbacks: function(adjustConfig) { + if (!adjustConfig) { + return; + } + + var registerIfPresent = function(callbackName, callbackFn) { + if (!callbackName) { + return; + } + if (typeof callbackFn === 'function') { + Adjust._registerNamedCallback(callbackName, callbackFn); + return; + } + var resolved = Adjust._resolveCallbackByPath(callbackName); + if (typeof resolved === 'function') { + Adjust._registerNamedCallback(callbackName, resolved); + } + }; + + registerIfPresent(adjustConfig.attributionCallbackName, adjustConfig.attributionCallbackFunction); + registerIfPresent(adjustConfig.thirdPartySharingSettingsChangedCallbackName, adjustConfig.thirdPartySharingSettingsChangedCallbackFunction); + registerIfPresent(adjustConfig.eventSuccessCallbackName, adjustConfig.eventSuccessCallbackFunction); + registerIfPresent(adjustConfig.eventFailureCallbackName, adjustConfig.eventFailureCallbackFunction); + registerIfPresent(adjustConfig.sessionSuccessCallbackName, adjustConfig.sessionSuccessCallbackFunction); + registerIfPresent(adjustConfig.sessionFailureCallbackName, adjustConfig.sessionFailureCallbackFunction); + registerIfPresent(adjustConfig.deferredDeeplinkCallbackName, adjustConfig.deferredDeeplinkCallbackFunction); + registerIfPresent(adjustConfig.remoteTriggerCallbackName, adjustConfig.remoteTriggerCallbackFunction); + + var registerInternal = function(callbackName, callbackFn) { + if (!callbackName || typeof callbackFn !== 'function') { + return; + } + if (Adjust._namedCallbackMap[callbackName]) { + return; + } + Adjust._registerNamedCallback(callbackName, callbackFn.bind(adjustConfig)); + }; + + registerInternal(adjustConfig.attributionCallbackName, adjustConfig.adjust_attributionCallback); + registerInternal(adjustConfig.thirdPartySharingSettingsChangedCallbackName, adjustConfig.adjust_thirdPartySharingSettingsChangedCallback); + registerInternal(adjustConfig.eventSuccessCallbackName, adjustConfig.adjust_eventSuccessCallback); + registerInternal(adjustConfig.eventFailureCallbackName, adjustConfig.adjust_eventFailureCallback); + registerInternal(adjustConfig.sessionSuccessCallbackName, adjustConfig.adjust_sessionSuccessCallback); + registerInternal(adjustConfig.sessionFailureCallbackName, adjustConfig.adjust_sessionFailureCallback); + registerInternal(adjustConfig.deferredDeeplinkCallbackName, adjustConfig.adjust_deferredDeeplinkCallback); + registerInternal(adjustConfig.remoteTriggerCallbackName, adjustConfig.adjust_remoteTriggerCallback); + }, + + _resolveCallbackByPath: function(path) { + if (!path || typeof path !== 'string') { + return null; + } + if (path.indexOf('(') !== -1 || path.indexOf(')') !== -1) { + return null; + } + var parts = path.split('.'); + var context = window; + for (var i = 0; i < parts.length; i++) { + if (!context) { + return null; + } + context = context[parts[i]]; + } + return context; + }, + + _invokeCallback: function(callbackName, callback, value) { + if (callbackName && callbackName.indexOf("adjust_getAttribution") !== -1) { + if (typeof value === 'string') { + callback(JSON.parse(value)); + } else { + callback(value); + } + return; + } + callback(value); + }, + + _nativeCallback: function(callbackName, value) { + if (!callbackName) { + return; + } + var getterCallback = this._callbackMap[callbackName]; + if (getterCallback) { + this._invokeCallback(callbackName, getterCallback, value); + delete this._callbackMap[callbackName]; + return; + } + + var namedCallback = this._namedCallbackMap[callbackName]; + if (namedCallback) { + this._invokeCallback(callbackName, namedCallback, value); + } + }, + + _setBridgeToken: function(token) { + this._bridgeToken = token; + this._bridgeTokenRequested = false; + if (!this._pendingBridgeCalls.length) { + return; + } + var pending = this._pendingBridgeCalls; + this._pendingBridgeCalls = []; + for (var i = 0; i < pending.length; i++) { + var entry = pending[i]; + this._callBridge(entry.method, entry.args); + } + }, + + _callBridge: function(method, args) { + if (!AdjustBridge) { + return undefined; + } + if (window.top !== window.self) { + return undefined; + } + var callArgs = args ? args.slice() : []; + if (!this._bridgeToken) { + if (!this._bridgeTokenRequested && typeof AdjustBridge.requestBridgeToken === 'function') { + this._bridgeTokenRequested = true; + AdjustBridge.requestBridgeToken(); + } + this._pendingBridgeCalls.push({ method: method, args: callArgs }); + return undefined; + } + callArgs.push(this._bridgeToken); + return AdjustBridge[method].apply(AdjustBridge, callArgs); + }, + + initSdk: function (adjustConfig) { + if (adjustConfig && !adjustConfig.getSdkPrefix()) { + adjustConfig.setSdkPrefix(this.getSdkPrefix()); + } + this.adjustConfig = adjustConfig; + this._registerConfigCallbacks(adjustConfig); + this._callBridge('initSdk', [JSON.stringify(adjustConfig)]); + }, + + getConfig: function () { + return this.adjustConfig; + }, + + trackEvent: function (adjustEvent) { + this._callBridge('trackEvent', [JSON.stringify(adjustEvent)]); + }, + + onResume: function () { + this._callBridge('onResume'); + }, + + onPause: function () { + this._callBridge('onPause'); + }, + + enable: function () { + this._callBridge('enable'); + }, + + disable: function () { + this._callBridge('disable'); + }, + + isEnabled: function (callback) { + if (!AdjustBridge) { + return undefined; + } + // supports legacy return with callback + if (arguments.length === 1) { + // generate unique callback ID + const callbackId = window.randomCallbackIdWithPrefix("adjust_isEnabled"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('isEnabled', [callbackId]); + } else { + return AdjustBridge.isEnabled(); + } + }, + + setReferrer: function (referrer) { + this._callBridge('setReferrer', [referrer]); + }, + + switchToOfflineMode: function() { + this._callBridge('switchToOfflineMode'); + }, + + switchBackToOnlineMode: function() { + this._callBridge('switchBackToOnlineMode'); + }, + + addGlobalCallbackParameter: function(key, value) { + if (AdjustBridge) { + if (typeof key !== 'string' || typeof value !== 'string') { + console.log('[Adjust]: Passed key or value is not of string type'); + return; + } + this._callBridge('addGlobalCallbackParameter', [key, value]); + } + }, + + addGlobalPartnerParameter: function(key, value) { + if (AdjustBridge) { + if (typeof key !== 'string' || typeof value !== 'string') { + console.log('[Adjust]: Passed key or value is not of string type'); + return; + } + this._callBridge('addGlobalPartnerParameter', [key, value]); + } + }, + + removeGlobalCallbackParameter: function(key) { + if (AdjustBridge) { + if (typeof key !== 'string') { + console.log('[Adjust]: Passed key is not of string type'); + return; + } + this._callBridge('removeGlobalCallbackParameter', [key]); + } + }, + + removeGlobalPartnerParameter: function(key) { + if (AdjustBridge) { + if (typeof key !== 'string') { + console.log('[Adjust]: Passed key is not of string type'); + return; + } + this._callBridge('removeGlobalPartnerParameter', [key]); + } + }, + + removeGlobalCallbackParameters: function() { + this._callBridge('removeGlobalCallbackParameters'); + }, + + removeGlobalPartnerParameters: function() { + this._callBridge('removeGlobalPartnerParameters'); + }, + + gdprForgetMe: function() { + this._callBridge('gdprForgetMe'); + }, + + trackThirdPartySharing: function(adjustThirdPartySharing) { + this._callBridge('trackThirdPartySharing', [JSON.stringify(adjustThirdPartySharing)]); + }, + + trackMeasurementConsent: function(consentMeasurement) { + this._callBridge('trackMeasurementConsent', [consentMeasurement]); + }, + + endFirstSessionDelay: function() { + this._callBridge('endFirstSessionDelay'); + }, + + enableCoppaComplianceInDelay: function() { + this._callBridge('enableCoppaComplianceInDelay'); + }, + + disableCoppaComplianceInDelay: function() { + this._callBridge('disableCoppaComplianceInDelay'); + }, + + enablePlayStoreKidsComplianceInDelay: function() { + this._callBridge('enablePlayStoreKidsComplianceInDelay'); + }, + + disablePlayStoreKidsComplianceInDelay: function() { + this._callBridge('disablePlayStoreKidsComplianceInDelay'); + }, + + setExternalDeviceIdInDelay: function(externalDeviceId) { + this._callBridge('setExternalDeviceIdInDelay', [externalDeviceId]); + }, + + getGoogleAdId: function (callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getGoogleAdId"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getGoogleAdId', [callbackId]); + } + }, + + getAdid: function (callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getAdid"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getAdid', [callbackId]); + } + }, + + getAdidWithTimeout: function (timeoutInMilliSec, callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getAdidWithTimeout"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getAdidWithTimeout', [timeoutInMilliSec, callbackId]); + } + }, + + getAmazonAdId: function (callbackSuccess, callbackFail) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getAmazonAdId"); + this._handleGetterCallback(callbackSuccess, callbackId); + // note: Java side only supports success callback, callbackFail is ignored + this._callBridge('getAmazonAdId', [callbackId]); + } + }, + + getAttribution: function (callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getAttribution"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getAttribution', [callbackId]); + } + }, + + getAttributionWithTimeout: function (timeoutInMilliSec, callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getAttributionWithTimeout"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getAttributionWithTimeout', [timeoutInMilliSec, callbackId]); + } + }, + + getThirdPartySharingSettingsWithTimeout: function (timeoutInMilliSec, callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getThirdPartySharingSettingsWithTimeout"); + this._handleGetterCallback(callback, callbackId); + this._callBridge('getThirdPartySharingSettingsWithTimeout', [timeoutInMilliSec, callbackId]); + } + }, + + getSdkVersion: function (callback) { + if (AdjustBridge) { + const callbackId = window.randomCallbackIdWithPrefix("adjust_getSdkVersion"); + // wrap callback to add SDK prefix before passing to _handleGetterCallback + const wrappedCallback = function(sdkVersion) { + callback(Adjust.getSdkPrefix() + '@' + sdkVersion); + }; + this._handleGetterCallback(wrappedCallback, callbackId); + this._callBridge('getSdkVersion', [callbackId]); + } + }, + + getSdkPrefix: function () { + if (this.adjustConfig) { + return this.adjustConfig.getSdkPrefix(); + } else { + return 'web-bridge5.8.0'; + } + }, + + teardown: function() { + if (AdjustBridge) { + this._callBridge('teardown'); + } + this.adjustConfig = undefined; + this._callbackMap = {}; + this._namedCallbackMap = {}; + this._bridgeToken = null; + this._bridgeTokenRequested = false; + this._pendingBridgeCalls = []; + }, +}; diff --git a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_config.js b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_config.js similarity index 59% rename from Adjust/sdk-plugin-webbridge/src/main/assets/adjust_config.js rename to Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_config.js index 6a98021e1..abc0b3791 100644 --- a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_config.js +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_config.js @@ -19,8 +19,7 @@ function AdjustConfig(appToken, environment, legacy) { } } - this.eventBufferingEnabled = null; - this.sendInBackground = null; + this.isSendingInBackgroundEnabled = null; this.logLevel = null; this.sdkPrefix = null; this.processName = null; @@ -28,8 +27,9 @@ function AdjustConfig(appToken, environment, legacy) { this.externalDeviceId = null; this.attributionCallbackName = null; this.attributionCallbackFunction = null; - this.deviceKnown = null; - this.needsCost = null; + this.thirdPartySharingSettingsChangedCallbackName = null; + this.thirdPartySharingSettingsChangedCallbackFunction = null; + this.isCostDataInAttributionEnabled = null; this.eventSuccessCallbackName = null; this.eventSuccessCallbackFunction = null; this.eventFailureCallbackName = null; @@ -38,39 +38,36 @@ function AdjustConfig(appToken, environment, legacy) { this.sessionSuccessCallbackFunction = null; this.sessionFailureCallbackName = null; this.sessionFailureCallbackFunction = null; - this.openDeferredDeeplink = null; + this.isOpeningDeferredDeeplinkEnabled = null; this.deferredDeeplinkCallbackName = null; this.deferredDeeplinkCallbackFunction = null; - this.delayStart = null; - this.userAgent = null; - this.secretId = null; - this.info1 = null; - this.info2 = null; - this.info3 = null; - this.info4 = null; + this.remoteTriggerCallbackName = null; + this.remoteTriggerCallbackFunction = null; this.fbPixelDefaultEventToken = null; this.fbPixelMapping = []; - this.urlStrategy = null; - this.preinstallTrackingEnabled = null; + this.urlStrategyDomains = []; + this.useSubdomains = null; + this.isDataResidency = null; + this.isPreinstallTrackingEnabled = null; this.preinstallFilePath = null; - this.playStoreKidsAppEnabled = null; - this.coppaCompliantEnabled = null; - this.finalAttributionEnabled = null; + this.coppaComplianceEnabled = null; + this.playStoreKidsComplianceEnabled = null; this.fbAppId = null; - this.readDeviceInfoOnceEnabled = null; + this.shouldReadDeviceIdsOnce = null; + this.eventDeduplicationIdsMaxSize = null; + this.isFirstSessionDelayEnabled = null; + this.storeInfo = null; + this.isGoogleAdIdReadingEnabled = null; + this.isAndroidIdReadingEnabled = null; + this.isAppSetIdReadingEnabled = null; + this.isFbIdReadingEnabled = null; + this.isFireAdIdReadingEnabled = null; + this.isDeviceIdsFromPluginsReadingEnabled = null; } AdjustConfig.EnvironmentSandbox = 'sandbox'; AdjustConfig.EnvironmentProduction = 'production'; -AdjustConfig.UrlStrategyIndia = "url_strategy_india"; -AdjustConfig.UrlStrategyChina = "url_strategy_china"; -AdjustConfig.UrlStrategyCn = "url_strategy_cn"; -AdjustConfig.UrlStrategyCnOnly = "url_strategy_cn_only"; -AdjustConfig.DataResidencyEU = "data_residency_eu"; -AdjustConfig.DataResidencyTR = "data_residency_tr"; -AdjustConfig.DataResidencyUS = "data_residency_us"; - AdjustConfig.LogLevelVerbose = 'VERBOSE', AdjustConfig.LogLevelDebug = 'DEBUG', AdjustConfig.LogLevelInfo = 'INFO', @@ -83,12 +80,8 @@ AdjustConfig.prototype.getBridge = function() { return this.bridge; }; -AdjustConfig.prototype.setEventBufferingEnabled = function(isEnabled) { - this.eventBufferingEnabled = isEnabled; -}; - -AdjustConfig.prototype.setSendInBackground = function(isEnabled) { - this.sendInBackground = isEnabled; +AdjustConfig.prototype.enableSendingInBackground = function() { + this.isSendingInBackgroundEnabled = true; }; AdjustConfig.prototype.setLogLevel = function(logLevel) { @@ -130,12 +123,23 @@ AdjustConfig.prototype.adjust_attributionCallback = function(attribution) { } }; -AdjustConfig.prototype.setDeviceKnown = function(deviceKnown) { - this.deviceKnown = deviceKnown; +AdjustConfig.prototype.setThirdPartySharingSettingsChangedCallback = function(callback) { + if (typeof callback === 'string' || callback instanceof String) { + this.thirdPartySharingSettingsChangedCallbackName = callback; + } else { + this.thirdPartySharingSettingsChangedCallbackName = 'Adjust.getConfig().adjust_thirdPartySharingSettingsChangedCallback'; + this.thirdPartySharingSettingsChangedCallbackFunction = callback; + } +}; + +AdjustConfig.prototype.adjust_thirdPartySharingSettingsChangedCallback = function(result) { + if (this.thirdPartySharingSettingsChangedCallbackFunction) { + this.thirdPartySharingSettingsChangedCallbackFunction(result); + } }; -AdjustConfig.prototype.setNeedsCost = function(needsCost) { - this.needsCost = needsCost; +AdjustConfig.prototype.enableCostDataInAttribution = function() { + this.isCostDataInAttributionEnabled = true; }; AdjustConfig.prototype.setEventSuccessCallback = function(callback) { @@ -198,8 +202,8 @@ AdjustConfig.prototype.adjust_sessionFailureCallback = function(sessionFailure) } }; -AdjustConfig.prototype.setOpenDeferredDeeplink = function(shouldOpen) { - this.openDeferredDeeplink = shouldOpen; +AdjustConfig.prototype.disableDeferredDeeplinkOpening = function() { + this.isOpeningDeferredDeeplinkEnabled = false; }; AdjustConfig.prototype.setDeferredDeeplinkCallback = function(callback) { @@ -217,20 +221,19 @@ AdjustConfig.prototype.adjust_deferredDeeplinkCallback = function(deeplink) { } }; -AdjustConfig.prototype.setDelayStart = function(delayStart) { - this.delayStart = delayStart; -}; - -AdjustConfig.prototype.setUserAgent = function(userAgent) { - this.userAgent = userAgent; +AdjustConfig.prototype.setRemoteTriggerCallback = function(callback) { + if (typeof callback === 'string' || callback instanceof String) { + this.remoteTriggerCallbackName = callback; + } else { + this.remoteTriggerCallbackName = 'Adjust.getConfig().adjust_remoteTriggerCallback'; + this.remoteTriggerCallbackFunction = callback; + } }; -AdjustConfig.prototype.setAppSecret = function(secretId, info1, info2, info3, info4) { - this.secretId = secretId; - this.info1 = info1; - this.info2 = info2; - this.info3 = info3; - this.info4 = info4; +AdjustConfig.prototype.adjust_remoteTriggerCallback = function(remoteTrigger) { + if (this.remoteTriggerCallbackFunction) { + this.remoteTriggerCallbackFunction(remoteTrigger); + } }; AdjustConfig.prototype.setReadMobileEquipmentIdentity = function(readMobileEquipmentIdentity) {}; @@ -244,34 +247,77 @@ AdjustConfig.prototype.addFbPixelMapping = function(fbEventNameKey, adjEventToke this.fbPixelMapping.push(adjEventTokenValue); }; -AdjustConfig.prototype.setUrlStrategy = function(urlStrategy) { - this.urlStrategy = urlStrategy; +AdjustConfig.prototype.setUrlStrategy = function(urlStrategyDomains, useSubdomains , isDataResidency) { + this.urlStrategyDomains = urlStrategyDomains; + this.useSubdomains = useSubdomains; + this.isDataResidency = isDataResidency; }; -AdjustConfig.prototype.setPreinstallTrackingEnabled = function(preinstallTrackingEnabled) { - this.preinstallTrackingEnabled = preinstallTrackingEnabled; +AdjustConfig.prototype.enablePreinstallTracking = function() { + this.isPreinstallTrackingEnabled = true; }; AdjustConfig.prototype.setPreinstallFilePath = function(preinstallFilePath) { this.preinstallFilePath = preinstallFilePath; }; -AdjustConfig.prototype.setPlayStoreKidsAppEnabled = function(isEnabled) { - this.playStoreKidsAppEnabled = isEnabled; +AdjustConfig.prototype.enableCoppaCompliance = function() { + this.coppaComplianceEnabled = true; }; -AdjustConfig.prototype.setCoppaCompliantEnabled = function(isEnabled) { - this.coppaCompliantEnabled = isEnabled; -}; - -AdjustConfig.prototype.setFinalAttributionEnabled = function(isEnabled) { - this.finalAttributionEnabled = isEnabled; +AdjustConfig.prototype.enablePlayStoreKidsCompliance = function() { + this.playStoreKidsComplianceEnabled = true; }; AdjustConfig.prototype.setFbAppId = function(fbAppId) { this.fbAppId = fbAppId; }; -AdjustConfig.prototype.setReadDeviceInfoOnceEnabled = function(isEnabled) { - this.readDeviceInfoOnceEnabled = isEnabled; +AdjustConfig.prototype.readDeviceIdsOnce = function() { + this.shouldReadDeviceIdsOnce = true; +}; + +AdjustConfig.prototype.setEventDeduplicationIdsMaxSize = function(eventDeduplicationIdsMaxSize) { + this.eventDeduplicationIdsMaxSize = eventDeduplicationIdsMaxSize; +}; + +AdjustConfig.prototype.enableFirstSessionDelay = function() { + this.isFirstSessionDelayEnabled = true; +}; + +AdjustConfig.prototype.setStoreInfo = function(storeInfo) { + this.storeInfo = JSON.stringify(storeInfo); +}; + +AdjustConfig.prototype.disableGoogleAdIdReading = function() { + this.isGoogleAdIdReadingEnabled = false; +}; + +AdjustConfig.prototype.disableAndroidIdReading = function() { + this.isAndroidIdReadingEnabled = false; +}; + +AdjustConfig.prototype.disableAppSetIdReading = function() { + this.isAppSetIdReadingEnabled = false; +}; + +AdjustConfig.prototype.disableFbIdReading = function() { + this.isFbIdReadingEnabled = false; +}; + +AdjustConfig.prototype.disableFireAdIdReading = function() { + this.isFireAdIdReadingEnabled = false; +}; + +AdjustConfig.prototype.disableDeviceIdsFromPluginsReading = function() { + this.isDeviceIdsFromPluginsReadingEnabled = false; +}; + +AdjustConfig.prototype.disableDeviceIdsReading = function() { + this.isGoogleAdIdReadingEnabled = false; + this.isAndroidIdReadingEnabled = false; + this.isAppSetIdReadingEnabled = false; + this.isFbIdReadingEnabled = false; + this.isFireAdIdReadingEnabled = false; + this.isDeviceIdsFromPluginsReadingEnabled = false; }; diff --git a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_event.js b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_event.js similarity index 61% rename from Adjust/sdk-plugin-webbridge/src/main/assets/adjust_event.js rename to Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_event.js index 576a1ee3c..6a82d94ef 100644 --- a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_event.js +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_event.js @@ -4,7 +4,7 @@ function AdjustEvent(eventToken) { this.currency = null; this.callbackParameters = []; this.partnerParameters = []; - this.orderId = null; + this.deduplicationId = null; this.callbackId = null; } @@ -14,17 +14,25 @@ AdjustEvent.prototype.setRevenue = function(revenue, currency) { }; AdjustEvent.prototype.addCallbackParameter = function(key, value) { + if (typeof key !== 'string' || typeof value !== 'string') { + console.log('[Adjust]: Passed key or value is not of string type'); + return; + } this.callbackParameters.push(key); this.callbackParameters.push(value); }; AdjustEvent.prototype.addPartnerParameter = function(key, value) { + if (typeof key !== 'string' || typeof value !== 'string') { + console.log('[Adjust]: Passed key or value is not of string type'); + return; + } this.partnerParameters.push(key); this.partnerParameters.push(value); }; -AdjustEvent.prototype.setOrderId = function(orderId) { - this.orderId = orderId; +AdjustEvent.prototype.setDeduplicationId = function(deduplicationId) { + this.deduplicationId = deduplicationId; }; AdjustEvent.prototype.setCallbackId = function(callbackId) { diff --git a/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_store_info.js b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_store_info.js new file mode 100644 index 000000000..d5b48848a --- /dev/null +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_store_info.js @@ -0,0 +1,8 @@ +function AdjustStoreInfo(storeName) { + this.storeName = storeName; + this.storeAppId = null; +} + +AdjustStoreInfo.prototype.setStoreAppId = function(storeAppId) { + this.storeAppId = storeAppId; +}; \ No newline at end of file diff --git a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js similarity index 57% rename from Adjust/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js rename to Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js index 2fd6b66ac..210d0b730 100644 --- a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/assets/adjust_third_party_sharing.js @@ -5,12 +5,20 @@ function AdjustThirdPartySharing(isEnabled) { } AdjustThirdPartySharing.prototype.addGranularOption = function(partnerName, key, value) { + if (typeof partnerName !== 'string' || typeof key !== 'string' || typeof value !== 'string') { + console.log('[Adjust]: Passed partnerName, key or value is not of string type'); + return; + } this.granularOptions.push(partnerName); this.granularOptions.push(key); this.granularOptions.push(value); }; AdjustThirdPartySharing.prototype.addPartnerSharingSetting = function(partnerName, key, value) { + if (typeof partnerName !== 'string' || typeof key !== 'string' || typeof value !== 'boolean') { + console.log('[Adjust]: Passed partnerName or key is not of string type or value is not of boolean type'); + return; + } this.partnerSharingSettings.push(partnerName); this.partnerSharingSettings.push(key); this.partnerSharingSettings.push(value); diff --git a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java similarity index 100% rename from Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java rename to Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridge.java diff --git a/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java new file mode 100644 index 000000000..43dc7371e --- /dev/null +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java @@ -0,0 +1,1296 @@ +package com.adjust.sdk.webbridge; + +import android.net.Uri; +import android.os.Build; +import android.util.Base64; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; +import android.app.Application; + +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.AdjustFactory; +import com.adjust.sdk.AdjustRemoteTrigger; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; +import com.adjust.sdk.AdjustStoreInfo; +import com.adjust.sdk.AdjustThirdPartySharing; +import com.adjust.sdk.AdjustThirdPartySharingResult; +import com.adjust.sdk.LogLevel; +import com.adjust.sdk.OnAdidReadListener; +import com.adjust.sdk.OnAmazonAdIdReadListener; +import com.adjust.sdk.OnAttributionChangedListener; +import com.adjust.sdk.OnAttributionReadListener; +import com.adjust.sdk.OnDeferredDeeplinkResponseListener; +import com.adjust.sdk.OnEventTrackingFailedListener; +import com.adjust.sdk.OnEventTrackingSucceededListener; +import com.adjust.sdk.OnGoogleAdIdReadListener; +import com.adjust.sdk.OnRemoteTriggerListener; +import com.adjust.sdk.OnSdkVersionReadListener; +import com.adjust.sdk.OnIsEnabledListener; +import com.adjust.sdk.OnSessionTrackingFailedListener; +import com.adjust.sdk.OnSessionTrackingSucceededListener; +import com.adjust.sdk.OnThirdPartySharingSettingsChangedListener; +import com.adjust.sdk.OnThirdPartySharingSettingsReadListener; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.List; + +/** + * Created by uerceg on 22/07/16. + */ +public class AdjustBridgeInstance { + private static final String LOG_LEVEL_VERBOSE = "VERBOSE"; + private static final String LOG_LEVEL_DEBUG = "DEBUG"; + private static final String LOG_LEVEL_INFO = "INFO"; + private static final String LOG_LEVEL_WARN = "WARN"; + private static final String LOG_LEVEL_ERROR = "ERROR"; + private static final String LOG_LEVEL_ASSERT = "ASSERT"; + private static final String LOG_LEVEL_SUPPRESS = "SUPPRESS"; + + private static final String JAVASCRIPT_INTERFACE_NAME = "AdjustBridge"; + private static final String FB_JAVASCRIPT_INTERFACE_NAME_PREFIX = "fbmq_"; + + private WebView webView; + private Application application; + private boolean isInitialized = false; + private boolean isOpeningDeferredDeeplinkEnabled = true; + private FacebookSDKJSInterface facebookSDKJSInterface = null; + + private String adjustSdkPrefix = null; + private boolean isBridgeSecurityEnabled = false; + private String bridgeSecurityToken = null; + + AdjustBridgeInstance() {} + + AdjustBridgeInstance(Application application, WebView webView) { + this.application = application; + setWebView(webView); + } + + private boolean isInitialized() { + if (webView == null) { + AdjustBridgeUtil.getLogger().error("Webview missing. Call AdjustBridge.setWebView before"); + return false; + } + if (application == null) { + AdjustBridgeUtil.getLogger().error("Application context missing. Call AdjustBridge.setApplicationContext before"); + return false; + } + return true; + } + + private boolean isBridgeAuthorized(String token) { + if (!isBridgeSecurityEnabled) { + return true; + } + if (bridgeSecurityToken == null) { + return false; + } + return bridgeSecurityToken.equals(token); + } + + private void enableBridgeSecurity() { + if (!isBridgeSecurityEnabled) { + isBridgeSecurityEnabled = true; + } + if (bridgeSecurityToken == null) { + bridgeSecurityToken = generateBridgeToken(); + } + AdjustBridgeUtil.sendBridgeTokenToWebView(webView, bridgeSecurityToken); + } + + private String generateBridgeToken() { + byte[] tokenBytes = new byte[16]; + new SecureRandom().nextBytes(tokenBytes); + return Base64.encodeToString(tokenBytes, Base64.NO_WRAP); + } + + public void registerFacebookSDKJSInterface() { + // Configure the web view to add fb pixel interface + String fbApplicationId = FacebookSDKJSInterface.getApplicationId(application.getApplicationContext()); + AdjustFactory.getLogger().info("AdjustBridgeInstance fbApplicationId: %s", fbApplicationId); + + if (fbApplicationId == null) { + return; + } + + this.facebookSDKJSInterface = new FacebookSDKJSInterface(); + + // Add FB pixel to JS interface. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + this.webView.addJavascriptInterface(facebookSDKJSInterface, + FB_JAVASCRIPT_INTERFACE_NAME_PREFIX + + fbApplicationId + ); + } + } + + @JavascriptInterface + public void initSdk(String adjustConfigString) { + initSdk(adjustConfigString, null); + } + + @JavascriptInterface + public void initSdk(String adjustConfigString, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + // Initialise SDK only if it's not already initialised. + if (isInitialized) { + AdjustBridgeUtil.getLogger().warn("Adjust bridge is already initialized. Ignoring further attempts"); + return; + } + if (!isInitialized()) { + return; + } + + try { + AdjustBridgeUtil.getLogger().verbose("Web bridge onCreate adjustConfigString: " + adjustConfigString); + + JSONObject jsonAdjustConfig = new JSONObject(adjustConfigString); + Object appTokenField = jsonAdjustConfig.get("appToken"); + Object environmentField = jsonAdjustConfig.get("environment"); + Object allowSuppressLogLevelField = jsonAdjustConfig.get("allowSuppressLogLevel"); + Object isSendingInBackgroundEnabledField = jsonAdjustConfig.get("isSendingInBackgroundEnabled"); + Object logLevelField = jsonAdjustConfig.get("logLevel"); + Object sdkPrefixField = jsonAdjustConfig.get("sdkPrefix"); + Object processNameField = jsonAdjustConfig.get("processName"); + Object defaultTrackerField = jsonAdjustConfig.get("defaultTracker"); + Object externalDeviceIdField = jsonAdjustConfig.get("externalDeviceId"); + Object attributionCallbackNameField = jsonAdjustConfig.get("attributionCallbackName"); + Object thirdPartySharingSettingsChangedCallbackNameField = jsonAdjustConfig.get("thirdPartySharingSettingsChangedCallbackName"); + Object isCostDataInAttributionEnabledField = jsonAdjustConfig.get("isCostDataInAttributionEnabled"); + Object eventSuccessCallbackNameField = jsonAdjustConfig.get("eventSuccessCallbackName"); + Object eventFailureCallbackNameField = jsonAdjustConfig.get("eventFailureCallbackName"); + Object sessionSuccessCallbackNameField = jsonAdjustConfig.get("sessionSuccessCallbackName"); + Object sessionFailureCallbackNameField = jsonAdjustConfig.get("sessionFailureCallbackName"); + Object isOpeningDeferredDeeplinkEnabledField = jsonAdjustConfig.get("isOpeningDeferredDeeplinkEnabled"); + Object deferredDeeplinkCallbackNameField = jsonAdjustConfig.get("deferredDeeplinkCallbackName"); + Object remoteTriggerCallbackNameField = jsonAdjustConfig.get("remoteTriggerCallbackName"); + Object fbPixelDefaultEventTokenField = jsonAdjustConfig.get("fbPixelDefaultEventToken"); + Object fbPixelMappingField = jsonAdjustConfig.get("fbPixelMapping"); + Object urlStrategyDomainsField = jsonAdjustConfig.get("urlStrategyDomains"); + Object useSubdomainsField = jsonAdjustConfig.get("useSubdomains"); + Object isDataResidencyField = jsonAdjustConfig.get("isDataResidency"); + Object isPreinstallTrackingEnabledField = jsonAdjustConfig.get("isPreinstallTrackingEnabled"); + Object preinstallFilePathField = jsonAdjustConfig.get("preinstallFilePath"); + Object coppaComplianceEnabledField = jsonAdjustConfig.get("coppaComplianceEnabled"); + Object playStoreKidsComplianceEnabledField = jsonAdjustConfig.get("playStoreKidsComplianceEnabled"); + Object fbAppIdField = jsonAdjustConfig.get("fbAppId"); + Object shouldReadDeviceIdsOnceField = jsonAdjustConfig.get("shouldReadDeviceIdsOnce"); + Object eventDeduplicationIdsMaxSizeField = jsonAdjustConfig.get("eventDeduplicationIdsMaxSize"); + Object isFirstSessionDelayEnabledField = jsonAdjustConfig.get("isFirstSessionDelayEnabled"); + Object storeInfoField = jsonAdjustConfig.get("storeInfo"); + Object isGoogleAdIdReadingEnabledField = jsonAdjustConfig.get("isGoogleAdIdReadingEnabled"); + Object isAndroidIdReadingEnabledField = jsonAdjustConfig.get("isAndroidIdReadingEnabled"); + Object isAppSetIdReadingEnabledField = jsonAdjustConfig.get("isAppSetIdReadingEnabled"); + Object isFbIdReadingEnabledField = jsonAdjustConfig.get("isFbIdReadingEnabled"); + Object isFireAdIdReadingEnabledField = jsonAdjustConfig.get("isFireAdIdReadingEnabled"); + Object isDeviceIdsFromPluginsReadingEnabledField = jsonAdjustConfig.get("isDeviceIdsFromPluginsReadingEnabled"); + + String appToken = AdjustBridgeUtil.fieldToString(appTokenField); + String environment = AdjustBridgeUtil.fieldToString(environmentField); + Boolean allowSuppressLogLevel = AdjustBridgeUtil.fieldToBoolean(allowSuppressLogLevelField); + + AdjustConfig adjustConfig; + if (allowSuppressLogLevel == null) { + adjustConfig = new AdjustConfig(application.getApplicationContext(), appToken, environment); + } else { + adjustConfig = new AdjustConfig(application.getApplicationContext(), appToken, environment, allowSuppressLogLevel.booleanValue()); + } + + if (!adjustConfig.isValid()) { + return; + } + + // Send in the background + Boolean isSendingInBackgroundEnabled = AdjustBridgeUtil.fieldToBoolean(isSendingInBackgroundEnabledField); + if (isSendingInBackgroundEnabled != null) { + if (isSendingInBackgroundEnabled) { + adjustConfig.enableSendingInBackground(); + } + } + + // Log level + String logLevelString = AdjustBridgeUtil.fieldToString(logLevelField); + if (logLevelString != null) { + if (logLevelString.equalsIgnoreCase(LOG_LEVEL_VERBOSE)) { + adjustConfig.setLogLevel(LogLevel.VERBOSE); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_DEBUG)) { + adjustConfig.setLogLevel(LogLevel.DEBUG); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_INFO)) { + adjustConfig.setLogLevel(LogLevel.INFO); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_WARN)) { + adjustConfig.setLogLevel(LogLevel.WARN); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_ERROR)) { + adjustConfig.setLogLevel(LogLevel.ERROR); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_ASSERT)) { + adjustConfig.setLogLevel(LogLevel.ASSERT); + } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_SUPPRESS)) { + adjustConfig.setLogLevel(LogLevel.SUPPRESS); + } + } + + // SDK prefix + String sdkPrefix = AdjustBridgeUtil.fieldToString(sdkPrefixField); + if (sdkPrefix != null) { + adjustConfig.setSdkPrefix(sdkPrefix); + adjustSdkPrefix = sdkPrefix; + } + + // Main process name + String processName = AdjustBridgeUtil.fieldToString(processNameField); + if (processName != null) { + adjustConfig.setProcessName(processName); + } + + // Default tracker + String defaultTracker = AdjustBridgeUtil.fieldToString(defaultTrackerField); + if (defaultTracker != null) { + adjustConfig.setDefaultTracker(defaultTracker); + } + + // External device ID + String externalDeviceId = AdjustBridgeUtil.fieldToString(externalDeviceIdField); + if (externalDeviceId != null) { + adjustConfig.setExternalDeviceId(externalDeviceId); + } + + // Attribution callback name + final String attributionCallbackName = AdjustBridgeUtil.fieldToString(attributionCallbackNameField); + if (attributionCallbackName != null) { + adjustConfig.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution attribution) { + AdjustBridgeUtil.execAttributionCallbackCommand(webView, attributionCallbackName, attribution); + } + }); + } + + // Third party sharing settings changed callback name + final String thirdPartySharingSettingsChangedCallbackName = + AdjustBridgeUtil.fieldToString(thirdPartySharingSettingsChangedCallbackNameField); + if (thirdPartySharingSettingsChangedCallbackName != null) { + adjustConfig.setOnThirdPartySharingSettingsChangedListener(new OnThirdPartySharingSettingsChangedListener() { + @Override + public void onThirdPartySharingSettingsChanged(AdjustThirdPartySharingResult adjustThirdPartySharingResult) { + AdjustBridgeUtil.execThirdPartySharingSettingsCallbackCommand( + webView, thirdPartySharingSettingsChangedCallbackName, adjustThirdPartySharingResult); + } + }); + } + + // Needs cost + Boolean isCostDataInAttributionEnabled = AdjustBridgeUtil.fieldToBoolean(isCostDataInAttributionEnabledField); + if (isCostDataInAttributionEnabled != null) { + if (isCostDataInAttributionEnabled) { + adjustConfig.enableCostDataInAttribution(); + } + } + + // Event success callback + final String eventSuccessCallbackName = AdjustBridgeUtil.fieldToString(eventSuccessCallbackNameField); + if (eventSuccessCallbackName != null) { + adjustConfig.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { + public void onEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + AdjustBridgeUtil.execEventSuccessCallbackCommand(webView, eventSuccessCallbackName, eventSuccessResponseData); + } + }); + } + + // Event failure callback + final String eventFailureCallbackName = AdjustBridgeUtil.fieldToString(eventFailureCallbackNameField); + if (eventFailureCallbackName != null) { + adjustConfig.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { + public void onEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + AdjustBridgeUtil.execEventFailureCallbackCommand(webView, eventFailureCallbackName, eventFailureResponseData); + } + }); + } + + // Session success callback + final String sessionSuccessCallbackName = AdjustBridgeUtil.fieldToString(sessionSuccessCallbackNameField); + if (sessionSuccessCallbackName != null) { + adjustConfig.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { + @Override + public void onSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + AdjustBridgeUtil.execSessionSuccessCallbackCommand(webView, sessionSuccessCallbackName, sessionSuccessResponseData); + } + }); + } + + // Session failure callback + final String sessionFailureCallbackName = AdjustBridgeUtil.fieldToString(sessionFailureCallbackNameField); + if (sessionFailureCallbackName != null) { + adjustConfig.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { + @Override + public void onSessionTrackingFailed(AdjustSessionFailure failureResponseData) { + AdjustBridgeUtil.execSessionFailureCallbackCommand(webView, sessionFailureCallbackName, failureResponseData); + } + }); + } + + // Should deferred deeplink be opened? + Boolean isOpeningDeferredDeeplinkEnabledObject = AdjustBridgeUtil.fieldToBoolean(isOpeningDeferredDeeplinkEnabledField); + if (isOpeningDeferredDeeplinkEnabledObject != null) { + isOpeningDeferredDeeplinkEnabled = isOpeningDeferredDeeplinkEnabledObject; + } + + // Deferred deeplink callback + final String deferredDeeplinkCallbackName = AdjustBridgeUtil.fieldToString(deferredDeeplinkCallbackNameField); + if (deferredDeeplinkCallbackName != null) { + adjustConfig.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + AdjustBridgeUtil.execSingleValueCallback(webView, deferredDeeplinkCallbackName, deeplink.toString()); + return isOpeningDeferredDeeplinkEnabled; + } + }); + } + + // Remote trigger callback + final String remoteTriggerCallbackName = AdjustBridgeUtil.fieldToString(remoteTriggerCallbackNameField); + if (remoteTriggerCallbackName != null) { + adjustConfig.setOnRemoteTriggerListener(new OnRemoteTriggerListener() { + @Override + public void onRemoteTrigger(AdjustRemoteTrigger remoteTrigger) { + AdjustBridgeUtil.execRemoteTriggerCallbackCommand(webView, remoteTriggerCallbackName, remoteTrigger); + } + }); + } + + // Check Pixel Default Event Token + String fbPixelDefaultEventToken = AdjustBridgeUtil.fieldToString(fbPixelDefaultEventTokenField); + if (fbPixelDefaultEventToken != null && this.facebookSDKJSInterface != null) { + this.facebookSDKJSInterface.setDefaultEventToken(fbPixelDefaultEventToken); + } + + // Add Pixel mappings + try { + String[] fbPixelMapping = AdjustBridgeUtil.jsonArrayToArray((JSONArray)fbPixelMappingField); + if (fbPixelMapping != null && this.facebookSDKJSInterface != null) { + for (int i = 0; i < fbPixelMapping.length; i += 2) { + String key = fbPixelMapping[i]; + String value = fbPixelMapping[i+1]; + this.facebookSDKJSInterface.addFbPixelEventTokenMapping(key, value); + } + } + } catch (Exception e) { + AdjustFactory.getLogger().error("AdjustBridgeInstance.configureFbPixel: %s", e.getMessage()); + } + + // Set url strategy + String[] urlStrategyDomainsArray = AdjustBridgeUtil.jsonArrayToArray((JSONArray) urlStrategyDomainsField); + List urlStrategyDomains = Arrays.asList(urlStrategyDomainsArray); + + Boolean useSubdomains = AdjustBridgeUtil.fieldToBoolean(useSubdomainsField); + Boolean isDataResidency = AdjustBridgeUtil.fieldToBoolean(isDataResidencyField); + if (urlStrategyDomains != null && !urlStrategyDomains.isEmpty() && useSubdomains != null && isDataResidency != null) { + adjustConfig.setUrlStrategy(urlStrategyDomains,useSubdomains,isDataResidency); + } + + // Preinstall tracking + Boolean isPreinstallTrackingEnabled = AdjustBridgeUtil.fieldToBoolean(isPreinstallTrackingEnabledField); + if (isPreinstallTrackingEnabled != null) { + if (isPreinstallTrackingEnabled) { + adjustConfig.enablePreinstallTracking(); + } + } + + // Preinstall secondary file path + String preinstallFilePath = AdjustBridgeUtil.fieldToString(preinstallFilePathField); + if (preinstallFilePath != null) { + adjustConfig.setPreinstallFilePath(preinstallFilePath); + } + + // Coppa compliance + Boolean coppaCompliantEnabled = AdjustBridgeUtil.fieldToBoolean(coppaComplianceEnabledField); + if (coppaCompliantEnabled != null) { + if (coppaCompliantEnabled) { + adjustConfig.enableCoppaCompliance(); + } + } + + // PlayStore Kids compliance + Boolean playStoreKidsComplianceEnabled = AdjustBridgeUtil.fieldToBoolean(playStoreKidsComplianceEnabledField); + if (playStoreKidsComplianceEnabled != null) { + if (playStoreKidsComplianceEnabled) { + adjustConfig.enablePlayStoreKidsCompliance(); + } + } + + // FB App ID + String fbAppId = AdjustBridgeUtil.fieldToString(fbAppIdField); + if (fbAppId != null) { + adjustConfig.setFbAppId(fbAppId); + } + + // read device info once + Boolean shouldReadDeviceIdsOnce = AdjustBridgeUtil.fieldToBoolean(shouldReadDeviceIdsOnceField); + if (shouldReadDeviceIdsOnce != null && shouldReadDeviceIdsOnce.booleanValue()) { + adjustConfig.enableDeviceIdsReadingOnce(); + } + + Integer eventDeduplicationIdsMaxSize = AdjustBridgeUtil.fieldToInteger(eventDeduplicationIdsMaxSizeField); + if (eventDeduplicationIdsMaxSize != null) { + adjustConfig.setEventDeduplicationIdsMaxSize(eventDeduplicationIdsMaxSize); + } + + // First session delay + Boolean isFirstSessionDelayEnabled = AdjustBridgeUtil.fieldToBoolean(isFirstSessionDelayEnabledField); + if (isFirstSessionDelayEnabled != null) { + if (isFirstSessionDelayEnabled) { + adjustConfig.enableFirstSessionDelay(); + } + } + + // store info + String storeInfoString = AdjustBridgeUtil.fieldToString(storeInfoField); + + try { + if (storeInfoString != null) { + JSONObject jsonStoreInfo = new JSONObject(storeInfoString); + + Object storeNameField = jsonStoreInfo.get("storeName"); + Object storeAppIdField = jsonStoreInfo.get("storeAppId"); + + String storeName = AdjustBridgeUtil.fieldToString(storeNameField); + String storeAppId = AdjustBridgeUtil.fieldToString(storeAppIdField); + AdjustStoreInfo storeInfo = new AdjustStoreInfo(storeName); + storeInfo.setStoreAppId(storeAppId); + + // set store info + adjustConfig.setStoreInfo(storeInfo); + } + } catch (Exception e) { + AdjustFactory.getLogger().error("AdjustBridgeInstance storeInfo: %s", e.getMessage()); + } + + // Google AdId reading + Boolean isGoogleAdIdReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isGoogleAdIdReadingEnabledField); + if (isGoogleAdIdReadingEnabled != null) { + if (!isGoogleAdIdReadingEnabled) { + adjustConfig.disableGoogleAdIdReading(); + } + } + + // Android Id reading + Boolean isAndroidIdReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isAndroidIdReadingEnabledField); + if (isAndroidIdReadingEnabled != null) { + if (!isAndroidIdReadingEnabled) { + adjustConfig.disableAndroidIdReading(); + } + } + + // AppSetId reading + Boolean isAppSetIdReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isAppSetIdReadingEnabledField); + if (isAppSetIdReadingEnabled != null) { + if (!isAppSetIdReadingEnabled) { + adjustConfig.disableAppSetIdReading(); + } + } + + // FbId reading + Boolean isFbIdReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isFbIdReadingEnabledField); + if (isFbIdReadingEnabled != null) { + if (!isFbIdReadingEnabled) { + adjustConfig.disableFbIdReading(); + } + } + + // Fire AdId reading + Boolean isFireAdIdReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isFireAdIdReadingEnabledField); + if (isFireAdIdReadingEnabled != null) { + if (!isFireAdIdReadingEnabled) { + adjustConfig.disableFireAdIdReading(); + } + } + + Boolean isDeviceIdsFromPluginsReadingEnabled = AdjustBridgeUtil.fieldToBoolean(isDeviceIdsFromPluginsReadingEnabledField); + if (isDeviceIdsFromPluginsReadingEnabled != null) { + if (!isDeviceIdsFromPluginsReadingEnabled) { + adjustConfig.disableDeviceIdsFromPluginsReading(); + } + } + + enableBridgeSecurity(); + + Adjust.initSdk(adjustConfig); + + isInitialized = true; + + } catch (Exception e) { + AdjustFactory.getLogger().error("AdjustBridgeInstance onCreate: %s", e.getMessage()); + } + } + + @JavascriptInterface + public void requestBridgeToken() { + if (webView == null) { + return; + } + enableBridgeSecurity(); + } + + @JavascriptInterface + public void trackEvent(String adjustEventString) { + trackEvent(adjustEventString, null); + } + + @JavascriptInterface + public void trackEvent(String adjustEventString, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + + try { + JSONObject jsonAdjustEvent = new JSONObject(adjustEventString); + + Object eventTokenField = jsonAdjustEvent.get("eventToken"); + Object revenueField = jsonAdjustEvent.get("revenue"); + Object currencyField = jsonAdjustEvent.get("currency"); + Object callbackParametersField = jsonAdjustEvent.get("callbackParameters"); + Object partnerParametersField = jsonAdjustEvent.get("partnerParameters"); + Object deduplicationIdField = jsonAdjustEvent.get("deduplicationId"); + Object callbackIdField = jsonAdjustEvent.get("callbackId"); + + String eventToken = AdjustBridgeUtil.fieldToString(eventTokenField); + AdjustEvent adjustEvent = new AdjustEvent(eventToken); + + if (!adjustEvent.isValid()) { + return; + } + + // Revenue + Double revenue = AdjustBridgeUtil.fieldToDouble(revenueField); + String currency = AdjustBridgeUtil.fieldToString(currencyField); + if (revenue != null && currency != null) { + adjustEvent.setRevenue(revenue, currency); + } + + // Callback parameters + String[] callbackParameters = AdjustBridgeUtil.jsonArrayToArray((JSONArray)callbackParametersField); + if (callbackParameters != null) { + for (int i = 0; i < callbackParameters.length; i += 2) { + String key = callbackParameters[i]; + String value = callbackParameters[i+1]; + adjustEvent.addCallbackParameter(key, value); + } + } + + // Partner parameters + String[] partnerParameters = AdjustBridgeUtil.jsonArrayToArray((JSONArray)partnerParametersField); + if (partnerParameters != null) { + for (int i = 0; i < partnerParameters.length; i += 2) { + String key = partnerParameters[i]; + String value = partnerParameters[i+1]; + adjustEvent.addPartnerParameter(key, value); + } + } + + // Revenue deduplication + String deduplicationId = AdjustBridgeUtil.fieldToString(deduplicationIdField); + if (deduplicationId != null) { + adjustEvent.setDeduplicationId(deduplicationId); + } + + // Callback id + String callbackId = AdjustBridgeUtil.fieldToString(callbackIdField); + if (callbackId != null) { + adjustEvent.setCallbackId(callbackId); + } + + // Track event + Adjust.trackEvent(adjustEvent); + } catch (Exception e) { + AdjustFactory.getLogger().error("AdjustBridgeInstance trackEvent: %s", e.getMessage()); + } + } + + + @JavascriptInterface + public void onResume() { + onResume(null); + } + + @JavascriptInterface + public void onResume(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.onResume(); + } + + @JavascriptInterface + public void onPause() { + onPause(null); + } + + @JavascriptInterface + public void onPause(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.onPause(); + } + + @JavascriptInterface + public void enable() { + enable(null); + } + + @JavascriptInterface + public void enable(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.enable(); + } + + @JavascriptInterface + public void disable() { + disable(null); + } + + @JavascriptInterface + public void disable(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.disable(); + } + + @JavascriptInterface + public void isEnabled(String callback) { + isEnabled(callback, null); + } + + @JavascriptInterface + public void isEnabled(String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.isEnabled(application.getApplicationContext(),new OnIsEnabledListener() { + @Override + public void onIsEnabledRead(boolean isEnabled) { + AdjustBridgeUtil.execSingleValueCallback(webView, callback, String.valueOf(isEnabled)); + } + }); + } + + @JavascriptInterface + public void setReferrer(String referrer) { + setReferrer(referrer, null); + } + + @JavascriptInterface + public void setReferrer(String referrer, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.setReferrer(referrer, application.getApplicationContext()); + } + + @JavascriptInterface + public void switchToOfflineMode() { + switchToOfflineMode(null); + } + + @JavascriptInterface + public void switchToOfflineMode(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.switchToOfflineMode(); + } + + @JavascriptInterface + public void switchBackToOnlineMode() { + switchBackToOnlineMode(null); + } + + @JavascriptInterface + public void switchBackToOnlineMode(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.switchBackToOnlineMode(); + } + + @JavascriptInterface + public void addGlobalCallbackParameter(String key, String value) { + addGlobalCallbackParameter(key, value, null); + } + + @JavascriptInterface + public void addGlobalCallbackParameter(String key, String value, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.addGlobalCallbackParameter(key, value); + } + + @JavascriptInterface + public void addGlobalPartnerParameter(String key, String value) { + addGlobalPartnerParameter(key, value, null); + } + + @JavascriptInterface + public void addGlobalPartnerParameter(String key, String value, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.addGlobalPartnerParameter(key, value); + } + + @JavascriptInterface + public void removeGlobalCallbackParameter(String key) { + removeGlobalCallbackParameter(key, null); + } + + @JavascriptInterface + public void removeGlobalCallbackParameter(String key, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.removeGlobalCallbackParameter(key); + } + + @JavascriptInterface + public void removeGlobalPartnerParameter(String key) { + removeGlobalPartnerParameter(key, null); + } + + @JavascriptInterface + public void removeGlobalPartnerParameter(String key, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.removeGlobalPartnerParameter(key); + } + + @JavascriptInterface + public void removeGlobalCallbackParameters() { + removeGlobalCallbackParameters(null); + } + + @JavascriptInterface + public void removeGlobalCallbackParameters(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.removeGlobalCallbackParameters(); + } + + @JavascriptInterface + public void removeGlobalPartnerParameters() { + removeGlobalPartnerParameters(null); + } + + @JavascriptInterface + public void removeGlobalPartnerParameters(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.removeGlobalPartnerParameters(); + } + + @JavascriptInterface + public void gdprForgetMe() { + gdprForgetMe(null); + } + + @JavascriptInterface + public void gdprForgetMe(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.gdprForgetMe(application.getApplicationContext()); + } + + @JavascriptInterface + public void trackThirdPartySharing(String adjustThirdPartySharingString) { + trackThirdPartySharing(adjustThirdPartySharingString, null); + } + + @JavascriptInterface + public void trackThirdPartySharing(String adjustThirdPartySharingString, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + + try { + JSONObject jsonAdjustThirdPartySharing = new JSONObject(adjustThirdPartySharingString); + + Object isEnabledField = + jsonAdjustThirdPartySharing.get("isEnabled"); + Object granularOptionsField = jsonAdjustThirdPartySharing.get("granularOptions"); + Object partnerSharingSettingsField = jsonAdjustThirdPartySharing.get("partnerSharingSettings"); + + Boolean isEnabled = AdjustBridgeUtil.fieldToBoolean(isEnabledField); + + AdjustThirdPartySharing adjustThirdPartySharing = + new AdjustThirdPartySharing(isEnabled); + + // Granular options + String[] granularOptions = + AdjustBridgeUtil.jsonArrayToArray((JSONArray)granularOptionsField); + if (granularOptions != null) { + for (int i = 0; i < granularOptions.length; i += 3) { + String partnerName = granularOptions[i]; + String key = granularOptions[i + 1]; + String value = granularOptions[i + 2]; + adjustThirdPartySharing.addGranularOption(partnerName, key, value); + } + } + + // Partner sharing settings + String[] partnerSharingSettings = + AdjustBridgeUtil.jsonArrayToArray((JSONArray)partnerSharingSettingsField); + if (partnerSharingSettings != null) { + for (int i = 0; i < partnerSharingSettings.length; i += 3) { + String partnerName = partnerSharingSettings[i]; + String key = partnerSharingSettings[i + 1]; + Boolean value = AdjustBridgeUtil.fieldToBoolean(partnerSharingSettings[i + 2]); + if (value != null) { + adjustThirdPartySharing.addPartnerSharingSetting(partnerName, key, value); + } else { + AdjustFactory.getLogger().error("Cannot add partner sharing setting with non boolean value"); + } + } + } + + // Track ThirdPartySharing + Adjust.trackThirdPartySharing(adjustThirdPartySharing); + } catch (Exception e) { + AdjustFactory.getLogger().error( + "AdjustBridgeInstance trackThirdPartySharing: %s", e.getMessage()); + } + } + + @JavascriptInterface + public void trackMeasurementConsent(String consentMeasurementString) { + trackMeasurementConsent(consentMeasurementString, null); + } + + @JavascriptInterface + public void trackMeasurementConsent(String consentMeasurementString, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Boolean consentMeasurement = AdjustBridgeUtil.fieldToBoolean(consentMeasurementString); + if (consentMeasurement != null) { + Adjust.trackMeasurementConsent(consentMeasurement); + } + } + + @JavascriptInterface + public void endFirstSessionDelay() { + endFirstSessionDelay(null); + } + + @JavascriptInterface + public void endFirstSessionDelay(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.endFirstSessionDelay(); + } + + @JavascriptInterface + public void enableCoppaComplianceInDelay() { + enableCoppaComplianceInDelay(null); + } + + @JavascriptInterface + public void enableCoppaComplianceInDelay(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.enableCoppaComplianceInDelay(); + } + + @JavascriptInterface + public void disableCoppaComplianceInDelay() { + disableCoppaComplianceInDelay(null); + } + + @JavascriptInterface + public void disableCoppaComplianceInDelay(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.disableCoppaComplianceInDelay(); + } + + @JavascriptInterface + public void enablePlayStoreKidsComplianceInDelay() { + enablePlayStoreKidsComplianceInDelay(null); + } + + @JavascriptInterface + public void enablePlayStoreKidsComplianceInDelay(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.enablePlayStoreKidsComplianceInDelay(); + } + + @JavascriptInterface + public void disablePlayStoreKidsComplianceInDelay() { + disablePlayStoreKidsComplianceInDelay(null); + } + + @JavascriptInterface + public void disablePlayStoreKidsComplianceInDelay(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.disablePlayStoreKidsComplianceInDelay(); + } + + @JavascriptInterface + public void setExternalDeviceIdInDelay(String externalDeviceId) { + setExternalDeviceIdInDelay(externalDeviceId, null); + } + + @JavascriptInterface + public void setExternalDeviceIdInDelay(String externalDeviceId, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.setExternalDeviceIdInDelay(externalDeviceId); + } + + @JavascriptInterface + public void getGoogleAdId(final String callback) { + getGoogleAdId(callback, null); + } + + @JavascriptInterface + public void getGoogleAdId(final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getGoogleAdId(application.getApplicationContext(), new OnGoogleAdIdReadListener() { + @Override + public void onGoogleAdIdRead(String googleAdId) { + AdjustBridgeUtil.execSingleValueCallback(webView, callback, googleAdId); + } + }); + } + + @JavascriptInterface + public void getAmazonAdId(final String callbackSuccess) { + getAmazonAdId(callbackSuccess, null); + } + + @JavascriptInterface + public void getAmazonAdId(final String callbackSuccess, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getAmazonAdId(application.getApplicationContext(),new OnAmazonAdIdReadListener() { + @Override + public void onAmazonAdIdRead(String adid) { + AdjustBridgeUtil.execSingleValueCallback(webView, callbackSuccess, adid); + } + }); + } + + @JavascriptInterface + public void getAdid(final String callback) { + getAdid(callback, null); + } + + @JavascriptInterface + public void getAdid(final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getAdid(new OnAdidReadListener() { + @Override + public void onAdidRead(String adid) { + AdjustBridgeUtil.execSingleValueCallback(webView, callback, adid); + } + }); + } + + @JavascriptInterface + public void getAdidWithTimeout(final long timeoutInMilliSec, final String callback) { + getAdidWithTimeout(timeoutInMilliSec, callback, null); + } + + @JavascriptInterface + public void getAdidWithTimeout(final long timeoutInMilliSec, final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getAdidWithTimeout(application.getApplicationContext(), timeoutInMilliSec, + new OnAdidReadListener() { + @Override + public void onAdidRead(String adid) { + AdjustBridgeUtil.execAdidCallbackCommand(webView, callback, adid); + } + }); + } + + @JavascriptInterface + public void getAttribution(final String callback) { + getAttribution(callback, null); + } + + @JavascriptInterface + public void getAttribution(final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getAttribution(new OnAttributionReadListener() { + @Override + public void onAttributionRead(AdjustAttribution attribution) { + AdjustBridgeUtil.execAttributionCallbackCommand(webView, callback, attribution); + } + + }); + } + + @JavascriptInterface + public void getAttributionWithTimeout(final long timeoutInMilliSec, final String callback) { + getAttributionWithTimeout(timeoutInMilliSec, callback, null); + } + + @JavascriptInterface + public void getAttributionWithTimeout(final long timeoutInMilliSec, final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getAttributionWithTimeout(application.getApplicationContext(), timeoutInMilliSec, + new OnAttributionReadListener() { + @Override + public void onAttributionRead(AdjustAttribution attribution) { + AdjustBridgeUtil.execAttributionCallbackCommand(webView, callback, attribution); + } + }); + } + + @JavascriptInterface + public void getThirdPartySharingSettingsWithTimeout(final long timeoutInMilliSec, final String callback) { + getThirdPartySharingSettingsWithTimeout(timeoutInMilliSec, callback, null); + } + + @JavascriptInterface + public void getThirdPartySharingSettingsWithTimeout(final long timeoutInMilliSec, final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getThirdPartySharingSettingsWithTimeout(application.getApplicationContext(), timeoutInMilliSec, + new OnThirdPartySharingSettingsReadListener() { + @Override + public void onThirdPartySharingSettingsRead(AdjustThirdPartySharingResult adjustThirdPartySharingResult) { + AdjustBridgeUtil.execThirdPartySharingSettingsCallbackCommand(webView, callback, adjustThirdPartySharingResult); + } + }); + } + + @JavascriptInterface + public void getSdkVersion(final String callback) { + getSdkVersion(callback, null); + } + + @JavascriptInterface + public void getSdkVersion(final String callback, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + if (!isInitialized()) { + return; + } + Adjust.getSdkVersion(new OnSdkVersionReadListener() { + @Override + public void onSdkVersionRead(String sdkVersion) { + AdjustBridgeUtil.execSingleValueCallback(webView, callback, sdkVersion); + } + }); + } + + @JavascriptInterface + public void fbPixelEvent(String pixelId, String event_name, String jsonString) { + fbPixelEvent(pixelId, event_name, jsonString, null); + } + + @JavascriptInterface + public void fbPixelEvent(String pixelId, String event_name, String jsonString, String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + this.facebookSDKJSInterface.sendEvent(pixelId, event_name, jsonString); + } + + @JavascriptInterface + public void teardown() { + teardown(null); + } + + @JavascriptInterface + public void teardown(String bridgeToken) { + if (!isBridgeAuthorized(bridgeToken)) { + return; + } + isInitialized = false; + isOpeningDeferredDeeplinkEnabled = true; + isBridgeSecurityEnabled = false; + bridgeSecurityToken = null; + } + + public void setWebView(WebView webView) { + this.webView = webView; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + webView.addJavascriptInterface(this, JAVASCRIPT_INTERFACE_NAME); + } + enableBridgeSecurity(); + } + + public void setApplicationContext(Application application) { + this.application = application; + } + + public void unregister() { + if (!isInitialized()) { + return; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + this.webView.removeJavascriptInterface(JAVASCRIPT_INTERFACE_NAME); + } + + unregisterFacebookSDKJSInterface(); + + application = null; + webView = null; + isInitialized = false; + isBridgeSecurityEnabled = false; + bridgeSecurityToken = null; + } + + public void unregisterFacebookSDKJSInterface() { + if (!isInitialized()) { + return; + } + + if (this.facebookSDKJSInterface == null) { + return; + } + + String fbApplicationId = FacebookSDKJSInterface.getApplicationId(application.getApplicationContext()); + if (fbApplicationId == null) { + return; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + this.webView.removeJavascriptInterface(FB_JAVASCRIPT_INTERFACE_NAME_PREFIX + fbApplicationId); + } + + this.facebookSDKJSInterface = null; + } +} diff --git a/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java new file mode 100644 index 000000000..38d7c801a --- /dev/null +++ b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java @@ -0,0 +1,321 @@ +package com.adjust.sdk.webbridge; + +import android.net.Uri; +import android.webkit.WebView; + +import com.adjust.sdk.AdjustAttribution; +import com.adjust.sdk.AdjustEventFailure; +import com.adjust.sdk.AdjustEventSuccess; +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.AdjustRemoteTrigger; +import com.adjust.sdk.AdjustSessionFailure; +import com.adjust.sdk.AdjustSessionSuccess; +import com.adjust.sdk.AdjustThirdPartySharingResult; +import com.adjust.sdk.ILogger; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Created by uerceg on 22/07/16. + */ +public class AdjustBridgeUtil { + private static final String NATIVE_CALLBACK_NAME = "Adjust._nativeCallback"; + private static final String SET_BRIDGE_TOKEN_CALLBACK_NAME = "Adjust._setBridgeToken"; + + public static void sendDeeplinkToWebView(final WebView webView, final Uri deeplink) { + // If web view is initialised, trigger adjust_deeplink method which user should override. + // In this method, the content of the deeplink will be delivered. + if (webView != null) { + webView.post(new Runnable() { + @Override + public void run() { + String deeplinkValue = deeplink == null ? "null" : JSONObject.quote(deeplink.toString()); + String command = "if (typeof adjust_deeplink === 'function') { adjust_deeplink(" + deeplinkValue + "); }"; + webView.evaluateJavascript(command, null); + } + }); + } + } + + public static String fieldToString(Object field) { + if (field == null) { + return null; + } + + String fieldString = field.toString(); + if (fieldString.equals("null")) { + return null; + } + + return fieldString; + } + + public static Boolean fieldToBoolean(Object field) { + if (field == null) { + return null; + } + + String fieldString = field.toString(); + if (fieldString.equalsIgnoreCase("true")) { + return true; + } + if (fieldString.equalsIgnoreCase("false")) { + return false; + } + + return null; + } + + public static Double fieldToDouble(Object field) { + if (field == null) { + return null; + } + + String fieldString = field.toString(); + try { + return Double.parseDouble(fieldString); + } catch (Exception e) { + return null; + } + } + + public static Long fieldToLong(Object field) { + if (field == null) { + return null; + } + + String fieldString = field.toString(); + try { + return Long.parseLong(fieldString); + } catch (Exception e) { + return null; + } + } + + public static Integer fieldToInteger(Object field) { + if (field == null) { + return null; + } + + String fieldString = field.toString(); + try { + return Integer.parseInt(fieldString); + } catch (Exception e) { + return null; + } + } + + public static void execAdidCallbackCommand(final WebView webView, final String commandName, final String adid) { + execNativeCallback(webView, commandName, adid == null ? "null" : JSONObject.quote(adid)); + } + + public static void execAttributionCallbackCommand(final WebView webView, final String commandName, final AdjustAttribution attribution) { + if (webView == null) { + return; + } + if (commandName == null) { + return; + } + try { + if (attribution != null) { + JSONObject jsonAttribution = new JSONObject(); + jsonAttribution.put("trackerName", attribution.trackerName == null ? JSONObject.NULL : attribution.trackerName); + jsonAttribution.put("trackerToken", attribution.trackerToken == null ? JSONObject.NULL : attribution.trackerToken); + jsonAttribution.put("campaign", attribution.campaign == null ? JSONObject.NULL : attribution.campaign); + jsonAttribution.put("network", attribution.network == null ? JSONObject.NULL : attribution.network); + jsonAttribution.put("creative", attribution.creative == null ? JSONObject.NULL : attribution.creative); + jsonAttribution.put("adgroup", attribution.adgroup == null ? JSONObject.NULL : attribution.adgroup); + jsonAttribution.put("clickLabel", attribution.clickLabel == null ? JSONObject.NULL : attribution.clickLabel); + jsonAttribution.put("costType", attribution.costType == null ? JSONObject.NULL : attribution.costType); + jsonAttribution.put("costAmount", attribution.costAmount == null || attribution.costAmount.isNaN() ? 0 : attribution.costAmount); + jsonAttribution.put("costCurrency", attribution.costCurrency == null ? JSONObject.NULL : attribution.costCurrency); + jsonAttribution.put("fbInstallReferrer", attribution.fbInstallReferrer == null ? JSONObject.NULL : attribution.fbInstallReferrer); + jsonAttribution.put("jsonResponse", attribution.jsonResponse == null ? JSONObject.NULL : new JSONObject(attribution.jsonResponse)); + + execNativeCallback(webView, commandName, jsonAttribution.toString()); + } else { + execNativeCallback(webView, commandName, "null"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execThirdPartySharingSettingsCallbackCommand(final WebView webView, final String commandName, final AdjustThirdPartySharingResult result) { + if (webView == null) { + return; + } + if (commandName == null) { + return; + } + try { + if (result != null) { + JSONObject jsonAdjustThirdPartySharingResult = new JSONObject(); + jsonAdjustThirdPartySharingResult.put("thirdPartySharingSettingsJson", result.getThirdPartySharingSettingsJson() == null ? JSONObject.NULL : result.getThirdPartySharingSettingsJson()); + execNativeCallback(webView, commandName, jsonAdjustThirdPartySharingResult.toString()); + } else { + execNativeCallback(webView, commandName, "null"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execSessionSuccessCallbackCommand(final WebView webView, final String commandName, final AdjustSessionSuccess sessionSuccess) { + if (webView == null) { + return; + } + if (sessionSuccess == null) { + return; + } + JSONObject jsonSessionSuccess = new JSONObject(); + try { + jsonSessionSuccess.put("message", sessionSuccess.message == null ? JSONObject.NULL : sessionSuccess.message); + jsonSessionSuccess.put("adid", sessionSuccess.adid == null ? JSONObject.NULL : sessionSuccess.adid); + jsonSessionSuccess.put("timestamp", sessionSuccess.timestamp == null ? JSONObject.NULL : sessionSuccess.timestamp); + jsonSessionSuccess.put("jsonResponse", sessionSuccess.jsonResponse == null ? JSONObject.NULL : sessionSuccess.jsonResponse); + execNativeCallback(webView, commandName, jsonSessionSuccess.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execSessionFailureCallbackCommand(final WebView webView, final String commandName, final AdjustSessionFailure sessionFailure) { + if (webView == null) { + return; + } + if (sessionFailure == null) { + return; + } + JSONObject jsonSessionFailure = new JSONObject(); + try { + jsonSessionFailure.put("message", sessionFailure.message == null ? JSONObject.NULL : sessionFailure.message); + jsonSessionFailure.put("adid", sessionFailure.adid == null ? JSONObject.NULL : sessionFailure.adid); + jsonSessionFailure.put("timestamp", sessionFailure.timestamp == null ? JSONObject.NULL : sessionFailure.timestamp); + jsonSessionFailure.put("willRetry", sessionFailure.willRetry ? String.valueOf(true) : String.valueOf(false)); + jsonSessionFailure.put("jsonResponse", sessionFailure.jsonResponse == null ? JSONObject.NULL : sessionFailure.jsonResponse); + execNativeCallback(webView, commandName, jsonSessionFailure.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execEventSuccessCallbackCommand(final WebView webView, final String commandName, final AdjustEventSuccess eventSuccess) { + if (webView == null) { + return; + } + if (eventSuccess == null) { + return; + } + JSONObject jsonEventSuccess = new JSONObject(); + try { + jsonEventSuccess.put("eventToken", eventSuccess.eventToken == null ? JSONObject.NULL : eventSuccess.eventToken); + jsonEventSuccess.put("message", eventSuccess.message == null ? JSONObject.NULL : eventSuccess.message); + jsonEventSuccess.put("adid", eventSuccess.adid == null ? JSONObject.NULL : eventSuccess.adid); + jsonEventSuccess.put("timestamp", eventSuccess.timestamp == null ? JSONObject.NULL : eventSuccess.timestamp); + jsonEventSuccess.put("callbackId", eventSuccess.callbackId == null ? JSONObject.NULL : eventSuccess.callbackId); + jsonEventSuccess.put("jsonResponse", eventSuccess.jsonResponse == null ? JSONObject.NULL : eventSuccess.jsonResponse); + execNativeCallback(webView, commandName, jsonEventSuccess.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execEventFailureCallbackCommand(final WebView webView, final String commandName, final AdjustEventFailure eventFailure) { + if (webView == null) { + return; + } + if (eventFailure == null) { + return; + } + JSONObject jsonEventFailure = new JSONObject(); + try { + jsonEventFailure.put("eventToken", eventFailure.eventToken == null ? JSONObject.NULL : eventFailure.eventToken); + jsonEventFailure.put("message", eventFailure.message == null ? JSONObject.NULL : eventFailure.message); + jsonEventFailure.put("adid", eventFailure.adid == null ? JSONObject.NULL : eventFailure.adid); + jsonEventFailure.put("timestamp", eventFailure.timestamp == null ? JSONObject.NULL : eventFailure.timestamp); + jsonEventFailure.put("willRetry", eventFailure.willRetry ? String.valueOf(true) : String.valueOf(false)); + jsonEventFailure.put("callbackId", eventFailure.callbackId == null ? JSONObject.NULL : eventFailure.callbackId); + jsonEventFailure.put("jsonResponse", eventFailure.jsonResponse == null ? JSONObject.NULL : eventFailure.jsonResponse); + execNativeCallback(webView, commandName, jsonEventFailure.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execRemoteTriggerCallbackCommand(final WebView webView, final String commandName, final AdjustRemoteTrigger remoteTrigger) { + if (webView == null) { + return; + } + if (remoteTrigger == null) { + return; + } + + JSONObject jsonRemoteTrigger = new JSONObject(); + try { + jsonRemoteTrigger.put("label", remoteTrigger.getLabel() == null ? JSONObject.NULL : remoteTrigger.getLabel()); + jsonRemoteTrigger.put("payload", remoteTrigger.getPayload() == null ? JSONObject.NULL : remoteTrigger.getPayload()); + + execNativeCallback(webView, commandName, jsonRemoteTrigger.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void execSingleValueCallback(final WebView webView, final String commandName, final String value) { + execNativeCallback(webView, commandName, value == null ? "null" : JSONObject.quote(value)); + } + + public static String[] jsonArrayToArray(JSONArray jsonArray) throws JSONException { + if (jsonArray != null) { + String[] array = new String[jsonArray.length()]; + for (int i = 0; i < jsonArray.length(); i++) { + array[i] = jsonArray.get(i).toString(); + } + return array; + } + return null; + } + + public static ILogger getLogger() { + return AdjustFactory.getLogger(); + } + + public static void sendBridgeTokenToWebView(final WebView webView, final String token) { + if (webView == null) { + return; + } + if (token == null) { + return; + } + + webView.post(new Runnable() { + @Override + public void run() { + String command = "if (window.Adjust && typeof " + SET_BRIDGE_TOKEN_CALLBACK_NAME + " === 'function') { " + + SET_BRIDGE_TOKEN_CALLBACK_NAME + "(" + JSONObject.quote(token) + "); }"; + webView.evaluateJavascript(command, null); + } + }); + } + + private static void execNativeCallback(final WebView webView, final String commandName, final String payload) { + if (webView == null) { + return; + } + if (commandName == null) { + return; + } + + webView.post(new Runnable() { + @Override + public void run() { + String command = "if (window.Adjust && typeof " + NATIVE_CALLBACK_NAME + " === 'function') { " + + NATIVE_CALLBACK_NAME + "(" + JSONObject.quote(commandName) + ", " + payload + "); }"; + webView.evaluateJavascript(command, null); + } + }); + } +} diff --git a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java b/Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java similarity index 100% rename from Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java rename to Adjust/plugins/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/FacebookSDKJSInterface.java diff --git a/Adjust/sdk-plugin-sociomantic/.gitignore b/Adjust/plugins/sdk-plugin-xiaomi-referrer/.gitignore similarity index 100% rename from Adjust/sdk-plugin-sociomantic/.gitignore rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/.gitignore diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/LICENSE b/Adjust/plugins/sdk-plugin-xiaomi-referrer/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Adjust/sdk-plugin-xiaomi-referrer/build.gradle b/Adjust/plugins/sdk-plugin-xiaomi-referrer/build.gradle similarity index 91% rename from Adjust/sdk-plugin-xiaomi-referrer/build.gradle rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/build.gradle index a3e925c03..ea1e4e9b9 100644 --- a/Adjust/sdk-plugin-xiaomi-referrer/build.gradle +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' repositories { maven { - url "https://oss.sonatype.org/content/repositories/staging/" + url "https://central.sonatype.com/repository/maven-snapshots/" } } @@ -21,6 +21,9 @@ android { defaultConfig { minSdkVersion rootProject.ext.coreMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion + aarMetadata { + minCompileSdk = 1 + } } namespace 'com.adjust.sdk.xiaomi' } @@ -31,7 +34,7 @@ dependencies { // Add SDK via module. compileOnly project(':sdk-core') // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' + // implementation 'com.adjust.sdk:adjust-android:5.8.0' // Add xiaomi referrer lib via Maven. implementation 'com.miui.referrer:homereferrer:1.0.0.6' @@ -109,7 +112,12 @@ afterEvaluate { repositories { maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { + println "Using Maven SNAPSHOT repository for publishing" + url "https://central.sonatype.com/repository/maven-snapshots/" + } else { + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" + } if (project.hasProperty("sonatypeUsername")) { credentials { username sonatypeUsername diff --git a/Adjust/test-app-webbridge/proguard-rules.pro b/Adjust/plugins/sdk-plugin-xiaomi-referrer/proguard-rules.pro similarity index 100% rename from Adjust/test-app-webbridge/proguard-rules.pro rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/proguard-rules.pro diff --git a/Adjust/sdk-plugin-xiaomi-referrer/src/main/AndroidManifest.xml b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-xiaomi-referrer/src/main/AndroidManifest.xml rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/AndroidManifest.xml diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java new file mode 100644 index 000000000..81224af71 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java @@ -0,0 +1,59 @@ +package com.adjust.sdk.xiaomi; + +import android.content.Context; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; + +public class AdjustXiaomiReferrer { + + static boolean shouldReadXiaomiReferrer = true; + + public static void readXiaomiReferrer(Context context) { + shouldReadXiaomiReferrer = true; + } + + public static void doNotReadXiaomiReferrer() { + shouldReadXiaomiReferrer = false; + } + + /** + * Read Xiaomi Install Referrer + * @param context Application context + * @param onXiaomiInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getXiaomiInstallReferrer(final Context context, final OnXiaomiInstallReferrerReadListener onXiaomiInstallReferrerReadListener) { + + if (onXiaomiInstallReferrerReadListener == null){ + AdjustFactory.getLogger().error("onXiaomiInstallReferrerReadListener can not be null"); + return; + } + + new AsyncTaskExecutor() { + @Override + protected XiaomiInstallReferrerResult doInBackground(Context[] contexts) { + try { + return XiaomiReferrerClient.getReferrer(context, AdjustFactory.getLogger(),3000); + } catch (Exception exception) { + return new XiaomiInstallReferrerResult(exception.getMessage()); + } + } + + @Override + protected void onPostExecute(XiaomiInstallReferrerResult xiaomiInstallReferrerResult) { + if (xiaomiInstallReferrerResult != null) { + if (xiaomiInstallReferrerResult.xiaomiInstallReferrerDetails != null) { + onXiaomiInstallReferrerReadListener.onXiaomiInstallReferrerRead(xiaomiInstallReferrerResult.xiaomiInstallReferrerDetails); + } else if (xiaomiInstallReferrerResult.error != null) { + onXiaomiInstallReferrerReadListener.onFail(xiaomiInstallReferrerResult.error); + } else { + onXiaomiInstallReferrerReadListener.onFail("XiaomiReferrer getInstallReferrer: xiaomiInstallReferrerDetails is null"); + } + } else { + onXiaomiInstallReferrerReadListener.onFail("XiaomiReferrer getInstallReferrer: xiaomiInstallReferrerResult is null"); + } + } + }.execute(context); + } + +} diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/OnXiaomiInstallReferrerReadListener.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/OnXiaomiInstallReferrerReadListener.java new file mode 100644 index 000000000..4953a9181 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/OnXiaomiInstallReferrerReadListener.java @@ -0,0 +1,7 @@ +package com.adjust.sdk.xiaomi; + +public interface OnXiaomiInstallReferrerReadListener { + + void onXiaomiInstallReferrerRead(XiaomiInstallReferrerDetails referrerDetails); + void onFail(String message); +} diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java new file mode 100644 index 000000000..9c5894cac --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java @@ -0,0 +1,29 @@ +package com.adjust.sdk.xiaomi; + +import android.content.Context; + +import com.adjust.sdk.ILogger; +import com.adjust.sdk.ReferrerDetails; +import com.miui.referrer.api.GetAppsReferrerDetails; + +public class Util { + public synchronized static ReferrerDetails getXiaomiInstallReferrerDetails(Context context, ILogger logger) { + if (!AdjustXiaomiReferrer.shouldReadXiaomiReferrer) { + return null; + } + + logger.info("getXiaomiInstallReferrerDetails invoked"); + + XiaomiInstallReferrerDetails xiaomiInstallReferrerDetails = XiaomiReferrerClient.getReferrer(context, logger, 3000).xiaomiInstallReferrerDetails; + if (xiaomiInstallReferrerDetails == null) { + return null; + } + + return new ReferrerDetails(xiaomiInstallReferrerDetails.installReferrer, + xiaomiInstallReferrerDetails.referrerClickTimestampSeconds, + xiaomiInstallReferrerDetails.installBeginTimestampSeconds, + xiaomiInstallReferrerDetails.referrerClickTimestampServerSeconds, + xiaomiInstallReferrerDetails.installBeginTimestampServerSeconds, + xiaomiInstallReferrerDetails.installVersion, null, null); + } +} diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerDetails.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerDetails.java new file mode 100644 index 000000000..161b838f5 --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerDetails.java @@ -0,0 +1,23 @@ +package com.adjust.sdk.xiaomi; + +import com.miui.referrer.api.GetAppsReferrerDetails; + +public class XiaomiInstallReferrerDetails { + + public String installReferrer; // The referrer URL of the installed package. + public long referrerClickTimestampSeconds; // The client-side timestamp, when the referrer click happened. + public long installBeginTimestampSeconds; // The client-side timestamp, when app installation began. + public long installBeginTimestampServerSeconds; // The server-side timestamp, when app installation began. + public long referrerClickTimestampServerSeconds; // The server-side timestamp, when the referrer click happened. + public String installVersion; // The app's version at the time when the app was first installed. + + public XiaomiInstallReferrerDetails(GetAppsReferrerDetails getAppsReferrerDetails) { + this.installReferrer = getAppsReferrerDetails.getInstallReferrer(); + this.referrerClickTimestampSeconds = getAppsReferrerDetails.getReferrerClickTimestampSeconds(); + this.installBeginTimestampSeconds = getAppsReferrerDetails.getInstallBeginTimestampSeconds(); + this.installBeginTimestampServerSeconds = getAppsReferrerDetails.getInstallBeginTimestampServerSeconds(); + this.referrerClickTimestampServerSeconds = getAppsReferrerDetails.getReferrerClickTimestampServerSeconds(); + this.installVersion = getAppsReferrerDetails.getInstallVersion(); + } + +} diff --git a/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerResult.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerResult.java new file mode 100644 index 000000000..be128d54b --- /dev/null +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiInstallReferrerResult.java @@ -0,0 +1,15 @@ +package com.adjust.sdk.xiaomi; + +public class XiaomiInstallReferrerResult { + + public String error; + public XiaomiInstallReferrerDetails xiaomiInstallReferrerDetails; + + XiaomiInstallReferrerResult(XiaomiInstallReferrerDetails xiaomiInstallReferrerDetails) { + this.xiaomiInstallReferrerDetails = xiaomiInstallReferrerDetails; + } + + public XiaomiInstallReferrerResult(String error) { + this.error = error; + } +} diff --git a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java similarity index 52% rename from Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java index cbdbdfa07..ef5b6a80f 100644 --- a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java +++ b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/XiaomiReferrerClient.java @@ -14,10 +14,10 @@ public class XiaomiReferrerClient { - public static GetAppsReferrerDetails getReferrer(Context context, final ILogger logger, long maxWaitTimeInMilli) { + public static XiaomiInstallReferrerResult getReferrer(Context context, final ILogger logger, long maxWaitTimeInMilli) { try { final GetAppsReferrerClient referrerClient = new GetAppsReferrerClient.Builder(context).build(); - final BlockingQueue referrerDetailsHolder = new LinkedBlockingQueue(1); + final BlockingQueue referrerDetailsHolder = new LinkedBlockingQueue(1); referrerClient.startConnection(new GetAppsReferrerStateListener() { @Override public void onGetAppsReferrerSetupFinished(int responseCode) { @@ -25,21 +25,29 @@ public void onGetAppsReferrerSetupFinished(int responseCode) { switch (responseCode) { case GetAppsReferrerResponse.OK: try { - GetAppsReferrerDetails getAppsReferrerDetails = referrerClient.getInstallReferrer(); - referrerDetailsHolder.offer(getAppsReferrerDetails); + XiaomiInstallReferrerDetails xiaomiInstallReferrerDetails = new XiaomiInstallReferrerDetails(referrerClient.getInstallReferrer()); + referrerDetailsHolder.offer(new XiaomiInstallReferrerResult(xiaomiInstallReferrerDetails)); } catch (Exception e) { - logger.error("XiaomiReferrer getInstallReferrer: " + e.getMessage()); + String message = "XiaomiReferrer getInstallReferrer: " + e.getMessage(); + logger.error(message); + referrerDetailsHolder.offer(new XiaomiInstallReferrerResult(message)); } break; case GetAppsReferrerResponse.FEATURE_NOT_SUPPORTED: - logger.info("XiaomiReferrer onGetAppsReferrerSetupFinished: FEATURE_NOT_SUPPORTED"); + String message = "XiaomiReferrer onGetAppsReferrerSetupFinished: FEATURE_NOT_SUPPORTED"; + logger.info(message); + referrerDetailsHolder.offer(new XiaomiInstallReferrerResult(message)); break; case GetAppsReferrerResponse.SERVICE_UNAVAILABLE: - logger.info("XiaomiReferrer onGetAppsReferrerSetupFinished: SERVICE_UNAVAILABLE"); + String message1 = "XiaomiReferrer onGetAppsReferrerSetupFinished: SERVICE_UNAVAILABLE"; + logger.info(message1); + referrerDetailsHolder.offer(new XiaomiInstallReferrerResult(message1)); break; } } catch (Exception e) { - logger.error("XiaomiReferrer onGetAppsReferrerSetupFinished: " + e.getMessage()); + String message = "XiaomiReferrer onGetAppsReferrerSetupFinished: " + e.getMessage(); + logger.error(message); + referrerDetailsHolder.offer(new XiaomiInstallReferrerResult(message)); } } @@ -52,8 +60,7 @@ public void onGetAppsServiceDisconnected() { } catch (Exception e) { logger.error("Exception while getting referrer: ", e.getMessage()); + return new XiaomiInstallReferrerResult(e.getMessage()); } - - return null; } } diff --git a/Adjust/sdk-plugin-xiaomi-referrer/src/main/res/values/strings.xml b/Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/res/values/strings.xml similarity index 100% rename from Adjust/sdk-plugin-xiaomi-referrer/src/main/res/values/strings.xml rename to Adjust/plugins/sdk-plugin-xiaomi-referrer/src/main/res/values/strings.xml diff --git a/Adjust/sdk-core/adjust-proguard-rules.txt b/Adjust/sdk-core/adjust-proguard-rules.txt index 7c3195e28..3ddc462cb 100644 --- a/Adjust/sdk-core/adjust-proguard-rules.txt +++ b/Adjust/sdk-core/adjust-proguard-rules.txt @@ -25,4 +25,17 @@ -keep class android.os.LocaleList { java.util.Locale get(int); } --keep public class com.android.installreferrer.** { *; } \ No newline at end of file +-keep public class com.android.installreferrer.** { *; } +-keep class com.google.android.gms.appset.AppSet { + com.google.android.gms.appset.AppSetIdClient getClient(android.content.Context); +} +-keep class com.google.android.gms.appset.AppSetIdClient { + com.google.android.gms.tasks.Task getAppSetIdInfo(); +} +-keep class com.google.android.gms.appset.AppSetIdInfo { + java.lang.String getId(); +} +-keep class com.google.android.gms.tasks.Task +-keep class com.google.android.gms.tasks.Tasks { + java.lang.Object await(com.google.android.gms.tasks.Task, long, java.util.concurrent.TimeUnit); +} diff --git a/Adjust/sdk-core/build.gradle b/Adjust/sdk-core/build.gradle index 8bbfac067..ce3bea010 100644 --- a/Adjust/sdk-core/build.gradle +++ b/Adjust/sdk-core/build.gradle @@ -16,6 +16,9 @@ android { minSdkVersion rootProject.ext.coreMinSdkVersion targetSdkVersion rootProject.ext.coreTargetSdkVersion consumerProguardFiles 'adjust-proguard-rules.txt' + aarMetadata { + minCompileSdk = 1 + } } buildTypes { @@ -41,6 +44,16 @@ if (localPropsFile.exists()) { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + /* + * according to https://developer.android.com/studio/write/annotations + * If you use annotations in your own library module, + * the annotations are included as part of the Android Archive (AAR) artifact + * in XML format in the annotations.zip file. + * Adding the androidx.annotation dependency doesn't introduce a dependency + * for any downstream users of your library. + */ + implementation 'androidx.annotation:annotation:1.8.0' + testImplementation 'junit:junit:4.13.2' } task adjustCoreAarRelease(type: Copy) { @@ -115,9 +128,9 @@ afterEvaluate { maven { if (rootProject.ext.coreVersionName.toString().contains('SNAPSHOT')) { println "Using Maven SNAPSHOT repository for publishing" - url "https://oss.sonatype.org/content/repositories/snapshots/" + url "https://central.sonatype.com/repository/maven-snapshots/" } else { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" + url "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2" } if (project.hasProperty("sonatypeUsername")) { credentials { @@ -207,6 +220,14 @@ def customizePomForAar(pom) { email 'ugljesa@adjust.com' } } + dependencies { + dependency { + groupId 'com.adjust.signature' + artifactId 'adjust-android-signature' + version '5.0.0' + scope 'compile' + } + } } } } diff --git a/Adjust/sdk-core/proguard-rules.pro b/Adjust/sdk-core/proguard-rules.pro index 85e1fa3e3..7498b73ed 100644 --- a/Adjust/sdk-core/proguard-rules.pro +++ b/Adjust/sdk-core/proguard-rules.pro @@ -16,7 +16,7 @@ # public *; #} -keep public class com.adjust.sdk.** { *; } --keep class com.adjust.sdk.DeviceInfo** +-keep class com.adjust.sdk.** -keepclassmembers class com.adjust.sdk.DeviceInfo** {*;} -keep class com.google.android.gms.common.ConnectionResult { int SUCCESS; @@ -29,3 +29,16 @@ boolean isLimitAdTrackingEnabled(); } -keep public class com.android.installreferrer.** { *; } +-keep class com.google.android.gms.appset.AppSet { + com.google.android.gms.appset.AppSetIdClient getClient(android.content.Context); +} +-keep class com.google.android.gms.appset.AppSetIdClient { + com.google.android.gms.tasks.Task getAppSetIdInfo(); +} +-keep class com.google.android.gms.appset.AppSetIdInfo { + java.lang.String getId(); +} +-keep class com.google.android.gms.tasks.Task +-keep class com.google.android.gms.tasks.Tasks { + java.lang.Object await(com.google.android.gms.tasks.Task, long, java.util.concurrent.TimeUnit); +} diff --git a/Adjust/sdk-core/src/main/AndroidManifest.xml b/Adjust/sdk-core/src/main/AndroidManifest.xml index e269d3838..648a2271d 100644 --- a/Adjust/sdk-core/src/main/AndroidManifest.xml +++ b/Adjust/sdk-core/src/main/AndroidManifest.xml @@ -2,10 +2,10 @@ - - - - - - + + + diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java index 79ba99be8..3dddd7518 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityHandler.java @@ -9,6 +9,23 @@ package com.adjust.sdk; +import static com.adjust.sdk.Constants.ACTIVITY_STATE_FILENAME; +import static com.adjust.sdk.Constants.ADID_TIMEOUT_TIMER_NAME; +import static com.adjust.sdk.Constants.ATTRIBUTION_FILENAME; +import static com.adjust.sdk.Constants.ATTRIBUTION_TIMEOUT_TIMER_NAME; +import static com.adjust.sdk.Constants.CONNECTION_TIMEOUT; +import static com.adjust.sdk.Constants.CONNECTION_TIMEOUT_VERIFY; +import static com.adjust.sdk.Constants.EVENT_METADATA_FILENAME; +import static com.adjust.sdk.Constants.GLOBAL_CALLBACK_PARAMETERS_FILENAME; +import static com.adjust.sdk.Constants.GLOBAL_PARTNER_PARAMETERS_FILENAME; +import static com.adjust.sdk.Constants.REFERRER_API_HUAWEI_ADS; +import static com.adjust.sdk.Constants.REFERRER_API_HUAWEI_APP_GALLERY; +import static com.adjust.sdk.Constants.REFERRER_API_META; +import static com.adjust.sdk.Constants.REFERRER_API_SAMSUNG; +import static com.adjust.sdk.Constants.REFERRER_API_VIVO; +import static com.adjust.sdk.Constants.REFERRER_API_XIAOMI; +import static com.adjust.sdk.Constants.TPS_SETTINGS_TIMEOUT_TIMER_NAME; + import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -18,6 +35,9 @@ import android.os.Handler; import android.text.TextUtils; +import androidx.annotation.NonNull; + +import com.adjust.sdk.SystemLifecycle.SystemLifecycleCallback; import com.adjust.sdk.network.ActivityPackageSender; import com.adjust.sdk.network.IActivityPackageSender; import com.adjust.sdk.network.UtilNetworking; @@ -26,6 +46,7 @@ import com.adjust.sdk.scheduler.TimerCycle; import com.adjust.sdk.scheduler.TimerOnce; +import org.json.JSONArray; import org.json.JSONObject; import java.io.InputStream; @@ -35,16 +56,9 @@ import java.util.Map; import java.util.Properties; -import static com.adjust.sdk.Constants.ACTIVITY_STATE_FILENAME; -import static com.adjust.sdk.Constants.ATTRIBUTION_FILENAME; -import static com.adjust.sdk.Constants.REFERRER_API_META; -import static com.adjust.sdk.Constants.REFERRER_API_SAMSUNG; -import static com.adjust.sdk.Constants.REFERRER_API_VIVO; -import static com.adjust.sdk.Constants.REFERRER_API_XIAOMI; -import static com.adjust.sdk.Constants.SESSION_CALLBACK_PARAMETERS_FILENAME; -import static com.adjust.sdk.Constants.SESSION_PARTNER_PARAMETERS_FILENAME; - -public class ActivityHandler implements IActivityHandler { +public class ActivityHandler + implements IActivityHandler, SystemLifecycleCallback +{ private static long FOREGROUND_TIMER_INTERVAL; private static long FOREGROUND_TIMER_START; private static long BACKGROUND_TIMER_INTERVAL; @@ -56,17 +70,17 @@ public class ActivityHandler implements IActivityHandler { private static final String FOREGROUND_TIMER_NAME = "Foreground timer"; private static final String BACKGROUND_TIMER_NAME = "Background timer"; private static final String DELAY_START_TIMER_NAME = "Delay Start timer"; - private static final String SESSION_CALLBACK_PARAMETERS_NAME = "Session Callback parameters"; - private static final String SESSION_PARTNER_PARAMETERS_NAME = "Session Partner parameters"; - private static final String SESSION_PARAMETERS_NAME = "Session parameters"; + private static final String GLOBAL_CALLBACK_PARAMETERS_NAME = "Global Callback parameters"; + private static final String GLOBAL_PARTNER_PARAMETERS_NAME = "Global Partner parameters"; + private static final String GLOBAL_PARAMETERS_NAME = "Global parameters"; + private static final String EVENT_METADATA_NAME = "Event metadata"; - private ThreadExecutor executor; + ThreadExecutor executor; private IPackageHandler packageHandler; private ActivityState activityState; private ILogger logger; private TimerCycle foregroundTimer; private TimerOnce backgroundTimer; - private TimerOnce delayStartTimer; private InternalState internalState; private String basePath; private String gdprPath; @@ -75,14 +89,23 @@ public class ActivityHandler implements IActivityHandler { private DeviceInfo deviceInfo; private AdjustConfig adjustConfig; // always valid after construction private AdjustAttribution attribution; + private AdjustThirdPartySharingResult thirdPartySharingResult; private IAttributionHandler attributionHandler; private ISdkClickHandler sdkClickHandler; private IPurchaseVerificationHandler purchaseVerificationHandler; - private SessionParameters sessionParameters; + private GlobalParameters globalParameters; private InstallReferrer installReferrer; - private InstallReferrerHuawei installReferrerHuawei; - private InstallReferrerMeta installReferrerMeta; private OnDeeplinkResolvedListener cachedDeeplinkResolutionCallback; + private final ArrayList cachedAdidReadCallbacks = new ArrayList<>(); + private final ArrayList cachedAdidReadTimeoutCallbacks = new ArrayList<>(); + private SystemLifecycle systemLifecycle; + private final ArrayList cachedAttributionReadCallbacks = new ArrayList<>(); + private final ArrayList cachedAttributionReadTimeoutCallbacks = new ArrayList<>(); + private List cachedAdjustThirdPartySharingArray; + private final ArrayList cachedThirdPartySharingTimeoutCallbacks = new ArrayList<>(); + private Boolean cachedLastMeasurementConsentTrack; + private FirstSessionDelayManager firstSessionDelayManager; + private @NonNull EventMetadata eventMetadata = new EventMetadata(); @Override public void teardown() { @@ -92,9 +115,6 @@ public void teardown() { if (foregroundTimer != null) { foregroundTimer.teardown(); } - if (delayStartTimer != null) { - delayStartTimer.teardown(); - } if (executor != null) { executor.teardown(); } @@ -110,39 +130,40 @@ public void teardown() { if (purchaseVerificationHandler != null) { purchaseVerificationHandler.teardown(); } - if (sessionParameters != null) { - if (sessionParameters.callbackParameters != null) { - sessionParameters.callbackParameters.clear(); + if (globalParameters != null) { + if (globalParameters.callbackParameters != null) { + globalParameters.callbackParameters.clear(); } - if (sessionParameters.partnerParameters != null) { - sessionParameters.partnerParameters.clear(); + if (globalParameters.partnerParameters != null) { + globalParameters.partnerParameters.clear(); } } teardownActivityStateS(); teardownAttributionS(); - teardownAllSessionParametersS(); + teardownAllGlobalParametersS(); + teardownEventMetadataS(); packageHandler = null; logger = null; foregroundTimer = null; executor = null; backgroundTimer = null; - delayStartTimer = null; internalState = null; deviceInfo = null; adjustConfig = null; attributionHandler = null; sdkClickHandler = null; purchaseVerificationHandler = null; - sessionParameters = null; + globalParameters = null; } static void deleteState(Context context) { deleteActivityState(context); deleteAttribution(context); - deleteSessionCallbackParameters(context); - deleteSessionPartnerParameters(context); + deleteGlobalCallbackParameters(context); + deleteGlobalPartnerParameters(context); + deleteEventMetadata(context); SharedPreferencesManager.getDefaultInstance(context).clear(); } @@ -150,13 +171,10 @@ static void deleteState(Context context) { public class InternalState { boolean enabled; boolean offline; - boolean background; - boolean delayStart; - boolean updatePackages; boolean firstLaunch; boolean sessionResponseProcessed; - boolean firstSdkStart; boolean preinstallHasBeenRead; + Boolean foregroundOrElseBackground; public boolean isEnabled() { return enabled; @@ -175,49 +193,57 @@ public boolean isOnline() { } public boolean isInBackground() { - return background; + return foregroundOrElseBackground != null + && ! foregroundOrElseBackground.booleanValue(); } public boolean isInForeground() { - return !background; - } - - public boolean isInDelayedStart() { - return delayStart; - } - - public boolean isNotInDelayedStart() { - return !delayStart; - } - - public boolean itHasToUpdatePackages() { - return updatePackages; + return foregroundOrElseBackground != null + && foregroundOrElseBackground.booleanValue(); } public boolean isFirstLaunch() { return firstLaunch; } - public boolean isNotFirstLaunch() { - return !firstLaunch; - } - public boolean hasSessionResponseNotBeenProcessed() { return !sessionResponseProcessed; } - public boolean hasFirstSdkStartOcurred() { - return firstSdkStart; + public boolean hasPreinstallBeenRead() { + return preinstallHasBeenRead; } + } - public boolean hasFirstSdkStartNotOcurred() { - return !firstSdkStart; - } + // region SystemLifecycleCallback + @Override public void onActivityLifecycle(final boolean foregroundOrElseBackground) { + try { + executor.submit(() -> { + firstSessionDelayManager.apiActionI("activity state", () -> { + if (internalState.foregroundOrElseBackground != null + && internalState.foregroundOrElseBackground.booleanValue() + == foregroundOrElseBackground) { + return; + } + // received foregroundOrElseBackground is strictly different from internal state one - public boolean hasPreinstallBeenRead() { - return preinstallHasBeenRead; + this.internalState.foregroundOrElseBackground = foregroundOrElseBackground; + + if (foregroundOrElseBackground) { + onResumeI(); + } else { + onPauseI(); + } + + }); + }); + } catch (Exception e) { + if (logger != null) { + logger.error("Exception while executing onActivityLifecycle task"); + } } } + // endregion private ActivityHandler(AdjustConfig adjustConfig) { init(adjustConfig); @@ -234,25 +260,26 @@ private ActivityHandler(AdjustConfig adjustConfig) { internalState.enabled = adjustConfig.startEnabled != null ? adjustConfig.startEnabled : true; // online by default internalState.offline = adjustConfig.startOffline; - // in the background by default - internalState.background = true; - // delay start not configured by default - internalState.delayStart = false; - // does not need to update packages by default - internalState.updatePackages = false; // does not have the session response by default internalState.sessionResponseProcessed = false; - // does not have first start by default - internalState.firstSdkStart = false; // preinstall has not been read by default internalState.preinstallHasBeenRead = false; - executor.submit(new Runnable() { - @Override - public void run() { - initI(); - } + cachedAdjustThirdPartySharingArray = null; + cachedLastMeasurementConsentTrack = null; + + firstSessionDelayManager = new FirstSessionDelayManager(this); + + executor.submit(() -> { + // has to be read in the background + readAttributionI(adjustConfig.context); + readThirdPartySharingResultI(adjustConfig.context); + readActivityStateI(adjustConfig.context); + readEventMetadataI(adjustConfig.context); + firstSessionDelayManager.activityStateFileReadI(); }); + + //firstSessionDelayManager.delayOrInit(() -> initI()); } @Override @@ -271,8 +298,13 @@ public ActivityState getActivityState() { } @Override - public SessionParameters getSessionParameters() { - return sessionParameters; + public GlobalParameters getGlobalParameters() { + return globalParameters; + } + + @Override + public FirstSessionDelayManager getFirstSessionDelayManager() { + return firstSessionDelayManager; } @Override @@ -321,60 +353,50 @@ public static ActivityHandler getInstance(AdjustConfig adjustConfig) { @Override public void onResume() { - internalState.background = false; - - executor.submit(new Runnable() { - @Override - public void run() { - delayStartI(); - - stopBackgroundTimerI(); + onActivityLifecycle(true); + } + public void onResumeI() { + stopBackgroundTimerI(); - startForegroundTimerI(); + startForegroundTimerI(); - logger.verbose("Subsession start"); + logger.verbose("Subsession start"); - startI(); - } - }); + startI(); } @Override public void onPause() { - internalState.background = true; - - executor.submit(new Runnable() { - @Override - public void run() { - stopForegroundTimerI(); + onActivityLifecycle(false); + } + public void onPauseI() { + stopForegroundTimerI(); - startBackgroundTimerI(); + startBackgroundTimerI(); - logger.verbose("Subsession end"); + logger.verbose("Subsession end"); - endI(); - } - }); + endI(); } @Override public void trackEvent(final AdjustEvent event) { - executor.submit(new Runnable() { - @Override - public void run() { - if (internalState.hasFirstSdkStartNotOcurred()) { - logger.warn("Event tracked before first activity resumed.\n" + - "If it was triggered in the Application class, it might timestamp or even send an install long before the user opens the app.\n" + - "Please check https://github.com/adjust/android_sdk#can-i-trigger-an-event-at-application-launch for more information."); - startI(); - } - trackEventI(event); + executor.submit(() -> firstSessionDelayManager.apiActionI("track event", () -> { + if (activityState == null) { + logger.warn("Event tracked before first activity resumed.\n" + + "If it was triggered in the Application class, it might timestamp or even send an install long before the user opens the app.\n" + + "Please check https://github.com/adjust/android_sdk#can-i-trigger-an-event-at-application-launch for more information."); + startI(); } - }); + trackEventI(event); + })); } @Override public void finishedTrackingActivity(ResponseData responseData) { + // process remote triggers from any response + processRemoteTriggers(responseData); + // redirect session responses to attribution handler to check for attribution information if (responseData instanceof SessionResponseData) { logger.debug("Finished tracking session"); @@ -396,26 +418,25 @@ public void finishedTrackingActivity(ResponseData responseData) { if (responseData instanceof PurchaseVerificationResponseData) { launchPurchaseVerificationResponseTasks((PurchaseVerificationResponseData)responseData); } + + // check if it's a third party sharing response + if (responseData instanceof ThirdPartySharingResponseData) { + launchThirdPartySharingResponseTasks((ThirdPartySharingResponseData)responseData); + } } @Override public void setEnabled(final boolean enabled) { - executor.submit(new Runnable() { - @Override - public void run() { - setEnabledI(enabled); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + (enabled ? "enable" : "disable"), + () -> setEnabledI(enabled))); } @Override public void setOfflineMode(final boolean offline) { - executor.submit(new Runnable() { - @Override - public void run() { - setOfflineModeI(offline); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + (offline ? "put SDK in offline mode" : "put SDK back to online mode"), + () -> setOfflineModeI(offline))); } @Override @@ -423,6 +444,14 @@ public boolean isEnabled() { return isEnabledI(); } + @Override + public void isEnabled(final OnIsEnabledListener onIsEnabledListener) { + executor.submit(() -> firstSessionDelayManager.apiActionI( + "is SDK enabled", + () -> new Handler(adjustConfig.context.getMainLooper()).post( + () -> onIsEnabledListener.onIsEnabledRead(isEnabledI())))); + } + private boolean isEnabledI() { if (activityState != null) { return activityState.enabled; @@ -432,23 +461,21 @@ private boolean isEnabledI() { } @Override - public void readOpenUrl(final Uri url, final long clickTime) { - executor.submit(new Runnable() { - @Override - public void run() { - readOpenUrlI(url, clickTime); - } - }); + public void processDeeplink(final AdjustDeeplink deeplink, final long clickTime) { + executor.submit(() -> firstSessionDelayManager.apiActionI( + "process deep link", + () -> processDeeplinkI(deeplink, clickTime))); } - public void readOpenUrl(final Uri url, final long clickTime, final OnDeeplinkResolvedListener callback) { + @Override + public void processAndResolveDeeplink(final AdjustDeeplink deeplink, + final long clickTime, + final OnDeeplinkResolvedListener callback) + { this.cachedDeeplinkResolutionCallback = callback; - executor.submit(new Runnable() { - @Override - public void run() { - readOpenUrlI(url, clickTime); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + "process and resolve deep link", + () -> processDeeplinkI(deeplink, clickTime))); } private void updateAdidI(final String adid) { @@ -456,13 +483,68 @@ private void updateAdidI(final String adid) { return; } - if (adid.equals(activityState.adid)) { - return; + if (!adid.equals(activityState.adid)) { + activityState.adid = adid; + writeActivityStateI(); } - activityState.adid = adid; - writeActivityStateI(); - return; + ArrayList cachedAdidReadCallbacksCopy = null; + synchronized (cachedAdidReadCallbacks) { + if (!cachedAdidReadCallbacks.isEmpty()) { + cachedAdidReadCallbacksCopy = new ArrayList<>(cachedAdidReadCallbacks); + cachedAdidReadCallbacks.clear(); + } + } + + // process regular adid callbacks + if (cachedAdidReadCallbacksCopy != null) { + ArrayList finalCachedAdidReadCallbacksCopy = cachedAdidReadCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (OnAdidReadListener onAdidReadListener : finalCachedAdidReadCallbacksCopy) { + if (onAdidReadListener != null) { + onAdidReadListener.onAdidRead(adid); + } + } + } + }); + } + + ArrayList cachedAdidReadTimeoutCallbacksCopy = null; + synchronized (cachedAdidReadTimeoutCallbacks) { + if (!cachedAdidReadTimeoutCallbacks.isEmpty()) { + cachedAdidReadTimeoutCallbacksCopy = new ArrayList<>(cachedAdidReadTimeoutCallbacks); + cachedAdidReadTimeoutCallbacks.clear(); + } + } + + // process timeout adid callbacks + if (cachedAdidReadTimeoutCallbacksCopy != null) { + ArrayList finalCachedAdidReadTimeoutCallbacksCopy = cachedAdidReadTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedAdidReadTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + + OnAdidReadListener onAdidReadListener = adjustTimeoutCallback.getOnAdidReadListener(); + if (onAdidReadListener != null) { + onAdidReadListener.onAdidRead(adid); + } + + // null callback to call it only once + adjustTimeoutCallback.setOnAdidReadListener(null); + } + } + } + }); + } } @Override @@ -471,20 +553,129 @@ public boolean updateAttributionI(AdjustAttribution attribution) { return false; } - if (adjustConfig.finalAttributionEnabled && activityState.askingAttribution) { - logger.info("Not updating intermediate attribution"); + if (activityState.askingAttribution) { return false; } + ArrayList cachedAttributionReadCallbacksCopy = null; + synchronized (cachedAttributionReadCallbacks) { + if (! cachedAttributionReadCallbacks.isEmpty()) { + cachedAttributionReadCallbacksCopy = new ArrayList<>(cachedAttributionReadCallbacks); + cachedAttributionReadCallbacks.clear(); + } + } + + // process regular attribution callbacks + if (cachedAttributionReadCallbacksCopy != null) { + ArrayList finalCachedAttributionReadCallbacksCopy = cachedAttributionReadCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (OnAttributionReadListener onAttributionReadListener : finalCachedAttributionReadCallbacksCopy) { + if (onAttributionReadListener != null) { + onAttributionReadListener.onAttributionRead(attribution); + } + } + } + }); + } + + ArrayList cachedAttributionReadTimeoutCallbacksCopy = null; + synchronized (cachedAttributionReadTimeoutCallbacks) { + if (! cachedAttributionReadTimeoutCallbacks.isEmpty()) { + cachedAttributionReadTimeoutCallbacksCopy = new ArrayList<>(cachedAttributionReadTimeoutCallbacks); + cachedAttributionReadTimeoutCallbacks.clear(); + } + } + + // process timeout attribution callbacks + if (cachedAttributionReadTimeoutCallbacksCopy != null) { + ArrayList finalCachedAttributionReadTimeoutCallbacksCopy = cachedAttributionReadTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedAttributionReadTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + OnAttributionReadListener onAttributionReadListener = adjustTimeoutCallback.getOnAttributionReadListener(); + if (onAttributionReadListener != null) { + onAttributionReadListener.onAttributionRead(attribution); + } + // null callback to call it only once + adjustTimeoutCallback.setOnAttributionReadListener(null); + } + } + } + }); + } + if (attribution.equals(this.attribution)) { return false; } this.attribution = attribution; writeAttributionI(); + return true; } + private boolean updateThirdPartySharingSettingsI(final AdjustThirdPartySharingResult thirdPartySharingResult) { + if (thirdPartySharingResult == null) { + return false; + } + + boolean thirdPartySharingSettingsChanged = !thirdPartySharingResult.equals(this.thirdPartySharingResult); + this.thirdPartySharingResult = thirdPartySharingResult; + + if (thirdPartySharingSettingsChanged) { + final SharedPreferencesManager sharedPreferencesManager = + SharedPreferencesManager.getDefaultInstance(getContext()); + sharedPreferencesManager.saveThirdPartySharingResult(this.thirdPartySharingResult); + } + + ArrayList cachedThirdPartySharingTimeoutCallbacksCopy = null; + synchronized (cachedThirdPartySharingTimeoutCallbacks) { + if (!cachedThirdPartySharingTimeoutCallbacks.isEmpty()) { + cachedThirdPartySharingTimeoutCallbacksCopy = new ArrayList<>(cachedThirdPartySharingTimeoutCallbacks); + cachedThirdPartySharingTimeoutCallbacks.clear(); + } + } + + // process third party sharing callbacks + if (cachedThirdPartySharingTimeoutCallbacksCopy != null) { + final AdjustThirdPartySharingResult thirdPartySharingResultCopy = this.thirdPartySharingResult; + ArrayList finalCachedThirdPartySharingTimeoutCallbacksCopy = cachedThirdPartySharingTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedThirdPartySharingTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + + OnThirdPartySharingSettingsReadListener listener = adjustTimeoutCallback.getOnThirdPartySharingSettingsReadListener(); + if (listener != null) { + listener.onThirdPartySharingSettingsRead(thirdPartySharingResultCopy); + } + + // null callback to call it only once + adjustTimeoutCallback.setOnThirdPartySharingSettingsReadListener(null); + } + } + } + }); + } + + return thirdPartySharingSettingsChanged; + } + @Override public void setAskingAttribution(final boolean askingAttribution) { executor.submit(new Runnable() { @@ -497,35 +688,40 @@ public void run() { @Override public void sendReftagReferrer() { - executor.submit(new Runnable() { - @Override - public void run() { - sendReftagReferrerI(); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + "send referrer", + () -> sendReftagReferrerI())); } @Override public void sendPreinstallReferrer() { + executor.submit(() -> firstSessionDelayManager.apiActionI( + "send preinstall referrer", + () -> sendPreinstallReferrerI())); + } + + @Override + public void sendInstallReferrer(final ReferrerDetails referrerDetails, + final String referrerApi) { executor.submit(new Runnable() { @Override public void run() { - sendPreinstallReferrerI(); + sendInstallReferrerI(referrerDetails, referrerApi); } }); } @Override - public void sendInstallReferrer(final ReferrerDetails referrerDetails, - final String referrerApi) { + public void sendLicenseVerificationData(final LicenseData licenseVerificationData) { executor.submit(new Runnable() { @Override public void run() { - sendInstallReferrerI(referrerDetails, referrerApi); + sendLicenseVerificationDataI(licenseVerificationData); } }); } + @Override public void launchEventResponseTasks(final EventResponseData eventResponseData) { executor.submit(new Runnable() { @@ -576,164 +772,128 @@ public void run() { }); } - @Override - public void sendFirstPackages () { + private void launchThirdPartySharingResponseTasks(final ThirdPartySharingResponseData thirdPartySharingResponseData) { executor.submit(new Runnable() { @Override public void run() { - sendFirstPackagesI(); + launchThirdPartySharingResponseTasksI(thirdPartySharingResponseData); } }); } @Override - public void addSessionCallbackParameter(final String key, final String value) { + public void processRemoteTriggers(ResponseData responseData) { executor.submit(new Runnable() { @Override public void run() { - addSessionCallbackParameterI(key, value); + processRemoteTriggersI(responseData); } }); } @Override - public void addSessionPartnerParameter(final String key, final String value) { - executor.submit(new Runnable() { - @Override - public void run() { - addSessionPartnerParameterI(key, value); - } - }); + public void addGlobalCallbackParameter(final String key, final String value) { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "add global callback parameter", + activityHandler -> + activityHandler.addGlobalCallbackParameterI(key, value))); } @Override - public void removeSessionCallbackParameter(final String key) { - executor.submit(new Runnable() { - @Override - public void run() { - removeSessionCallbackParameterI(key); - } - }); + public void addGlobalPartnerParameter(final String key, final String value) { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "add global partner parameter", + activityHandler -> + activityHandler.addGlobalPartnerParameterI(key, value))); } @Override - public void removeSessionPartnerParameter(final String key) { - executor.submit(new Runnable() { - @Override - public void run() { - removeSessionPartnerParameterI(key); - } - }); + public void removeGlobalCallbackParameter(final String key) { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "remove global callback parameter", + activityHandler -> + activityHandler.removeGlobalCallbackParameterI(key))); } @Override - public void resetSessionCallbackParameters() { - executor.submit(new Runnable() { - @Override - public void run() { - resetSessionCallbackParametersI(); - } - }); + public void removeGlobalPartnerParameter(final String key) { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "remove global partner parameter", + activityHandler -> + activityHandler.removeGlobalPartnerParameterI(key))); } @Override - public void resetSessionPartnerParameters() { - executor.submit(new Runnable() { - @Override - public void run() { - resetSessionPartnerParametersI(); - } - }); + public void removeGlobalCallbackParameters() { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "remove global callback parameters", + activityHandler -> + activityHandler.removeGlobalCallbackParametersI())); + } + + @Override + public void removeGlobalPartnerParameters() { + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "remove global partner parameters", + activityHandler -> + activityHandler.removeGlobalPartnerParametersI())); } @Override public void setPushToken(final String token, final boolean preSaved) { - executor.submit(new Runnable() { - @Override - public void run() { - if (!preSaved) { - SharedPreferencesManager.getDefaultInstance(getContext()).savePushToken(token); - } + executor.submit(() -> firstSessionDelayManager.apiActionI( + "set push token", + () -> { + if (!preSaved) { + SharedPreferencesManager.getDefaultInstance(getContext()).savePushToken(token); + } - if (internalState.hasFirstSdkStartNotOcurred()) { - // No install has been tracked so far. - // Push token is saved, ready for the session package to pick it up. - return; - } else { - setPushTokenI(token); + if (activityState == null) { + // No install has been tracked so far. + // Push token is saved, ready for the session package to pick it up. + return; + } else { + setPushTokenI(token); + } } - } - }); + )); } @Override public void gdprForgetMe() { - executor.submit(new Runnable() { - @Override - public void run() { - gdprForgetMeI(); - } - }); - } - - @Override - public void disableThirdPartySharing() { - executor.submit(new Runnable() { - @Override - public void run() { - disableThirdPartySharingI(); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + "GDPR forget device", + () -> gdprForgetMeI())); } @Override public void trackThirdPartySharing(final AdjustThirdPartySharing adjustThirdPartySharing) { - executor.submit(new Runnable() { - @Override - public void run() { - trackThirdPartySharingI(adjustThirdPartySharing); - } - }); + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "track third party sharing", + activityHandler -> + activityHandler.tryTrackThirdPartySharingI(adjustThirdPartySharing))); } @Override public void trackMeasurementConsent(final boolean consentMeasurement) { - executor.submit(new Runnable() { - @Override - public void run() { - trackMeasurementConsentI(consentMeasurement); - } - }); - } - - @Override - public void trackAdRevenue(final String source, final JSONObject adRevenueJson) { - executor.submit(new Runnable() { - @Override - public void run() { - trackAdRevenueI(source, adRevenueJson); - } - }); + executor.submit(() -> firstSessionDelayManager.preLaunchActionI( + "track measurement consent", + activityHandler -> + activityHandler.tryTrackMeasurementConsentI(consentMeasurement))); } @Override public void trackAdRevenue(final AdjustAdRevenue adjustAdRevenue) { - executor.submit(new Runnable() { - @Override - public void run() { - trackAdRevenueI(adjustAdRevenue); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + "track ad revenue", + () -> trackAdRevenueI(adjustAdRevenue))); } @Override public void trackPlayStoreSubscription(final AdjustPlayStoreSubscription subscription) { - executor.submit(new Runnable() { - @Override - public void run() { - trackSubscriptionI(subscription); - } - }); + executor.submit(() -> firstSessionDelayManager.apiActionI( + "track play store subscription", + () -> trackPlayStoreSubscriptionI(subscription))); } @Override @@ -770,33 +930,258 @@ public void run() { } @Override - public String getAdid() { - if (activityState == null) { - return null; + public void getAdid(OnAdidReadListener callback) { + if (activityState != null && activityState.adid != null) { + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callback.onAdidRead(activityState.adid); + } + }); + } else { + if (activityState == null) { + logger.warn("SDK needs to be initialized before getting adid"); + } + synchronized (cachedAdidReadCallbacks) { + cachedAdidReadCallbacks.add(callback); + } + } + } + + @Override + public void getAdidWithTimeout(long timeoutInMilliSec, OnAdidReadListener callback) { + if (activityState != null && activityState.adid != null) { + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + callback.onAdidRead(activityState.adid); + } + }); + } else { + if (activityState == null) { + logger.warn("SDK needs to be initialized before getting adid"); + } + + // adid not found in activity state + // queue timeout callback for later processing + queueGetAdidWithTimeout(timeoutInMilliSec, callback, cachedAdidReadTimeoutCallbacks, getContext()); + } + } + + @Override + public void getAttribution(OnAttributionReadListener onAttributionReadListener) { + if (attribution != null) { + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + onAttributionReadListener.onAttributionRead(attribution); + } + }); + }else { + synchronized (cachedAttributionReadCallbacks) { + cachedAttributionReadCallbacks.add(onAttributionReadListener); + } + } + } + + @Override + public void getAttributionWithTimeout(long timeoutInMilliSec, OnAttributionReadListener onAttributionReadListener) { + if (attribution != null) { + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + onAttributionReadListener.onAttributionRead(attribution); + } + }); + } else { + // attribution not found + // queue timeout callback for later processing + queueGetAttributionWithTimeout(timeoutInMilliSec, onAttributionReadListener, cachedAttributionReadTimeoutCallbacks, getContext()); + } + } + + @Override + public void getThirdPartySharingSettingsWithTimeout(long timeoutInMilliSec, OnThirdPartySharingSettingsReadListener listener) { + if (thirdPartySharingResult != null) { + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + listener.onThirdPartySharingSettingsRead(thirdPartySharingResult); + } + }); + } else { + // third party sharing settings not found + // queue timeout callback for later processing + queueGetThirdPartySharingSettingsWithTimeout(timeoutInMilliSec, listener, cachedThirdPartySharingTimeoutCallbacks, getContext()); + } + } + + @Override + public void verifyPlayStorePurchase(final AdjustPlayStorePurchase purchase, + final OnPurchaseVerificationFinishedListener callback) + { + executor.submit(() -> firstSessionDelayManager.apiActionI( + "verify play store purchase", + () -> verifyPlayStorePurchaseI(purchase, callback))); + } + + @Override + public void verifyAndTrackPlayStorePurchase(AdjustEvent event, OnPurchaseVerificationFinishedListener callback) { + executor.submit(() -> firstSessionDelayManager.apiActionI( + "verify and track play store purchase", + () -> verifyAndTrackPlayStorePurchaseI(event, callback))); + } + + @Override + public void endFirstSessionDelay() { + executor.submit(() -> firstSessionDelayManager.endFirstSessionDelayI()); + } + + @Override + public void setCoppaComplianceInDelay(final boolean isCoppaComplianceEnabled) { + executor.submit(() -> firstSessionDelayManager.setCoppaComplianceInDelayI(isCoppaComplianceEnabled));; + } + + @Override + public void setPlayStoreKidsComplianceInDelay(final boolean isPlayStoreKidsComplianceEnabled) { + executor.submit(() -> firstSessionDelayManager.setPlayStoreKidsComplianceInDelayI(isPlayStoreKidsComplianceEnabled));; + } + + @Override + public void setExternalDeviceIdInDelay(final String externalDeviceId) { + executor.submit(() -> firstSessionDelayManager.setExternalDeviceIdInDelayI(externalDeviceId)); + } + + @Override + public InternalState getInternalState() { + return internalState; + } + + public static void queueGetAdidWithTimeout(final long timeoutInMilliSec, + final OnAdidReadListener onAdidReadListener, + final ArrayList cachedAdidReadTimeoutCallbacks, + final Context context) { + AdjustTimeoutCallback timeoutCallback = new AdjustTimeoutCallback(onAdidReadListener); + + // cache the callback before starting the timer + synchronized (cachedAdidReadTimeoutCallbacks) { + cachedAdidReadTimeoutCallbacks.add(timeoutCallback); } - return activityState.adid; + + // set up timeout timer immediately + TimerOnce timerOnce = new TimerOnce(new Runnable() { + @Override + public void run() { + if (timeoutCallback.getOnAdidReadListener() != null) { + // remove callback from array and call callback with null + synchronized (cachedAdidReadTimeoutCallbacks) { + cachedAdidReadTimeoutCallbacks.remove(timeoutCallback); + } + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + // if timer elapses, return null (only if callback still exists) + OnAdidReadListener onAdidReadListener = timeoutCallback.getOnAdidReadListener(); + if (onAdidReadListener != null) { + onAdidReadListener.onAdidRead(null); + } + + // null callback to call it only once + timeoutCallback.setOnAdidReadListener(null); + } + }); + } + } + }, ADID_TIMEOUT_TIMER_NAME); + + timeoutCallback.setTimer(timerOnce); + timerOnce.startIn(timeoutInMilliSec); } - @Override - public AdjustAttribution getAttribution() { - return attribution; + public static void queueGetAttributionWithTimeout(final long timeoutInMilliSec, + final OnAttributionReadListener attributionReadListener, + final ArrayList cachedAttributionReadTimeoutCallbacks, + final Context context) { + AdjustTimeoutCallback timeoutCallback = new AdjustTimeoutCallback(attributionReadListener); + + // cache the callback before starting the timer + synchronized (cachedAttributionReadTimeoutCallbacks) { + cachedAttributionReadTimeoutCallbacks.add(timeoutCallback); + } + + // set up timeout timer immediately + TimerOnce timerOnce = new TimerOnce(new Runnable() { + @Override + public void run() { + if (timeoutCallback.getOnAttributionReadListener() != null) { + // remove callback from array and call callback with null + synchronized (cachedAttributionReadTimeoutCallbacks) { + cachedAttributionReadTimeoutCallbacks.remove(timeoutCallback); + } + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + // if timer elapses, return null (only if callback still exists) + OnAttributionReadListener onAttributionReadListener = timeoutCallback.getOnAttributionReadListener(); + if (onAttributionReadListener != null) { + onAttributionReadListener.onAttributionRead(null); + } + + // null callback to call it only once + timeoutCallback.setOnAttributionReadListener(null); + } + }); + } + } + }, ATTRIBUTION_TIMEOUT_TIMER_NAME); + + timeoutCallback.setTimer(timerOnce); + timerOnce.startIn(timeoutInMilliSec); } - @Override - public void verifyPurchase(final AdjustPurchase purchase, final OnPurchaseVerificationFinishedListener callback) { - executor.submit(new Runnable() { + public static void queueGetThirdPartySharingSettingsWithTimeout(final long timeoutInMilliSec, + final OnThirdPartySharingSettingsReadListener listener, + final ArrayList cachedThirdPartySharingSettingsReadTimeoutCallbacks, + final Context context) { + AdjustTimeoutCallback timeoutCallback = new AdjustTimeoutCallback(listener); + + // cache the callback before starting the timer + synchronized (cachedThirdPartySharingSettingsReadTimeoutCallbacks) { + cachedThirdPartySharingSettingsReadTimeoutCallbacks.add(timeoutCallback); + } + + // set up timeout timer immediately + TimerOnce timerOnce = new TimerOnce(new Runnable() { @Override public void run() { - verifyPurchaseI(purchase, callback); + if (timeoutCallback.getOnThirdPartySharingSettingsReadListener() != null) { + // remove callback from array and call callback with null + synchronized (cachedThirdPartySharingSettingsReadTimeoutCallbacks) { + cachedThirdPartySharingSettingsReadTimeoutCallbacks.remove(timeoutCallback); + } + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + // if timer elapses, return null (only if callback still exists) + OnThirdPartySharingSettingsReadListener readListener = + timeoutCallback.getOnThirdPartySharingSettingsReadListener(); + if (readListener != null) { + readListener.onThirdPartySharingSettingsRead(null); + } + + // null callback to call it only once + timeoutCallback.setOnThirdPartySharingSettingsReadListener(null); + } + }); + } } - }); - } + }, TPS_SETTINGS_TIMEOUT_TIMER_NAME); - public InternalState getInternalState() { - return internalState; + timeoutCallback.setTimer(timerOnce); + timerOnce.startIn(timeoutInMilliSec); } - private void initI() { + void initI() { SESSION_INTERVAL = AdjustFactory.getSessionInterval(); SUBSESSION_INTERVAL = AdjustFactory.getSubsessionInterval(); // get timer values @@ -804,13 +1189,13 @@ private void initI() { FOREGROUND_TIMER_START = AdjustFactory.getTimerStart(); BACKGROUND_TIMER_INTERVAL = AdjustFactory.getTimerInterval(); - // has to be read in the background - readAttributionI(adjustConfig.context); - readActivityStateI(adjustConfig.context); + globalParameters = new GlobalParameters(); + readGlobalCallbackParametersI(adjustConfig.context); + readGlobalPartnerParametersI(adjustConfig.context); - sessionParameters = new SessionParameters(); - readSessionCallbackParametersI(adjustConfig.context); - readSessionPartnerParametersI(adjustConfig.context); + if (activityState != null) { + activityState.setEventDeduplicationIdsMaxSize(adjustConfig.getEventDeduplicationIdsMaxSize()); + } if (adjustConfig.startEnabled != null) { adjustConfig.preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @@ -821,9 +1206,8 @@ public void run(ActivityHandler activityHandler) { }); } - if (internalState.hasFirstSdkStartOcurred()) { + if (activityState != null) { internalState.enabled = activityState.enabled; - internalState.updatePackages = activityState.updatePackages; internalState.firstLaunch = false; } else { internalState.firstLaunch = true; // first launch if activity state is null @@ -833,35 +1217,19 @@ public void run(ActivityHandler activityHandler) { deviceInfo = new DeviceInfo(adjustConfig); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Event buffering is enabled"); - } - - deviceInfo.reloadPlayIds(adjustConfig); - if (deviceInfo.playAdId == null) { - if (!Util.canReadPlayIds(adjustConfig)) { - if (adjustConfig.coppaCompliantEnabled) { - logger.info("Cannot read Google Play Services Advertising ID with COPPA enabled"); - } - - if (adjustConfig.playStoreKidsAppEnabled) { - logger.info("Cannot read Google Play Services Advertising ID with play store kids app enabled"); - } + deviceInfo.reloadGoogleAdId(adjustConfig); + if (deviceInfo.googleAdId == null) { + if (!Util.isGoogleAdIdReadingEnabled(adjustConfig)) { + logger.info("Cannot read Google Advertising ID with COPPA or play store kids app enabled or reading disabled"); } else { - logger.warn("Unable to get Google Play Services Advertising ID at start time"); + logger.warn("Unable to get Google Advertising ID at start time"); } if (deviceInfo.androidId == null) { - if (!Util.canReadNonPlayIds(adjustConfig)) { - if (adjustConfig.coppaCompliantEnabled) { - logger.info("Cannot read non Play IDs with COPPA enabled"); - } - - if (adjustConfig.playStoreKidsAppEnabled) { - logger.info("Cannot read non Play IDs with play store kids app enabled"); - } + if (! Util.isAndroidIdReadingEnabled(adjustConfig)) { + logger.info("Cannot read Android ID with COPPA or play store kids app enabled or reading disabled"); } else { - logger.error("Unable to get any Device IDs. Please check if Proguard is correctly set with Adjust SDK"); + logger.error("Unable to get Android Id. Please check if Proguard is correctly set with Adjust SDK"); } } } else { @@ -875,7 +1243,7 @@ public void run(ActivityHandler activityHandler) { // push token if (adjustConfig.pushToken != null) { logger.info("Push token: '%s'", adjustConfig.pushToken); - if (internalState.hasFirstSdkStartOcurred()) { + if (activityState != null) { // since sdk has already started, try to send current push token setPushToken(adjustConfig.pushToken, false); } else { @@ -884,20 +1252,24 @@ public void run(ActivityHandler activityHandler) { } } else { // since sdk has already started, check if there is a saved push from previous runs - if (internalState.hasFirstSdkStartOcurred()) { + if (activityState != null) { String savedPushToken = SharedPreferencesManager.getDefaultInstance(getContext()).getPushToken(); if(savedPushToken!=null) setPushToken(savedPushToken, true); } } - // cached deep link resolution callback + // cached deeplink resolution callback if (this.cachedDeeplinkResolutionCallback == null) { this.cachedDeeplinkResolutionCallback = adjustConfig.cachedDeeplinkResolutionCallback; } + handleAdidCallbackI(); + handleAttributionCallbackI(); + handleThirdPartySharingCallbackI(); + // GDPR - if (internalState.hasFirstSdkStartOcurred()) { + if (activityState != null) { SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(getContext()); if (sharedPreferencesManager.getGdprForgetMe()) { gdprForgetMe(); @@ -913,7 +1285,7 @@ public void run() { }, FOREGROUND_TIMER_START, FOREGROUND_TIMER_INTERVAL, FOREGROUND_TIMER_NAME); // create background timer - if (adjustConfig.sendInBackground) { + if (adjustConfig.isSendingInBackgroundEnabled) { logger.info("Send in background configured"); backgroundTimer = new TimerOnce(new Runnable() { @@ -924,31 +1296,16 @@ public void run() { }, BACKGROUND_TIMER_NAME); } - // configure delay start timer - if (internalState.hasFirstSdkStartNotOcurred() && - adjustConfig.delayStart != null && - adjustConfig.delayStart > 0.0) - { - logger.info("Delay start configured"); - internalState.delayStart = true; - delayStartTimer = new TimerOnce(new Runnable() { - @Override - public void run() { - sendFirstPackages(); - } - }, DELAY_START_TIMER_NAME); - } - - UtilNetworking.setUserAgent(adjustConfig.userAgent); - IActivityPackageSender packageHandlerActivitySender = new ActivityPackageSender( - adjustConfig.urlStrategy, + adjustConfig.urlStrategyDomains, + adjustConfig.useSubdomains, adjustConfig.basePath, adjustConfig.gdprPath, adjustConfig.subscriptionPath, adjustConfig.purchaseVerificationPath, deviceInfo.clientSdk, + CONNECTION_TIMEOUT, adjustConfig.context); packageHandler = AdjustFactory.getPackageHandler( this, @@ -958,12 +1315,14 @@ public void run() { IActivityPackageSender attributionHandlerActivitySender = new ActivityPackageSender( - adjustConfig.urlStrategy, + adjustConfig.urlStrategyDomains, + adjustConfig.useSubdomains, adjustConfig.basePath, adjustConfig.gdprPath, adjustConfig.subscriptionPath, adjustConfig.purchaseVerificationPath, deviceInfo.clientSdk, + CONNECTION_TIMEOUT, adjustConfig.context); attributionHandler = AdjustFactory.getAttributionHandler( @@ -973,12 +1332,14 @@ public void run() { IActivityPackageSender sdkClickHandlerActivitySender = new ActivityPackageSender( - adjustConfig.urlStrategy, + adjustConfig.urlStrategyDomains, + adjustConfig.useSubdomains, adjustConfig.basePath, adjustConfig.gdprPath, adjustConfig.subscriptionPath, adjustConfig.purchaseVerificationPath, deviceInfo.clientSdk, + CONNECTION_TIMEOUT, adjustConfig.context); sdkClickHandler = AdjustFactory.getSdkClickHandler( @@ -988,12 +1349,14 @@ public void run() { IActivityPackageSender purchaseVerificationHandlerActivitySender = new ActivityPackageSender( - adjustConfig.urlStrategy, + adjustConfig.urlStrategyDomains, + adjustConfig.useSubdomains, adjustConfig.basePath, adjustConfig.gdprPath, adjustConfig.subscriptionPath, adjustConfig.purchaseVerificationPath, deviceInfo.clientSdk, + CONNECTION_TIMEOUT_VERIFY, adjustConfig.context); purchaseVerificationHandler = AdjustFactory.getPurchaseVerificationHandler( @@ -1001,33 +1364,241 @@ public void run() { toSendI(true), purchaseVerificationHandlerActivitySender); - if (isToUpdatePackagesI()) { - updatePackagesI(); - } - installReferrer = new InstallReferrer(adjustConfig.context, new InstallReferrerReadListener() { @Override public void onInstallReferrerRead(ReferrerDetails referrerDetails, String referrerApi) { sendInstallReferrer(referrerDetails, referrerApi); } - }); - installReferrerHuawei = new InstallReferrerHuawei(adjustConfig.context, new InstallReferrerReadListener() { @Override - public void onInstallReferrerRead(ReferrerDetails referrerDetails, String referrerApi) { - sendInstallReferrer(referrerDetails, referrerApi); + public void onFail(String message) { + logger.debug(message); } + }); - installReferrerMeta = new InstallReferrerMeta(adjustConfig.context, adjustConfig.fbAppId, - new InstallReferrerReadListener() { - @Override - public void onInstallReferrerRead(ReferrerDetails referrerDetails, String referrerApi) { - sendInstallReferrer(referrerDetails, referrerApi); - } - }); preLaunchActionsI(adjustConfig.preLaunchActions.preLaunchActionsArray); sendReftagReferrerI(); + + bootstrapLifecycleI(); + } + + private void handleAttributionCallbackI() { + synchronized (cachedAttributionReadCallbacks) { + cachedAttributionReadCallbacks.addAll(adjustConfig.cachedAttributionReadCallbacks); + adjustConfig.cachedAttributionReadCallbacks.clear(); + } + + synchronized (cachedAttributionReadTimeoutCallbacks) { + cachedAttributionReadTimeoutCallbacks.addAll(adjustConfig.cachedAttributionReadTimeoutCallbacks); + adjustConfig.cachedAttributionReadTimeoutCallbacks.clear(); + } + + if (attribution == null) { + return; + } + + ArrayList cachedAttributionReadCallbacksCopy = null; + synchronized (cachedAttributionReadCallbacks) { + if (! cachedAttributionReadCallbacks.isEmpty()) { + cachedAttributionReadCallbacksCopy = new ArrayList<>(cachedAttributionReadCallbacks); + cachedAttributionReadCallbacks.clear(); + } + } + + // process regular attribution callbacks + if (cachedAttributionReadCallbacksCopy != null) { + final AdjustAttribution attributionCopy = attribution; + ArrayList finalCachedAttributionReadCallbacksCopy = cachedAttributionReadCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (OnAttributionReadListener onAttributionReadListener : finalCachedAttributionReadCallbacksCopy) { + if (onAttributionReadListener != null) { + onAttributionReadListener.onAttributionRead(attributionCopy); + } + } + } + }); + } + + ArrayList cachedAttributionReadTimeoutCallbacksCopy = null; + synchronized (cachedAttributionReadTimeoutCallbacks) { + if (! cachedAttributionReadTimeoutCallbacks.isEmpty()) { + cachedAttributionReadTimeoutCallbacksCopy = new ArrayList<>(cachedAttributionReadTimeoutCallbacks); + cachedAttributionReadTimeoutCallbacks.clear(); + } + } + + // process timeout attribution callbacks + if (cachedAttributionReadTimeoutCallbacksCopy != null) { + final AdjustAttribution attributionCopy = attribution; + ArrayList finalCachedAttributionReadTimeoutCallbacksCopy = cachedAttributionReadTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedAttributionReadTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + OnAttributionReadListener onAttributionReadListener = adjustTimeoutCallback.getOnAttributionReadListener(); + if (onAttributionReadListener != null) { + onAttributionReadListener.onAttributionRead(attributionCopy); + } + + // null callback to call it only once + adjustTimeoutCallback.setOnAttributionReadListener(null); + } + } + } + }); + } + } + + private void handleAdidCallbackI() { + synchronized (cachedAdidReadCallbacks) { + cachedAdidReadCallbacks.addAll(adjustConfig.cachedAdidReadCallbacks); + adjustConfig.cachedAdidReadCallbacks.clear(); + } + + synchronized (cachedAdidReadTimeoutCallbacks) { + cachedAdidReadTimeoutCallbacks.addAll(adjustConfig.cachedAdidReadTimeoutCallbacks); + adjustConfig.cachedAdidReadTimeoutCallbacks.clear(); + } + + if (activityState == null || activityState.adid == null) { + return; + } + + ArrayList cachedAdidReadCallbacksCopy = null; + synchronized (cachedAdidReadCallbacks) { + if (! cachedAdidReadCallbacks.isEmpty()) { + cachedAdidReadCallbacksCopy = new ArrayList<>(cachedAdidReadCallbacks); + cachedAdidReadCallbacks.clear(); + } + } + + // process regular adid callbacks + if (cachedAdidReadCallbacksCopy != null) { + final String adidCopy = activityState.adid; + ArrayList finalCachedAdidReadCallbacksCopy = cachedAdidReadCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (OnAdidReadListener onAdidReadListener : finalCachedAdidReadCallbacksCopy) { + if (onAdidReadListener != null) { + onAdidReadListener.onAdidRead(adidCopy); + } + } + } + }); + } + + + ArrayList cachedAdidReadTimeoutCallbacksCopy = null; + synchronized (cachedAdidReadTimeoutCallbacks) { + if (! cachedAdidReadTimeoutCallbacks.isEmpty()) { + cachedAdidReadTimeoutCallbacksCopy = new ArrayList<>(cachedAdidReadTimeoutCallbacks); + cachedAdidReadTimeoutCallbacks.clear(); + } + } + + // process timeout adid callbacks + if (cachedAdidReadTimeoutCallbacksCopy != null) { + final String adidCopy = activityState.adid; + ArrayList finalCachedAdidReadTimeoutCallbacksCopy = cachedAdidReadTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedAdidReadTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + OnAdidReadListener onAdidReadListener = adjustTimeoutCallback.getOnAdidReadListener(); + if (onAdidReadListener != null) { + onAdidReadListener.onAdidRead(adidCopy); + } + + // null callback to call it only once + adjustTimeoutCallback.setOnAdidReadListener(null); + } + } + } + }); + } + } + + private void handleThirdPartySharingCallbackI() { + synchronized (cachedThirdPartySharingTimeoutCallbacks) { + cachedThirdPartySharingTimeoutCallbacks.addAll(adjustConfig.cachedThirdPartySharingTimeoutCallbacks); + adjustConfig.cachedThirdPartySharingTimeoutCallbacks.clear(); + } + + if (thirdPartySharingResult == null) { + return; + } + + ArrayList cachedThirdPartySharingTimeoutCallbacksCopy = null; + synchronized (cachedThirdPartySharingTimeoutCallbacks) { + if (! cachedThirdPartySharingTimeoutCallbacks.isEmpty()) { + cachedThirdPartySharingTimeoutCallbacksCopy = new ArrayList<>(cachedThirdPartySharingTimeoutCallbacks); + cachedThirdPartySharingTimeoutCallbacks.clear(); + } + } + + // process third party sharing callbacks + if (cachedThirdPartySharingTimeoutCallbacksCopy != null) { + final AdjustThirdPartySharingResult thirdPartySharingResultCopy = thirdPartySharingResult; + ArrayList finalCachedThirdPartySharingTimeoutCallbacksCopy = cachedThirdPartySharingTimeoutCallbacksCopy; + new Handler(adjustConfig.context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + for (AdjustTimeoutCallback adjustTimeoutCallback : finalCachedThirdPartySharingTimeoutCallbacksCopy) { + if (adjustTimeoutCallback != null) { + // cancel any pending timeout + TimerOnce timerOnce = adjustTimeoutCallback.getTimeoutTimer(); + if (timerOnce != null) { + timerOnce.cancel(); + } + OnThirdPartySharingSettingsReadListener listener = adjustTimeoutCallback.getOnThirdPartySharingSettingsReadListener(); + if (listener != null) { + listener.onThirdPartySharingSettingsRead(thirdPartySharingResultCopy); + } + + // null callback to call it only once + adjustTimeoutCallback.setOnThirdPartySharingSettingsReadListener(null); + } + } + } + }); + } + } + + private void bootstrapLifecycleI() { + this.systemLifecycle = SystemLifecycle.getSingletonInstance(); + + for (@NonNull final String message : systemLifecycle.logMessageList) { + logger.debug("Lifecycle: %s", message); + } + + systemLifecycle.overwriteCallback(this); + + if (AdjustFactory.isSystemLifecycleBootstrapIgnored()) { + return; + } + + this.internalState.foregroundOrElseBackground = + systemLifecycle.foregroundOrElseBackgroundCached(); + + if (internalState.isInForeground()) { + onResumeI(); + } } private void checkForPreinstallI() { @@ -1038,7 +1609,7 @@ private void checkForPreinstallI() { // sending preinstall referrer doesn't require preinstall tracking flag to be enabled sendPreinstallReferrerI(); - if (!adjustConfig.preinstallTrackingEnabled) return; + if (!adjustConfig.isPreinstallTrackingEnabled) return; if (internalState.hasPreinstallBeenRead()) return; if (deviceInfo.packageName == null || deviceInfo.packageName.isEmpty()) { @@ -1162,6 +1733,20 @@ private void checkForPreinstallI() { } } + // 9. try reading preinstall payload from content provider maps + if (PreinstallUtil.hasNotBeenRead(Constants.CONTENT_PROVIDER_SAMSUNG_MAPS, readStatus)) { + String payloadContentProviderMaps = PreinstallUtil.getPayloadFromContentProviderSamsungMaps( + adjustConfig.context, + deviceInfo.packageName, + logger); + + if (payloadContentProviderMaps != null && !payloadContentProviderMaps.isEmpty()) { + sdkClickHandler.sendPreinstallPayload(payloadContentProviderMaps, Constants.CONTENT_PROVIDER_SAMSUNG_MAPS); + } else { + readStatus = PreinstallUtil.markAsRead(Constants.CONTENT_PROVIDER_SAMSUNG_MAPS, readStatus); + } + } + sharedPreferencesManager.setPreinstallPayloadReadStatus(readStatus); internalState.preinstallHasBeenRead = true; @@ -1200,31 +1785,13 @@ private void preLaunchActionsI(List preLaunchActionsArray) private void startI() { // check if it's the first sdk start - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { AdjustSigner.onResume(adjustConfig.logger); startFirstSessionI(); return; } else { - SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(getContext()); - - // check if disable third party sharing request came, then send it first - if (sharedPreferencesManager.getDisableThirdPartySharing()) { - disableThirdPartySharingI(); - } - for (AdjustThirdPartySharing adjustThirdPartySharing : - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray) - { - trackThirdPartySharingI(adjustThirdPartySharing); - } - if (adjustConfig.preLaunchActions.lastMeasurementConsentTracked != null) { - trackMeasurementConsentI( - adjustConfig.preLaunchActions. - lastMeasurementConsentTracked.booleanValue()); - } - - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray = - new ArrayList<>(); - adjustConfig.preLaunchActions.lastMeasurementConsentTracked = null; + // check if third party sharing request came, then send it first + processPreLaunchArraysI(); } // it shouldn't start if it was disabled after a first session @@ -1247,7 +1814,9 @@ private void startI() { private void startFirstSessionI() { activityState = new ActivityState(); - internalState.firstSdkStart = true; + //internalState.firstSdkStart = true; + + activityState.setEventDeduplicationIdsMaxSize(adjustConfig.getEventDeduplicationIdsMaxSize()); // still update handlers status updateHandlersStatusAndSendI(); @@ -1265,25 +1834,7 @@ private void startFirstSessionI() { } else { processCoppaComplianceI(); - // check if disable third party sharing request came, then send it first - if (sharedPreferencesManager.getDisableThirdPartySharing()) { - disableThirdPartySharingI(); - } - for (AdjustThirdPartySharing adjustThirdPartySharing : - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray) - { - trackThirdPartySharingI(adjustThirdPartySharing); - } - if (adjustConfig.preLaunchActions.lastMeasurementConsentTracked != null) { - trackMeasurementConsentI( - adjustConfig.preLaunchActions. - lastMeasurementConsentTracked.booleanValue()); - } - - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray = - new ArrayList<>(); - adjustConfig.preLaunchActions.lastMeasurementConsentTracked = null; - + processPreLaunchArraysI(); activityState.sessionCount = 1; // this is the first session transferSessionPackageI(now); @@ -1293,14 +1844,12 @@ private void startFirstSessionI() { activityState.resetSessionAttributes(now); activityState.enabled = internalState.isEnabled(); - activityState.updatePackages = internalState.itHasToUpdatePackages(); writeActivityStateI(); sharedPreferencesManager.removePushToken(); sharedPreferencesManager.removeGdprForgetMe(); - sharedPreferencesManager.removeDisableThirdPartySharing(); - // check for cached deep links + // check for cached deeplinks processCachedDeeplinkI(); // don't check attribution right after first sdk start @@ -1343,11 +1892,14 @@ private void processSessionI() { // Try to check if there's new referrer information. installReferrer.startConnection(); - installReferrerHuawei.readReferrer(); - installReferrerMeta.readReferrer(); + readInstallReferrerMeta(); + readInstallReferrerHuaweiAds(); + readInstallReferrerHuaweiAppGallery(); readInstallReferrerSamsung(); readInstallReferrerXiaomi(); readInstallReferrerVivo(); + readLicenseVerificationData(); + return; } @@ -1355,6 +1907,59 @@ private void processSessionI() { logger.verbose("Time span since last activity too short for a new subsession"); } + private void readInstallReferrerMeta() { + executor.submit(new Runnable() { + @Override + public void run() { + ReferrerDetails referrerDetails = Reflection.getMetaReferrer(getContext(), adjustConfig.fbAppId, logger); + if (referrerDetails != null) { + sendInstallReferrer(referrerDetails, REFERRER_API_META); + } + } + }); + } + + private void readLicenseVerificationData() { + executor.submit(new Runnable() { + @Override + public void run() { + if (SharedPreferencesManager + .getDefaultInstance(getContext()) + .getLicenseVerificationTracked()){ + return; + } + LicenseData licenseData = Reflection.getLicenseRequiredData(getContext(), logger,deviceInfo.appInstallTime); + if (licenseData != null) { + sendLicenseVerificationData(licenseData); + } + } + }); + } + + private void readInstallReferrerHuaweiAds() { + executor.submit(new Runnable() { + @Override + public void run() { + ReferrerDetails referrerDetails = Reflection.getHuaweiAdsReferrer(getContext(), logger); + if (referrerDetails != null) { + sendInstallReferrer(referrerDetails, REFERRER_API_HUAWEI_ADS); + } + } + }); + } + + private void readInstallReferrerHuaweiAppGallery() { + executor.submit(new Runnable() { + @Override + public void run() { + ReferrerDetails referrerDetails = Reflection.getHuaweiAppGalleryReferrer(getContext(), logger); + if (referrerDetails != null) { + sendInstallReferrer(referrerDetails, REFERRER_API_HUAWEI_APP_GALLERY); + } + } + }); + } + private void readInstallReferrerSamsung() { executor.submit(new Runnable() { @Override @@ -1428,6 +2033,7 @@ private void processCachedDeeplinkI() { SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(getContext()); String cachedDeeplinkUrl = sharedPreferencesManager.getDeeplinkUrl(); + String cachedDeeplinkReferrer = sharedPreferencesManager.getDeeplinkReferrer(); long cachedDeeplinkClickTime = sharedPreferencesManager.getDeeplinkClickTime(); if (cachedDeeplinkUrl == null) { @@ -1437,7 +2043,11 @@ private void processCachedDeeplinkI() { return; } - readOpenUrl(Uri.parse(cachedDeeplinkUrl), cachedDeeplinkClickTime); + AdjustDeeplink deeplink = new AdjustDeeplink(Uri.parse(cachedDeeplinkUrl)); + if (cachedDeeplinkReferrer != null) { + deeplink.setReferrer(Uri.parse(cachedDeeplinkReferrer)); + } + processDeeplink(deeplink, cachedDeeplinkClickTime); sharedPreferencesManager.removeDeeplink(); } @@ -1457,31 +2067,31 @@ private void trackEventI(AdjustEvent event) { if (!checkActivityStateI(activityState)) return; if (!isEnabledI()) return; if (!checkEventI(event)) return; - if (!checkOrderIdI(event.orderId)) return; if (activityState.isGdprForgotten) return; + if (!shouldProcessEventI(event.deduplicationId)) return; long now = System.currentTimeMillis(); + int sequence = eventMetadata.incrementSequenceForEvent(event.eventToken); + activityState.eventCount++; updateActivityStateI(now); - PackageBuilder eventBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder eventBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); eventBuilder.internalState = internalState; - ActivityPackage eventPackage = eventBuilder.buildEventPackage(event, internalState.isInDelayedStart()); + ActivityPackage eventPackage = eventBuilder.buildEventPackage(event, sequence); packageHandler.addPackage(eventPackage); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", eventPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } + packageHandler.sendFirstPackage(); // if it is in the background and it can send, start the background timer - if (adjustConfig.sendInBackground && internalState.isInBackground()) { + if (adjustConfig.isSendingInBackgroundEnabled && internalState.isInBackground()) { startBackgroundTimerI(); } writeActivityStateI(); + writeEventMetadataI(); } private void launchEventResponseTasksI(final EventResponseData eventResponseData) { @@ -1503,7 +2113,7 @@ public void run() { if (adjustConfig.onEventTrackingSucceededListener == null) { return; } - adjustConfig.onEventTrackingSucceededListener.onFinishedEventTrackingSucceeded(eventResponseData.getSuccessResponseData()); + adjustConfig.onEventTrackingSucceededListener.onEventTrackingSucceeded(eventResponseData.getSuccessResponseData()); } }; handler.post(runnable); @@ -1523,7 +2133,7 @@ public void run() { if (adjustConfig.onEventTrackingFailedListener == null) { return; } - adjustConfig.onEventTrackingFailedListener.onFinishedEventTrackingFailed(eventResponseData.getFailureResponseData()); + adjustConfig.onEventTrackingFailedListener.onEventTrackingFailed(eventResponseData.getFailureResponseData()); } }; handler.post(runnable); @@ -1593,6 +2203,9 @@ private void launchSessionResponseTasksI(SessionResponseData sessionResponseData // launch Session tracking listener if available launchSessionResponseListenerI(sessionResponseData, handler); + // if there is any, try to launch the deeplink + prepareDeeplinkI(sessionResponseData.deeplink, handler); + // mark session response has proccessed internalState.sessionResponseProcessed = true; } @@ -1611,7 +2224,7 @@ public void run() { if (adjustConfig.onSessionTrackingSucceededListener == null) { return; } - adjustConfig.onSessionTrackingSucceededListener.onFinishedSessionTrackingSucceeded(sessionResponseData.getSuccessResponseData()); + adjustConfig.onSessionTrackingSucceededListener.onSessionTrackingSucceeded(sessionResponseData.getSuccessResponseData()); } }; handler.post(runnable); @@ -1631,7 +2244,7 @@ public void run() { if (adjustConfig.onSessionTrackingFailedListener == null) { return; } - adjustConfig.onSessionTrackingFailedListener.onFinishedSessionTrackingFailed(sessionResponseData.getFailureResponseData()); + adjustConfig.onSessionTrackingFailedListener.onSessionTrackingFailed(sessionResponseData.getFailureResponseData()); } }; handler.post(runnable); @@ -1641,6 +2254,9 @@ public void run() { } private void launchAttributionResponseTasksI(AttributionResponseData attributionResponseData) { + // process remote triggers from any response + processRemoteTriggersI(attributionResponseData); + // try to update adid from response updateAdidI(attributionResponseData.adid); @@ -1678,6 +2294,26 @@ public void run() { handler.post(runnable); } + private void launchThirdPartySharingSettingsChangedListenerI(Handler handler) { + if (adjustConfig.onThirdPartySharingSettingsChangedListener == null) { + return; + } + // add it to the handler queue + Runnable runnable = new Runnable() { + @Override + public void run() { + if (adjustConfig == null) { + return; + } + if (adjustConfig.onThirdPartySharingSettingsChangedListener == null) { + return; + } + adjustConfig.onThirdPartySharingSettingsChangedListener.onThirdPartySharingSettingsChanged(thirdPartySharingResult); + } + }; + handler.post(runnable); + } + private void launchPurchaseVerificationResponseTasksI(PurchaseVerificationResponseData purchaseVerificationResponseData) { // use the same handler to ensure that all tasks are executed sequentially Handler handler = new Handler(adjustConfig.context.getMainLooper()); @@ -1705,6 +2341,90 @@ public void run() { } }; handler.post(runnable); + + if (purchaseVerificationResponseData.activityPackage != null && + purchaseVerificationResponseData.activityPackage.event != null) + { + this.trackEventI(purchaseVerificationResponseData.activityPackage.event); + } + } + + private void processRemoteTriggersI(ResponseData responseData) { + // process remote triggers independently from other response processing + if (responseData.jsonResponse == null) { + return; + } + + JSONArray remoteTriggers = responseData.jsonResponse.optJSONArray("remote_triggers"); + + if (remoteTriggers == null) { + return; + } + + if (remoteTriggers.length() == 0) { + return; + } + + if (adjustConfig.onRemoteTriggerListener == null) { + return; + } + + // process each remote trigger in order + for (int i = 0; i < remoteTriggers.length(); i++) { + JSONObject remoteTrigger = remoteTriggers.optJSONObject(i); + if (remoteTrigger == null) { + logger.warn("Invalid remote trigger item, skipping"); + continue; + } + + String label = remoteTrigger.optString("label"); + if (label.isEmpty()) { + logger.warn("Remote trigger missing or invalid label, skipping"); + continue; + } + + JSONObject payload = remoteTrigger.optJSONObject("payload"); + if (payload == null) { + logger.warn("Remote trigger missing or invalid payload, skipping"); + continue; + } + + final AdjustRemoteTrigger adjustRemoteTrigger = new AdjustRemoteTrigger(label, payload); + Handler handler = new Handler(adjustConfig.context.getMainLooper()); + Runnable runnable = new Runnable() { + @Override + public void run() { + if (adjustConfig.onRemoteTriggerListener != null) { + adjustConfig.onRemoteTriggerListener.onRemoteTrigger(adjustRemoteTrigger); + } + } + }; + handler.post(runnable); + } + } + + private void launchThirdPartySharingResponseTasksI(final ThirdPartySharingResponseData thirdPartySharingResponseData) { + if (thirdPartySharingResponseData.jsonResponse == null) { + return; + } + + final JSONObject tpsSettingsJson = thirdPartySharingResponseData.jsonResponse.optJSONObject("third_party_sharing"); + + if (tpsSettingsJson == null) { + // nothing to update + return; + } + + String tpsSettingsJsonString = tpsSettingsJson.toString(); + + boolean thirdPartySharingSettingsChanged = + updateThirdPartySharingSettingsI(new AdjustThirdPartySharingResult(tpsSettingsJsonString)); + + // if third party sharing settings changed, launch third party sharing settings changed delegate + if (thirdPartySharingSettingsChanged) { + Handler handler = new Handler(adjustConfig.context.getMainLooper()); + launchThirdPartySharingSettingsChangedListenerI(handler); + } } private void prepareDeeplinkI(final Uri deeplink, final Handler handler) { @@ -1723,8 +2443,8 @@ public void run() { return; } boolean toLaunchDeeplink = true; - if (adjustConfig.onDeeplinkResponseListener != null) { - toLaunchDeeplink = adjustConfig.onDeeplinkResponseListener.launchReceivedDeeplink(deeplink); + if (adjustConfig.onDeferredDeeplinkResponseListener != null) { + toLaunchDeeplink = adjustConfig.onDeferredDeeplinkResponseListener.launchReceivedDeeplink(deeplink); } if (toLaunchDeeplink) { launchDeeplinkMain(deeplinkIntent, deeplink); @@ -1736,15 +2456,9 @@ public void run() { private Intent createDeeplinkIntentI(Uri deeplink) { Intent mapIntent; - if (adjustConfig.deepLinkComponent == null) { - mapIntent = new Intent(Intent.ACTION_VIEW, deeplink); - } else { - mapIntent = new Intent(Intent.ACTION_VIEW, deeplink, adjustConfig.context, adjustConfig.deepLinkComponent); - } + mapIntent = new Intent(Intent.ACTION_VIEW, deeplink); mapIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mapIntent.setPackage(adjustConfig.context.getPackageName()); - return mapIntent; } @@ -1756,12 +2470,12 @@ private void launchDeeplinkMain(Intent deeplinkIntent, Uri deeplink) { // Start an activity if it's safe if (!isIntentSafe) { - logger.error("Unable to open deferred deep link (%s)", deeplink); + logger.error("Unable to open deferred deeplink (%s)", deeplink); return; } // add it to the handler queue - logger.info("Open deferred deep link (%s)", deeplink); + logger.info("Open deferred deeplink (%s)", deeplink); adjustConfig.context.startActivity(deeplinkIntent); } @@ -1782,7 +2496,7 @@ private void setEnabledI(boolean enabled) { // save new enabled state in internal state internalState.enabled = enabled; - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { updateStatusI(!enabled, "Handlers will start as paused due to the SDK being disabled", "Handlers will still start as paused", @@ -1801,23 +2515,7 @@ private void setEnabledI(boolean enabled) { } else { processCoppaComplianceI(); - if (sharedPreferencesManager.getDisableThirdPartySharing()) { - disableThirdPartySharingI(); - } - for (AdjustThirdPartySharing adjustThirdPartySharing : - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray) - { - trackThirdPartySharingI(adjustThirdPartySharing); - } - if (adjustConfig.preLaunchActions.lastMeasurementConsentTracked != null) { - trackMeasurementConsentI( - adjustConfig.preLaunchActions. - lastMeasurementConsentTracked.booleanValue()); - } - - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray = - new ArrayList<>(); - adjustConfig.preLaunchActions.lastMeasurementConsentTracked = null; + processPreLaunchArraysI(); } // check if install was tracked @@ -1835,6 +2533,19 @@ private void setEnabledI(boolean enabled) { "Resuming handlers due to SDK being enabled"); } + private void processPreLaunchArraysI() { + if (cachedAdjustThirdPartySharingArray != null && canTrackThirdPartySharingI()) { + for (AdjustThirdPartySharing adjustThirdPartySharing : cachedAdjustThirdPartySharingArray) { + trackThirdPartySharingI(adjustThirdPartySharing); + } + } + cachedAdjustThirdPartySharingArray = null; + + if (cachedLastMeasurementConsentTrack != null && canTrackMeasurementConsentI()) { + trackMeasurementConsentI(cachedLastMeasurementConsentTrack.booleanValue()); + } + cachedLastMeasurementConsentTrack = null; + } private void checkAfterNewStartI() { checkAfterNewStartI(SharedPreferencesManager.getDefaultInstance(getContext())); @@ -1860,11 +2571,13 @@ private void checkAfterNewStartI(SharedPreferencesManager sharedPreferencesManag // try to read and send the install referrer installReferrer.startConnection(); - installReferrerHuawei.readReferrer(); - installReferrerMeta.readReferrer(); + readInstallReferrerMeta(); + readInstallReferrerHuaweiAds(); + readInstallReferrerHuaweiAppGallery(); readInstallReferrerSamsung(); readInstallReferrerXiaomi(); readInstallReferrerVivo(); + readLicenseVerificationData(); } private void setOfflineModeI(boolean offline) { @@ -1877,7 +2590,7 @@ private void setOfflineModeI(boolean offline) { internalState.offline = offline; - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { updateStatusI(offline, "Handlers will start paused due to SDK being offline", "Handlers will still start as paused", @@ -1941,7 +2654,7 @@ private void sendReftagReferrerI() { if (!isEnabledI()) { return; } - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { return; } @@ -1952,7 +2665,7 @@ private void sendPreinstallReferrerI() { if (!isEnabledI()) { return; } - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { return; } @@ -1986,7 +2699,30 @@ private void sendInstallReferrerI(ReferrerDetails referrerDetails, String referr activityState, adjustConfig, deviceInfo, - sessionParameters, + globalParameters, + firstSessionDelayManager, + internalState); + + sdkClickHandler.sendSdkClick(sdkClickPackage); + } + + private void sendLicenseVerificationDataI(LicenseData licenseData) { + if (!isEnabledI()) { + return; + } + + if (licenseData == null || !licenseData.isValid()) { + return; + } + + // Create sdk click + ActivityPackage sdkClickPackage = PackageFactory.buildLicenseVerificationSdkClickPackage( + licenseData, + activityState, + adjustConfig, + deviceInfo, + globalParameters, + firstSessionDelayManager, internalState); sdkClickHandler.sendSdkClick(sdkClickPackage); @@ -2004,23 +2740,47 @@ private boolean isValidReferrerDetails(final ReferrerDetails referrerDetails) { return referrerDetails.installReferrer.length() != 0; } - private void readOpenUrlI(Uri url, long clickTime) { + + private void processDeeplinkI(AdjustDeeplink deeplink, long clickTime) { if (!isEnabledI()) { return; } + if (deeplink == null) { + return; + } - if (Util.isUrlFilteredOut(url)) { - logger.debug("Deeplink (" + url.toString() + ") processing skipped"); + if (Util.isUrlFilteredOut(deeplink.getUrl())) { + if (deeplink.getUrl() != null) { + logger.debug("Deeplink (" + deeplink.getUrl().toString() + ") processing skipped"); + } return; } + if (Util.isUrlWithTrackerQueryParam(deeplink.getUrl())) { + final String resolvedLink = deeplink.getUrl().toString(); + Handler handler = new Handler(adjustConfig.context.getMainLooper()); + OnDeeplinkResolvedListener onDeeplinkResolvedListener = cachedDeeplinkResolutionCallback; + cachedDeeplinkResolutionCallback = null; + if (onDeeplinkResolvedListener != null) { + Runnable runnable = new Runnable() { + @Override + public void run() { + onDeeplinkResolvedListener.onDeeplinkResolved(resolvedLink); + } + }; + handler.post(runnable); + } + } + ActivityPackage sdkClickPackage = PackageFactory.buildDeeplinkSdkClickPackage( - url, + deeplink.getUrl(), + deeplink.getReferrer(), clickTime, activityState, adjustConfig, deviceInfo, - sessionParameters, + globalParameters, + firstSessionDelayManager, internalState); if (sdkClickPackage == null) { @@ -2039,14 +2799,8 @@ private void updateHandlersStatusAndSendI() { resumeSendingI(); - // if event buffering is not enabled - if (!adjustConfig.eventBufferingEnabled || - // or if it's the first launch and it hasn't received the session response - (internalState.isFirstLaunch() && internalState.hasSessionResponseNotBeenProcessed())) - { - // try to send - packageHandler.sendFirstPackage(); - } + // try to send + packageHandler.sendFirstPackage(); } private void pauseSendingI() { @@ -2098,19 +2852,23 @@ public static boolean deleteAttribution(Context context) { return context.deleteFile(ATTRIBUTION_FILENAME); } - public static boolean deleteSessionCallbackParameters(Context context) { - return context.deleteFile(SESSION_CALLBACK_PARAMETERS_FILENAME); + public static boolean deleteEventMetadata(Context context) { + return context.deleteFile(EVENT_METADATA_FILENAME); } - public static boolean deleteSessionPartnerParameters(Context context) { - return context.deleteFile(SESSION_PARTNER_PARAMETERS_FILENAME); + public static boolean deleteGlobalCallbackParameters(Context context) { + return context.deleteFile(GLOBAL_CALLBACK_PARAMETERS_FILENAME); + } + + public static boolean deleteGlobalPartnerParameters(Context context) { + return context.deleteFile(GLOBAL_PARTNER_PARAMETERS_FILENAME); } private void transferSessionPackageI(long now) { - PackageBuilder builder = new PackageBuilder(adjustConfig, deviceInfo, activityState, - sessionParameters, now); + PackageBuilder builder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); builder.internalState = internalState; - ActivityPackage sessionPackage = builder.buildSessionPackage(internalState.isInDelayedStart()); + ActivityPackage sessionPackage = builder.buildSessionPackage(); packageHandler.addPackage(sessionPackage); packageHandler.sendFirstPackage(); } @@ -2176,91 +2934,15 @@ private void backgroundTimerFiredI() { } } - private void delayStartI() { - // it's not configured to start delayed or already finished - if (internalState.isNotInDelayedStart()) { - return; - } - - // the delay has already started - if (isToUpdatePackagesI()) { - return; - } - - // check against max start delay - double delayStartSeconds = adjustConfig.delayStart != null ? adjustConfig.delayStart : 0.0; - long maxDelayStartMilli = AdjustFactory.getMaxDelayStart(); - - long delayStartMilli = (long)(delayStartSeconds * 1000); - if (delayStartMilli > maxDelayStartMilli) { - double maxDelayStartSeconds = maxDelayStartMilli / 1000; - String delayStartFormatted = Util.SecondsDisplayFormat.format(delayStartSeconds); - String maxDelayStartFormatted = Util.SecondsDisplayFormat.format(maxDelayStartSeconds); - - logger.warn("Delay start of %s seconds bigger than max allowed value of %s seconds", delayStartFormatted, maxDelayStartFormatted); - delayStartMilli = maxDelayStartMilli; - delayStartSeconds = maxDelayStartSeconds; - } - - String delayStartFormatted = Util.SecondsDisplayFormat.format(delayStartSeconds); - logger.info("Waiting %s seconds before starting first session", delayStartFormatted); - - delayStartTimer.startIn(delayStartMilli); - - internalState.updatePackages = true; - - if (activityState != null) { - activityState.updatePackages = true; - writeActivityStateI(); - } - } - - private void sendFirstPackagesI() { - if (internalState.isNotInDelayedStart()) { - logger.info("Start delay expired or never configured"); - return; - } - - // update packages in queue - updatePackagesI(); - // no longer is in delay start - internalState.delayStart = false; - // cancel possible still running timer if it was called by user - delayStartTimer.cancel(); - // and release timer - delayStartTimer = null; - // update the status and try to send first package - updateHandlersStatusAndSendI(); - } - - private void updatePackagesI() { - // update activity packages - packageHandler.updatePackages(sessionParameters); - // no longer needs to update packages - internalState.updatePackages = false; - if (activityState != null) { - activityState.updatePackages = false; - writeActivityStateI(); - } - } - - private boolean isToUpdatePackagesI() { - if (activityState != null) { - return activityState.updatePackages; - } else { - return internalState.itHasToUpdatePackages(); - } - } - - public void addSessionCallbackParameterI(String key, String value) { - if (!Util.isValidParameter(key, "key", "Session Callback")) return; - if (!Util.isValidParameter(value, "value", "Session Callback")) return; + public void addGlobalCallbackParameterI(String key, String value) { + if (!Util.isValidParameter(key, "key", "Global Callback")) return; + if (!Util.isValidParameter(value, "value", "Global Callback")) return; - if (sessionParameters.callbackParameters == null) { - sessionParameters.callbackParameters = new LinkedHashMap(); + if (globalParameters.callbackParameters == null) { + globalParameters.callbackParameters = new LinkedHashMap(); } - String oldValue = sessionParameters.callbackParameters.get(key); + String oldValue = globalParameters.callbackParameters.get(key); if (value.equals(oldValue)) { logger.verbose("Key %s already present with the same value", key); @@ -2271,20 +2953,20 @@ public void addSessionCallbackParameterI(String key, String value) { logger.warn("Key %s will be overwritten", key); } - sessionParameters.callbackParameters.put(key, value); + globalParameters.callbackParameters.put(key, value); - writeSessionCallbackParametersI(); + writeGlobalCallbackParametersI(); } - public void addSessionPartnerParameterI(String key, String value) { - if (!Util.isValidParameter(key, "key", "Session Partner")) return; - if (!Util.isValidParameter(value, "value", "Session Partner")) return; + public void addGlobalPartnerParameterI(String key, String value) { + if (!Util.isValidParameter(key, "key", "Global Partner")) return; + if (!Util.isValidParameter(value, "value", "Global Partner")) return; - if (sessionParameters.partnerParameters == null) { - sessionParameters.partnerParameters = new LinkedHashMap(); + if (globalParameters.partnerParameters == null) { + globalParameters.partnerParameters = new LinkedHashMap(); } - String oldValue = sessionParameters.partnerParameters.get(key); + String oldValue = globalParameters.partnerParameters.get(key); if (value.equals(oldValue)) { logger.verbose("Key %s already present with the same value", key); @@ -2295,20 +2977,20 @@ public void addSessionPartnerParameterI(String key, String value) { logger.warn("Key %s will be overwritten", key); } - sessionParameters.partnerParameters.put(key, value); + globalParameters.partnerParameters.put(key, value); - writeSessionPartnerParametersI(); + writeGlobalPartnerParametersI(); } - public void removeSessionCallbackParameterI(String key) { + public void removeGlobalCallbackParameterI(String key) { if (!Util.isValidParameter(key, "key", "Session Callback")) return; - if (sessionParameters.callbackParameters == null) { + if (globalParameters.callbackParameters == null) { logger.warn("Session Callback parameters are not set"); return; } - String oldValue = sessionParameters.callbackParameters.remove(key); + String oldValue = globalParameters.callbackParameters.remove(key); if (oldValue == null) { logger.warn("Key %s does not exist", key); @@ -2317,18 +2999,18 @@ public void removeSessionCallbackParameterI(String key) { logger.debug("Key %s will be removed", key); - writeSessionCallbackParametersI(); + writeGlobalCallbackParametersI(); } - public void removeSessionPartnerParameterI(String key) { + public void removeGlobalPartnerParameterI(String key) { if (!Util.isValidParameter(key, "key", "Session Partner")) return; - if (sessionParameters.partnerParameters == null) { + if (globalParameters.partnerParameters == null) { logger.warn("Session Partner parameters are not set"); return; } - String oldValue = sessionParameters.partnerParameters.remove(key); + String oldValue = globalParameters.partnerParameters.remove(key); if (oldValue == null) { logger.warn("Key %s does not exist", key); @@ -2337,27 +3019,27 @@ public void removeSessionPartnerParameterI(String key) { logger.debug("Key %s will be removed", key); - writeSessionPartnerParametersI(); + writeGlobalPartnerParametersI(); } - public void resetSessionCallbackParametersI() { - if (sessionParameters.callbackParameters == null) { + public void removeGlobalCallbackParametersI() { + if (globalParameters.callbackParameters == null) { logger.warn("Session Callback parameters are not set"); } - sessionParameters.callbackParameters = null; + globalParameters.callbackParameters = null; - writeSessionCallbackParametersI(); + writeGlobalCallbackParametersI(); } - public void resetSessionPartnerParametersI() { - if (sessionParameters.partnerParameters == null) { + public void removeGlobalPartnerParametersI() { + if (globalParameters.partnerParameters == null) { logger.warn("Session Partner parameters are not set"); } - sessionParameters.partnerParameters = null; + globalParameters.partnerParameters = null; - writeSessionPartnerParametersI(); + writeGlobalPartnerParametersI(); } private void setPushTokenI(String token) { @@ -2373,7 +3055,8 @@ private void setPushTokenI(String token) { writeActivityStateI(); long now = System.currentTimeMillis(); - PackageBuilder infoPackageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder infoPackageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); infoPackageBuilder.internalState = internalState; ActivityPackage infoPackage = infoPackageBuilder.buildInfoPackage(Constants.PUSH); @@ -2382,11 +3065,7 @@ private void setPushTokenI(String token) { // If push token was cached, remove it. SharedPreferencesManager.getDefaultInstance(getContext()).removePushToken(); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", infoPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } + packageHandler.sendFirstPackage(); } private void gdprForgetMeI() { @@ -2398,7 +3077,8 @@ private void gdprForgetMeI() { writeActivityStateI(); long now = System.currentTimeMillis(); - PackageBuilder gdprPackageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder gdprPackageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); gdprPackageBuilder.internalState = internalState; ActivityPackage gdprPackage = gdprPackageBuilder.buildGdprPackage(); @@ -2407,113 +3087,74 @@ private void gdprForgetMeI() { // If GDPR choice was cached, remove it. SharedPreferencesManager.getDefaultInstance(getContext()).removeGdprForgetMe(); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", gdprPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } + packageHandler.sendFirstPackage(); } - private void disableThirdPartySharingI() { - // cache the disable third party sharing request, so that the request order maintains - // even this call returns before making server request - SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(getContext()); - sharedPreferencesManager.setDisableThirdPartySharing(); - - if (!checkActivityStateI(activityState)) { return; } - if (!isEnabledI()) { return; } - if (activityState.isGdprForgotten) { return; } - if (activityState.isThirdPartySharingDisabled) { return; } - if (adjustConfig.coppaCompliantEnabled) { - logger.warn("Call to disable third party sharing API ignored, already done when COPPA enabled"); + public void tryTrackThirdPartySharingI(final AdjustThirdPartySharing adjustThirdPartySharing) { + if (canTrackThirdPartySharingI()) { + trackThirdPartySharingI(adjustThirdPartySharing); return; } - activityState.isThirdPartySharingDisabled = true; - writeActivityStateI(); - - long now = System.currentTimeMillis(); - PackageBuilder packageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); - packageBuilder.internalState = internalState; - - ActivityPackage activityPackage = packageBuilder.buildDisableThirdPartySharingPackage(); - packageHandler.addPackage(activityPackage); - - // Removed the cached disable third party sharing flag. - sharedPreferencesManager.removeDisableThirdPartySharing(); - - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", activityPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); + if (cachedAdjustThirdPartySharingArray == null) { + cachedAdjustThirdPartySharingArray = new ArrayList<>(); } + + cachedAdjustThirdPartySharingArray.add(adjustThirdPartySharing); } - private void trackThirdPartySharingI(final AdjustThirdPartySharing adjustThirdPartySharing) { - if (!checkActivityStateI(activityState)) { - adjustConfig.preLaunchActions.preLaunchAdjustThirdPartySharingArray.add( - adjustThirdPartySharing); - return; - } - if (!isEnabledI()) { return; } - if (activityState.isGdprForgotten) { return; } - if (adjustConfig.coppaCompliantEnabled) { + private boolean canTrackThirdPartySharingI() { + if (!checkActivityStateI(activityState)) {return false;} + if (!isEnabledI()) { return false; } + if (activityState.isGdprForgotten) { return false; } + if (adjustConfig.coppaComplianceEnabled) { logger.warn("Calling third party sharing API not allowed when COPPA enabled"); - return; + return false; } + return true; + } + + private void trackThirdPartySharingI(final AdjustThirdPartySharing adjustThirdPartySharing) { long now = System.currentTimeMillis(); PackageBuilder packageBuilder = new PackageBuilder( - adjustConfig, deviceInfo, activityState, sessionParameters, now); + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); packageBuilder.internalState = internalState; ActivityPackage activityPackage = packageBuilder.buildThirdPartySharingPackage(adjustThirdPartySharing); packageHandler.addPackage(activityPackage); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", activityPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } + packageHandler.sendFirstPackage(); } - private void trackMeasurementConsentI(final boolean consentMeasurement) { - if (!checkActivityStateI(activityState)) { - adjustConfig.preLaunchActions.lastMeasurementConsentTracked = consentMeasurement; + public void tryTrackMeasurementConsentI(final boolean consentMeasurement) { + if (canTrackMeasurementConsentI()) { + trackMeasurementConsentI(consentMeasurement); return; } - if (!isEnabledI()) { return; } - if (activityState.isGdprForgotten) { return; } + cachedLastMeasurementConsentTrack = consentMeasurement; + } + + private boolean canTrackMeasurementConsentI() { + if (!checkActivityStateI(activityState)) { return false; } + if (!isEnabledI()) { return false; } + if (activityState.isGdprForgotten) { return false; } + + return true; + } + + private void trackMeasurementConsentI(final boolean consentMeasurement) { long now = System.currentTimeMillis(); PackageBuilder packageBuilder = new PackageBuilder( - adjustConfig, deviceInfo, activityState, sessionParameters, now); + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); packageBuilder.internalState = internalState; ActivityPackage activityPackage = packageBuilder.buildMeasurementConsentPackage(consentMeasurement); packageHandler.addPackage(activityPackage); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", activityPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } - } - - private void trackAdRevenueI(String source, JSONObject adRevenueJson) { - if (!checkActivityStateI(activityState)) { return; } - if (!isEnabledI()) { return; } - if (activityState.isGdprForgotten) { return; } - - long now = System.currentTimeMillis(); - - PackageBuilder packageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); - packageBuilder.internalState = internalState; - - ActivityPackage adRevenuePackage = packageBuilder.buildAdRevenuePackage(source, adRevenueJson); - packageHandler.addPackage(adRevenuePackage); packageHandler.sendFirstPackage(); } @@ -2525,40 +3166,45 @@ private void trackAdRevenueI(AdjustAdRevenue adjustAdRevenue) { long now = System.currentTimeMillis(); - PackageBuilder packageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder packageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); packageBuilder.internalState = internalState; - ActivityPackage adRevenuePackage = packageBuilder.buildAdRevenuePackage(adjustAdRevenue, internalState.isInDelayedStart()); + ActivityPackage adRevenuePackage = packageBuilder.buildAdRevenuePackage(adjustAdRevenue); packageHandler.addPackage(adRevenuePackage); packageHandler.sendFirstPackage(); } - private void trackSubscriptionI(final AdjustPlayStoreSubscription subscription) { + private void trackPlayStoreSubscriptionI(final AdjustPlayStoreSubscription subscription) { if (!checkActivityStateI(activityState)) { return; } if (!isEnabledI()) { return; } if (activityState.isGdprForgotten) { return; } long now = System.currentTimeMillis(); - PackageBuilder packageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder packageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); packageBuilder.internalState = internalState; - ActivityPackage subscriptionPackage = packageBuilder.buildSubscriptionPackage(subscription, internalState.isInDelayedStart()); + ActivityPackage subscriptionPackage = packageBuilder.buildSubscriptionPackage(subscription); packageHandler.addPackage(subscriptionPackage); packageHandler.sendFirstPackage(); } - private void verifyPurchaseI(final AdjustPurchase purchase, final OnPurchaseVerificationFinishedListener callback) { + private void verifyPlayStorePurchaseI(final AdjustPlayStorePurchase purchase, + final OnPurchaseVerificationFinishedListener callback) { if (callback == null) { logger.warn("Purchase verification aborted because verification callback is null"); return; } // from this moment on we know that we can ping client callback in case of error - if (adjustConfig.urlStrategy != null && - (adjustConfig.urlStrategy.equals(AdjustConfig.DATA_RESIDENCY_EU) || - adjustConfig.urlStrategy.equals(AdjustConfig.DATA_RESIDENCY_US) || - adjustConfig.urlStrategy.equals(AdjustConfig.DATA_RESIDENCY_TR))) { + if (adjustConfig.isDataResidency) { logger.warn("Purchase verification not available for data residency users right now"); + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 109, + "Purchase verification not available for data residency users right now"); + callback.onVerificationFinished(result); return; } if (!checkActivityStateI(activityState)) { @@ -2600,7 +3246,8 @@ private void verifyPurchaseI(final AdjustPurchase purchase, final OnPurchaseVeri } long now = System.currentTimeMillis(); - PackageBuilder packageBuilder = new PackageBuilder(adjustConfig, deviceInfo, activityState, sessionParameters, now); + PackageBuilder packageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); packageBuilder.internalState = internalState; ActivityPackage verificationPackage = packageBuilder.buildVerificationPackage(purchase, callback); @@ -2617,6 +3264,78 @@ private void verifyPurchaseI(final AdjustPurchase purchase, final OnPurchaseVeri purchaseVerificationHandler.sendPurchaseVerificationPackage(verificationPackage); } + private void verifyAndTrackPlayStorePurchaseI(final AdjustEvent event, + final OnPurchaseVerificationFinishedListener callback) { + if (callback == null) { + logger.warn("Purchase verification aborted because verification callback is null"); + return; + } + // from this moment on we know that we can ping client callback in case of error + if (adjustConfig.isDataResidency) { + logger.warn("Purchase verification not available for data residency users right now"); + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 109, + "Purchase verification not available for data residency users right now"); + callback.onVerificationFinished(result); + return; + } + if (!checkActivityStateI(activityState)) { + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 102, + "Purchase verification aborted because SDK is still not initialized"); + callback.onVerificationFinished(result); + logger.warn("Purchase verification aborted because SDK is still not initialized"); + return; + } + if (!isEnabledI()) { + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 103, + "Purchase verification aborted because SDK is disabled"); + callback.onVerificationFinished(result); + logger.warn("Purchase verification aborted because SDK is disabled"); + return; + } + if (activityState.isGdprForgotten) { + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 104, + "Purchase verification aborted because user is GDPR forgotten"); + callback.onVerificationFinished(result); + logger.warn("Purchase verification aborted because user is GDPR forgotten"); + return; + } + if (event == null) { + logger.warn("Purchase verification aborted because event instance is null"); + AdjustPurchaseVerificationResult verificationResult = + new AdjustPurchaseVerificationResult( + "not_verified", + 106, + "Purchase verification aborted because event instance is null"); + callback.onVerificationFinished(verificationResult); + return; + } + + long now = System.currentTimeMillis(); + PackageBuilder packageBuilder = new PackageBuilder( + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); + ActivityPackage verificationPackage = packageBuilder.buildVerificationPackage(event, callback); + if (verificationPackage == null) { + logger.warn("Purchase verification aborted because verification package is null"); + AdjustPurchaseVerificationResult verificationResult = + new AdjustPurchaseVerificationResult( + "not_verified", + 107, + "Purchase verification aborted because verification package is null"); + callback.onVerificationFinished(verificationResult); + return; + } + verificationPackage.event = event; + purchaseVerificationHandler.sendPurchaseVerificationPackage(verificationPackage); + } + private void gotOptOutResponseI() { activityState.isGdprForgotten = true; writeActivityStateI(); @@ -2632,9 +3351,6 @@ private void readActivityStateI(Context context) { logger.error("Failed to read %s file (%s)", ACTIVITY_STATE_NAME, e.getMessage()); activityState = null; } - if (activityState != null) { - internalState.firstSdkStart = true; - } } private void readAttributionI(Context context) { @@ -2646,29 +3362,45 @@ private void readAttributionI(Context context) { } } + private void readEventMetadataI(Context context) { + try { + eventMetadata = Util.readObject(context, EVENT_METADATA_FILENAME, EVENT_METADATA_NAME, EventMetadata.class); + } catch (Exception e) { + logger.error("Failed to read %s file (%s)", EVENT_METADATA_NAME, e.getMessage()); + } + + if (eventMetadata == null) { + eventMetadata = new EventMetadata(); + } + } + + private void readThirdPartySharingResultI(final Context context) { + thirdPartySharingResult = SharedPreferencesManager.getDefaultInstance(context).getThirdPartySharingResult(); + } + @SuppressWarnings("unchecked") - private void readSessionCallbackParametersI(Context context) { + private void readGlobalCallbackParametersI(Context context) { try { - sessionParameters.callbackParameters = Util.readObject(context, - SESSION_CALLBACK_PARAMETERS_FILENAME, - SESSION_CALLBACK_PARAMETERS_NAME, + globalParameters.callbackParameters = Util.readObject(context, + GLOBAL_CALLBACK_PARAMETERS_FILENAME, + GLOBAL_CALLBACK_PARAMETERS_NAME, (Class>)(Class)Map.class); } catch (Exception e) { - logger.error("Failed to read %s file (%s)", SESSION_CALLBACK_PARAMETERS_NAME, e.getMessage()); - sessionParameters.callbackParameters = null; + logger.error("Failed to read %s file (%s)", GLOBAL_CALLBACK_PARAMETERS_NAME, e.getMessage()); + globalParameters.callbackParameters = null; } } @SuppressWarnings("unchecked") - private void readSessionPartnerParametersI(Context context) { + private void readGlobalPartnerParametersI(Context context) { try { - sessionParameters.partnerParameters = Util.readObject(context, - SESSION_PARTNER_PARAMETERS_FILENAME, - SESSION_PARTNER_PARAMETERS_NAME, + globalParameters.partnerParameters = Util.readObject(context, + GLOBAL_PARTNER_PARAMETERS_FILENAME, + GLOBAL_PARTNER_PARAMETERS_NAME, (Class>)(Class)Map.class); } catch (Exception e) { - logger.error("Failed to read %s file (%s)", SESSION_PARTNER_PARAMETERS_NAME, e.getMessage()); - sessionParameters.partnerParameters = null; + logger.error("Failed to read %s file (%s)", GLOBAL_PARTNER_PARAMETERS_NAME, e.getMessage()); + globalParameters.partnerParameters = null; } } @@ -2708,30 +3440,49 @@ private void teardownAttributionS() { } } - private void writeSessionCallbackParametersI() { - synchronized (SessionParameters.class) { - if (sessionParameters == null) { + private void writeGlobalCallbackParametersI() { + synchronized (GlobalParameters.class) { + if (globalParameters == null) { + return; + } + Util.writeObject(globalParameters.callbackParameters, adjustConfig.context, GLOBAL_CALLBACK_PARAMETERS_FILENAME, GLOBAL_CALLBACK_PARAMETERS_NAME); + } + } + + private void writeGlobalPartnerParametersI() { + synchronized (GlobalParameters.class) { + if (globalParameters == null) { + return; + } + Util.writeObject(globalParameters.partnerParameters, adjustConfig.context, GLOBAL_PARTNER_PARAMETERS_FILENAME, GLOBAL_PARTNER_PARAMETERS_NAME); + } + } + + + private void teardownAllGlobalParametersS() { + synchronized (GlobalParameters.class) { + if (globalParameters == null) { return; } - Util.writeObject(sessionParameters.callbackParameters, adjustConfig.context, SESSION_CALLBACK_PARAMETERS_FILENAME, SESSION_CALLBACK_PARAMETERS_NAME); + globalParameters = null; } } - private void writeSessionPartnerParametersI() { - synchronized (SessionParameters.class) { - if (sessionParameters == null) { + private void writeEventMetadataI() { + synchronized (EventMetadata.class) { + if (eventMetadata == null) { return; } - Util.writeObject(sessionParameters.partnerParameters, adjustConfig.context, SESSION_PARTNER_PARAMETERS_FILENAME, SESSION_PARTNER_PARAMETERS_NAME); + Util.writeObject(eventMetadata, adjustConfig.context, EVENT_METADATA_FILENAME, EVENT_METADATA_NAME); } } - private void teardownAllSessionParametersS() { - synchronized (SessionParameters.class) { - if (sessionParameters == null) { + private void teardownEventMetadataS() { + synchronized (EventMetadata.class) { + if (eventMetadata == null) { return; } - sessionParameters = null; + eventMetadata = null; } } @@ -2749,18 +3500,18 @@ private boolean checkEventI(AdjustEvent event) { return true; } - private boolean checkOrderIdI(String orderId) { - if (orderId == null || orderId.isEmpty()) { - return true; // no order ID given + private boolean shouldProcessEventI(String deduplicationId) { + if (deduplicationId == null || deduplicationId.isEmpty()) { + return true; // no deduplication ID given } - if (activityState.findOrderId(orderId)) { - logger.info("Skipping duplicated order ID '%s'", orderId); - return false; // order ID found -> used already + if (activityState.eventDeduplicationIdExists(deduplicationId)) { + logger.info("Skipping duplicate event with deduplication ID '%s'", deduplicationId); + return false; // deduplication ID found -> used already } - activityState.addOrderId(orderId); - logger.verbose("Added order ID '%s'", orderId); + activityState.addDeduplicationId(deduplicationId); + logger.verbose("Added deduplication ID '%s'", deduplicationId); // activity state will get written by caller return true; } @@ -2780,7 +3531,7 @@ private boolean checkAdjustAdRevenue(AdjustAdRevenue adjustAdRevenue) { } private boolean checkActivityStateI(ActivityState activityState) { - if (internalState.hasFirstSdkStartNotOcurred()) { + if (activityState == null) { logger.error("Sdk did not yet start"); return false; } @@ -2799,8 +3550,7 @@ private boolean pausedI(boolean sdkClickHandlerOnly) { } // other handlers are paused if either: return internalState.isOffline() || // it's offline - !isEnabledI() || // is disabled - internalState.isInDelayedStart(); // is in delayed start + !isEnabledI(); // is disabled } private boolean toSendI() { @@ -2814,7 +3564,7 @@ private boolean toSendI(boolean sdkClickHandlerOnly) { } // has the option to send in the background -> is to send - if (adjustConfig.sendInBackground) { + if (adjustConfig.isSendingInBackgroundEnabled) { return true; } @@ -2920,7 +3670,7 @@ private void checkForInstallReferrerInfo(final SdkClickResponseData responseData } private void processCoppaComplianceI() { - if (!adjustConfig.coppaCompliantEnabled) { + if (!adjustConfig.coppaComplianceEnabled) { resetThirdPartySharingCoppaActivityStateI(); return; } @@ -2940,21 +3690,17 @@ private void disableThirdPartySharingForCoppaEnabledI() { long now = System.currentTimeMillis(); PackageBuilder packageBuilder = new PackageBuilder( - adjustConfig, deviceInfo, activityState, sessionParameters, now); - packageBuilder.internalState = internalState; + adjustConfig, deviceInfo, activityState, globalParameters, firstSessionDelayManager, now); ActivityPackage activityPackage = packageBuilder.buildThirdPartySharingPackage(adjustThirdPartySharing); packageHandler.addPackage(activityPackage); - if (adjustConfig.eventBufferingEnabled) { - logger.info("Buffered event %s", activityPackage.getSuffix()); - } else { - packageHandler.sendFirstPackage(); - } + packageHandler.sendFirstPackage(); } private void resetThirdPartySharingCoppaActivityStateI() { + if (activityState == null) { return; } if (activityState.isThirdPartySharingDisabledForCoppa) { activityState.isThirdPartySharingDisabledForCoppa = false; diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java index 09c9af098..ebee2f705 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityKind.java @@ -30,8 +30,6 @@ public static ActivityKind fromString(String string) { return INFO; } else if ("gdpr".equals(string)) { return GDPR; - } else if ("disable_third_party_sharing".equals(string)) { - return DISABLE_THIRD_PARTY_SHARING; } else if ("ad_revenue".equals(string)) { return AD_REVENUE; } else if ("subscription".equals(string)) { @@ -62,8 +60,6 @@ public String toString() { return "info"; case GDPR: return "gdpr"; - case DISABLE_THIRD_PARTY_SHARING: - return "disable_third_party_sharing"; case AD_REVENUE: return "ad_revenue"; case SUBSCRIPTION: diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java index b088db476..5b8b406fe 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityPackage.java @@ -72,6 +72,8 @@ public class ActivityPackage implements Serializable { private int lastErrorCode; private double waitBeforeSendTimeSeconds; + public transient AdjustEvent event; + public String getPath() { return path; } @@ -220,7 +222,7 @@ public String getExtendedString() { if (parameters != null) { builder.append("Parameters:"); SortedMap sortedParameters = new TreeMap(parameters); - List stringsToExclude = Arrays.asList("app_secret", "secret_id", "adj_signing_id"); + List stringsToExclude = Arrays.asList("secret_id", "adj_signing_id"); for (Map.Entry entry : sortedParameters.entrySet() ) { String key = entry.getKey(); if (stringsToExclude.contains(key)) { @@ -279,7 +281,7 @@ private void readObject(ObjectInputStream stream) throws ClassNotFoundException, suffix = Util.readStringField(fields, "suffix", null); callbackParameters = Util.readObjectField(fields, "callbackParameters", null); partnerParameters = Util.readObjectField(fields, "partnerParameters", null); - retryCount = Util.readIntField(fields, "errorCount", 0); + retryCount = Util.readIntField(fields, "retryCount", 0); firstErrorCode = Util.readIntField(fields, "firstErrorCode", 0); lastErrorCode = Util.readIntField(fields, "lastErrorCode", 0); waitBeforeSendTimeSeconds = Util.readDoubleField(fields, "waitBeforeSendTimeSeconds", 0.0); diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java index df170f05f..c080347d5 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ActivityState.java @@ -20,14 +20,13 @@ public class ActivityState implements Serializable, Cloneable { private static final long serialVersionUID = 9039439291143138148L; - private static final int ORDER_ID_MAXCOUNT = 10; + private static final int EVENT_DEDUPLICATION_IDS_MAX_SIZE = 10; private transient ILogger logger; @SuppressWarnings("unchecked") private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("uuid", String.class), new ObjectStreamField("enabled", boolean.class), new ObjectStreamField("isGdprForgotten", boolean.class), - new ObjectStreamField("isThirdPartySharingDisabled", boolean.class), new ObjectStreamField("askingAttribution", boolean.class), new ObjectStreamField("eventCount", int.class), new ObjectStreamField("sessionCount", int.class), @@ -36,7 +35,6 @@ public class ActivityState implements Serializable, Cloneable { new ObjectStreamField("timeSpent", long.class), new ObjectStreamField("lastActivity", long.class), new ObjectStreamField("lastInterval", long.class), - new ObjectStreamField("updatePackages", boolean.class), new ObjectStreamField("orderIds", (Class>)(Class) LinkedList.class), new ObjectStreamField("pushToken", String.class), new ObjectStreamField("adid", String.class), @@ -74,7 +72,6 @@ public class ActivityState implements Serializable, Cloneable { protected String uuid; protected boolean enabled; protected boolean isGdprForgotten; - protected boolean isThirdPartySharingDisabled; protected boolean isThirdPartySharingDisabledForCoppa; protected boolean askingAttribution; @@ -90,9 +87,8 @@ public class ActivityState implements Serializable, Cloneable { protected long lastInterval; - protected boolean updatePackages; - protected LinkedList orderIds; + protected int eventDeduplicationIdsMaxSize; protected String pushToken; protected String adid; @@ -136,7 +132,6 @@ protected ActivityState() { uuid = Util.createUuid(); enabled = true; isGdprForgotten = false; - isThirdPartySharingDisabled = false; isThirdPartySharingDisabledForCoppa = false; askingAttribution = false; eventCount = 0; // no events yet @@ -146,7 +141,6 @@ protected ActivityState() { timeSpent = -1; // this information will be collected and attached to the next session lastActivity = -1; lastInterval = -1; - updatePackages = false; orderIds = null; pushToken = null; adid = null; @@ -177,6 +171,7 @@ protected ActivityState() { installReferrerMeta = null; clickTimeMeta = 0; isClickMeta = null; + eventDeduplicationIdsMaxSize = EVENT_DEDUPLICATION_IDS_MAX_SIZE; } protected void resetSessionAttributes(long now) { @@ -187,22 +182,32 @@ protected void resetSessionAttributes(long now) { lastInterval = -1; } - protected void addOrderId(String orderId) { - if (orderIds == null) { - orderIds = new LinkedList(); + protected void addDeduplicationId(String deduplicationId) { + if (eventDeduplicationIdsMaxSize == 0) { + return; } - if (orderIds.size() >= ORDER_ID_MAXCOUNT) { - orderIds.removeLast(); + if (orderIds == null) { + orderIds = new LinkedList(); + } else { + while (orderIds.size() >= eventDeduplicationIdsMaxSize) { + orderIds.removeLast(); + } } - orderIds.addFirst(orderId); + orderIds.addFirst(deduplicationId); } - protected boolean findOrderId(String orderId) { + protected boolean eventDeduplicationIdExists(String deduplicationId) { if (orderIds == null) { return false; } - return orderIds.contains(orderId); + return orderIds.contains(deduplicationId); + } + + protected void setEventDeduplicationIdsMaxSize(Integer size) { + if (size != null && size >= 0) { + eventDeduplicationIdsMaxSize = size; + } } @Override @@ -223,7 +228,6 @@ public boolean equals(Object other) { if (!Util.equalString(uuid, otherActivityState.uuid)) return false; if (!Util.equalBoolean(enabled, otherActivityState.enabled)) return false; if (!Util.equalBoolean(isGdprForgotten, otherActivityState.isGdprForgotten)) return false; - if (!Util.equalBoolean(isThirdPartySharingDisabled, otherActivityState.isThirdPartySharingDisabled)) return false; if (!Util.equalBoolean(isThirdPartySharingDisabledForCoppa, otherActivityState.isThirdPartySharingDisabledForCoppa)) return false; if (!Util.equalBoolean(askingAttribution, otherActivityState.askingAttribution)) return false; if (!Util.equalInt(eventCount, otherActivityState.eventCount)) return false; @@ -232,7 +236,6 @@ public boolean equals(Object other) { if (!Util.equalLong(sessionLength, otherActivityState.sessionLength)) return false; if (!Util.equalLong(timeSpent, otherActivityState.timeSpent)) return false; if (!Util.equalLong(lastInterval, otherActivityState.lastInterval)) return false; - if (!Util.equalBoolean(updatePackages, otherActivityState.updatePackages)) return false; if (!Util.equalObject(orderIds, otherActivityState.orderIds)) return false; if (!Util.equalString(pushToken, otherActivityState.pushToken)) return false; if (!Util.equalString(adid, otherActivityState.adid)) return false; @@ -272,7 +275,6 @@ public int hashCode() { hashCode = Util.hashString(uuid, hashCode); hashCode = Util.hashBoolean(enabled, hashCode); hashCode = Util.hashBoolean(isGdprForgotten, hashCode); - hashCode = Util.hashBoolean(isThirdPartySharingDisabled, hashCode); hashCode = Util.hashBoolean(isThirdPartySharingDisabledForCoppa, hashCode); hashCode = Util.hashBoolean(askingAttribution, hashCode); hashCode = 37 * hashCode + eventCount; @@ -281,7 +283,6 @@ public int hashCode() { hashCode = Util.hashLong(sessionLength, hashCode); hashCode = Util.hashLong(timeSpent, hashCode); hashCode = Util.hashLong(lastInterval, hashCode); - hashCode = Util.hashBoolean(updatePackages, hashCode); hashCode = Util.hashObject(orderIds, hashCode); hashCode = Util.hashString(pushToken, hashCode); hashCode = Util.hashString(adid, hashCode); @@ -330,11 +331,9 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo uuid = Util.readStringField(fields, "uuid", null); enabled = Util.readBooleanField(fields, "enabled", true); isGdprForgotten = Util.readBooleanField(fields, "isGdprForgotten", false); - isThirdPartySharingDisabled = Util.readBooleanField(fields, "isThirdPartySharingDisabled", false); isThirdPartySharingDisabledForCoppa = Util.readBooleanField(fields, "isThirdPartySharingDisabledForCoppa", false); askingAttribution = Util.readBooleanField(fields, "askingAttribution", false); - updatePackages = Util.readBooleanField(fields, "updatePackages", false); orderIds = Util.readObjectField(fields, "orderIds", null); pushToken = Util.readStringField(fields, "pushToken", null); adid = Util.readStringField(fields, "adid", null); @@ -376,6 +375,8 @@ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFo if (uuid == null) { uuid = Util.createUuid(); } + + eventDeduplicationIdsMaxSize = EVENT_DEDUPLICATION_IDS_MAX_SIZE; } private void writeObject(ObjectOutputStream stream) throws IOException { diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java index 2df015494..4439933bb 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Adjust.java @@ -1,9 +1,6 @@ package com.adjust.sdk; import android.content.Context; -import android.net.Uri; - -import org.json.JSONObject; import java.util.Map; @@ -34,7 +31,7 @@ private Adjust() { */ public static synchronized AdjustInstance getDefaultInstance() { @SuppressWarnings("unused") - String VERSION = "!SDK-VERSION-STRING!:com.adjust.sdk:adjust-android:4.38.5"; + String VERSION = "!SDK-VERSION-STRING!:com.adjust.sdk:adjust-android:5.8.0"; if (defaultInstance == null) { defaultInstance = new AdjustInstance(); @@ -47,9 +44,9 @@ public static synchronized AdjustInstance getDefaultInstance() { * * @param adjustConfig AdjustConfig object used for SDK initialisation */ - public static void onCreate(AdjustConfig adjustConfig) { + public static void initSdk(AdjustConfig adjustConfig) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.onCreate(adjustConfig); + adjustInstance.initSdk(adjustConfig); } /** @@ -79,23 +76,40 @@ public static void onPause() { } /** - * Called to disable/enable SDK. + * Called to enable SDK. * - * @param enabled boolean indicating whether SDK should be enabled or disabled */ - public static void setEnabled(boolean enabled) { + public static void enable() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.setEnabled(enabled); + adjustInstance.enable(); + } + /** + * Called to disable SDK. + * + */ + public static void disable() { + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.disable(); } /** * Get information if SDK is enabled or not. * - * @return boolean indicating whether SDK is enabled or not + * @param context Application context + * @param isEnabledListener Callback to get triggered once information is obtained */ - public static boolean isEnabled() { + public static void isEnabled(final Context context, final OnIsEnabledListener isEnabledListener) { + if (context == null) { + AdjustFactory.getLogger().error("null context"); + return; + } + if (isEnabledListener == null) { + AdjustFactory.getLogger().error("Callback for getting isEnabled can't be null"); + return; + } + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - return adjustInstance.isEnabled(); + adjustInstance.isEnabled(extractApplicationContext(context), isEnabledListener); } /** @@ -108,39 +122,26 @@ public static boolean isAdjustUninstallDetectionPayload(Map payl } /** - * Called to process deep link. - * - * @param url Deep link URL to process - * - * @deprecated Use {@link #appWillOpenUrl(Uri, Context)}} instead. - */ - @Deprecated - public static void appWillOpenUrl(Uri url) { - AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.appWillOpenUrl(url); - } - - /** - * Called to process deep link. + * Called to process deeplink. * - * @param url Deep link URL to process + * @param adjustDeeplink Deeplink object to process * @param context Application context */ - public static void appWillOpenUrl(Uri url, Context context) { + public static void processDeeplink(AdjustDeeplink adjustDeeplink, Context context) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.appWillOpenUrl(url, extractApplicationContext(context)); + adjustInstance.processDeeplink(adjustDeeplink, extractApplicationContext(context)); } /** - * Process the deep link that has opened an app and potentially get a resolved link. + * Process the deeplink that has opened an app and potentially get a resolved link. * - * @param url Deep link URL to process - * @param callback Callback where either resolved or echoed deep link will be sent. + * @param adjustDeeplink Deeplink object to process + * @param callback Callback where either resolved or echoed deeplink will be sent. * @param context Application context */ - public static void processDeeplink(Uri url, Context context, OnDeeplinkResolvedListener callback) { + public static void processAndResolveDeeplink(AdjustDeeplink adjustDeeplink, Context context, OnDeeplinkResolvedListener callback) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.processDeeplink(url, extractApplicationContext(context), callback); + adjustInstance.processAndResolveDeeplink(adjustDeeplink, extractApplicationContext(context), callback); } /** @@ -155,21 +156,20 @@ public static void setReferrer(String referrer, Context context) { } /** - * Called to set SDK to offline or online mode. + * Called to set SDK to offline mode. * - * @param enabled boolean indicating should SDK be in offline mode (true) or not (false) */ - public static void setOfflineMode(boolean enabled) { + public static void switchToOfflineMode() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.setOfflineMode(enabled); + adjustInstance.switchToOfflineMode(); } - /** - * Called if SDK initialisation was delayed and you would like to stop waiting for timer. + * Called to set SDK to online mode. + * */ - public static void sendFirstPackages() { + public static void switchBackToOnlineMode() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.sendFirstPackages(); + adjustInstance.switchBackToOnlineMode(); } /** @@ -178,9 +178,9 @@ public static void sendFirstPackages() { * @param key Global callback parameter key * @param value Global callback parameter value */ - public static void addSessionCallbackParameter(String key, String value) { + public static void addGlobalCallbackParameter(String key, String value) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.addSessionCallbackParameter(key, value); + adjustInstance.addGlobalCallbackParameter(key, value); } /** @@ -189,9 +189,9 @@ public static void addSessionCallbackParameter(String key, String value) { * @param key Global partner parameter key * @param value Global partner parameter value */ - public static void addSessionPartnerParameter(String key, String value) { + public static void addGlobalPartnerParameter(String key, String value) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.addSessionPartnerParameter(key, value); + adjustInstance.addGlobalPartnerParameter(key, value); } /** @@ -199,9 +199,9 @@ public static void addSessionPartnerParameter(String key, String value) { * * @param key Global callback parameter key */ - public static void removeSessionCallbackParameter(String key) { + public static void removeGlobalCallbackParameter(String key) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.removeSessionCallbackParameter(key); + adjustInstance.removeGlobalCallbackParameter(key); } /** @@ -209,36 +209,25 @@ public static void removeSessionCallbackParameter(String key) { * * @param key Global partner parameter key */ - public static void removeSessionPartnerParameter(String key) { + public static void removeGlobalPartnerParameter(String key) { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.removeSessionPartnerParameter(key); + adjustInstance.removeGlobalPartnerParameter(key); } /** * Called to remove all added global callback parameters. */ - public static void resetSessionCallbackParameters() { + public static void removeGlobalCallbackParameters() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.resetSessionCallbackParameters(); + adjustInstance.removeGlobalCallbackParameters(); } /** * Called to remove all added global partner parameters. */ - public static void resetSessionPartnerParameters() { - AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.resetSessionPartnerParameters(); - } - - /** - * Called to set user's push notifications token. - * - * @param token Push notifications token - * @deprecated use {@link #setPushToken(String, Context)} instead. - */ - public static void setPushToken(String token) { + public static void removeGlobalPartnerParameters() { AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.setPushToken(token); + adjustInstance.removeGlobalPartnerParameters(); } /** @@ -262,16 +251,6 @@ public static void gdprForgetMe(final Context context) { adjustInstance.gdprForgetMe(extractApplicationContext(context)); } - /** - * Called to disable the third party sharing. - * - * @param context Application context - */ - public static void disableThirdPartySharing(final Context context) { - AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.disableThirdPartySharing(extractApplicationContext(context)); - } - public static void trackThirdPartySharing( final AdjustThirdPartySharing adjustThirdPartySharing) { @@ -284,17 +263,6 @@ public static void trackMeasurementConsent(final boolean consentMeasurement) { adjustInstance.trackMeasurementConsent(consentMeasurement); } - /** - * Track ad revenue from a source provider - * - * @param source Source of ad revenue information, see AdjustConfig.AD_REVENUE_* for some possible sources - * @param payload JsonObject content of the ad revenue information - */ - public static void trackAdRevenue(final String source, final JSONObject payload) { - AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.trackAdRevenue(source, payload); - } - /** * Track ad revenue from a source provider * @@ -318,61 +286,202 @@ public static void trackPlayStoreSubscription(final AdjustPlayStoreSubscription /** * Called to get value of Google Play Advertising Identifier. * - * @param context Application context - * @param onDeviceIdRead Callback to get triggered once identifier is obtained + * @param context Application context + * @param onGoogleAdIdReadListener Callback to get triggered once identifier is obtained */ - public static void getGoogleAdId(Context context, OnDeviceIdsRead onDeviceIdRead) { - Context appContext = null; - if (context != null) { - appContext = context.getApplicationContext(); + public static void getGoogleAdId(final Context context,final OnGoogleAdIdReadListener onGoogleAdIdReadListener) { + if (onGoogleAdIdReadListener == null) { + AdjustFactory.getLogger().error("onGoogleAdIdReadListener cannot be null"); + return; } - - Util.getGoogleAdId(appContext, onDeviceIdRead); + if (context == null) { + AdjustFactory.getLogger().error("getGoogleAdId: null context"); + return; + } + Util.getGoogleAdId(context.getApplicationContext(), onGoogleAdIdReadListener); } /** * Called to get value of Amazon Advertising Identifier. * - * @param context Application context - * @return Amazon Advertising Identifier + * @param context Application context + * @param onAmazonAdIdReadListener Callback to get triggered once identifier is obtained */ - public static String getAmazonAdId(final Context context) { - Context appContext = extractApplicationContext(context); - if (appContext != null) { - return DeviceInfo.getFireAdvertisingIdBypassConditions(appContext.getContentResolver()); + public static void getAmazonAdId(final Context context,final OnAmazonAdIdReadListener onAmazonAdIdReadListener) { + if (onAmazonAdIdReadListener == null) { + AdjustFactory.getLogger().error("onAmazonAdIdReadListener cannot be null"); + return; } + Context appContext = extractApplicationContext(context); - return null; + if (appContext == null) { + AdjustFactory.getLogger().error("getAmazonAdId: null context"); + return; + } + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getAmazonAdId(appContext, onAmazonAdIdReadListener); } /** * Called to get value of unique Adjust device identifier. * - * @return Unique Adjust device indetifier + * @param onAdidReadListener Callback to get triggered once identifier is obtained. */ - public static String getAdid() { + public static void getAdid(final OnAdidReadListener onAdidReadListener) { + if (onAdidReadListener == null) { + AdjustFactory.getLogger().error("Callback for getting adid can't be null"); + return; + } AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - return adjustInstance.getAdid(); + adjustInstance.getAdid(onAdidReadListener); + } + + /** + * Called to get value of unique Adjust device identifier with a timeout + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. If adid is not available within this time, + * the callback will return null adid. + * @param onAdidReadListener Callback to get triggered once identifier is obtained. + */ + public static void getAdidWithTimeout(final Context context, final long timeoutInMilliSec, + final OnAdidReadListener onAdidReadListener) { + if (context == null) { + AdjustFactory.getLogger().error("Context for getting adid can't be null"); + return; + } + if (timeoutInMilliSec < 0) { + AdjustFactory.getLogger().error("Timeout value for getting adid can't be negative"); + return; + } + if (onAdidReadListener == null) { + AdjustFactory.getLogger().error("Callback for getting adid can't be null"); + return; + } + + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getAdidWithTimeout(extractApplicationContext(context), timeoutInMilliSec, onAdidReadListener); } /** * Called to get user's current attribution value. * - * @return AdjustAttribution object with current attribution value + * @param attributionReadListener Callback to get triggered once attribution is obtained + */ + public static void getAttribution(final OnAttributionReadListener attributionReadListener) { + if (attributionReadListener == null) { + AdjustFactory.getLogger().error("Callback for getting attribution can't be null"); + return; + } + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getAttribution(attributionReadListener); + } + + /** + * Called to get user's current attribution value. + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. If attribution is not available within this time, + * the callback will return null attribution. + * @param attributionReadListener Callback to get triggered once attribution is obtained + */ + public static void getAttributionWithTimeout(final Context context, final long timeoutInMilliSec, + final OnAttributionReadListener attributionReadListener) { + if (context == null) { + AdjustFactory.getLogger().error("Context for getting attribution can't be null"); + return; + } + if (timeoutInMilliSec < 0) { + AdjustFactory.getLogger().error("Timeout value for getting attribution can't be negative"); + return; + } + if (attributionReadListener == null) { + AdjustFactory.getLogger().error("Callback for getting attribution can't be null"); + return; + } + + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getAttributionWithTimeout(extractApplicationContext(context), timeoutInMilliSec, attributionReadListener); + } + + /** + * Called to get user's current third party sharing settings. + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. If third party sharing settings + * are not available within this time, the callback will return null. + * @param listener Callback to get triggered once third party sharing settings are obtained + */ + public static void getThirdPartySharingSettingsWithTimeout(final Context context, final long timeoutInMilliSec, + final OnThirdPartySharingSettingsReadListener listener) { + if (listener == null) { + AdjustFactory.getLogger().error("Callback for getting third party sharing settings can't be null"); + return; + } + if (context == null) { + AdjustFactory.getLogger().error("Context for getting third party sharing settings can't be null"); + listener.onThirdPartySharingSettingsRead(null); + return; + } + if (timeoutInMilliSec < 0) { + AdjustFactory.getLogger().error("Timeout value for getting third party sharing settings can't be negative"); + listener.onThirdPartySharingSettingsRead(null); + return; + } + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getThirdPartySharingSettingsWithTimeout(extractApplicationContext(context), timeoutInMilliSec, listener); + } + + /** + * Called to get Google Install Referrer. + * + * @param context Application context + * @param onGooglePlayInstallReferrerReadListener Callback to obtain install referrer. + */ + public static void getGooglePlayInstallReferrer(final Context context, final OnGooglePlayInstallReferrerReadListener onGooglePlayInstallReferrerReadListener) { + if (onGooglePlayInstallReferrerReadListener == null) { + AdjustFactory.getLogger().error("onGooglePlayInstallReferrerReadListener cannot be null"); + return; + } + if (context == null) { + AdjustFactory.getLogger().error("null context"); + return; + } + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.getGooglePlayInstallReferrer(context ,onGooglePlayInstallReferrerReadListener); + } + + /** + * Called to get last opened deeplink. + * + * @param context Application context + * @param onLastDeeplinkReadListener Callback to obtain last opened deeplink. */ - public static AdjustAttribution getAttribution() { + public static void getLastDeeplink(final Context context, final OnLastDeeplinkReadListener onLastDeeplinkReadListener) { + if (onLastDeeplinkReadListener == null) { + AdjustFactory.getLogger().error("onLastDeeplinkReadListener cannot be null"); + return; + } + if (context == null) { + AdjustFactory.getLogger().error("null context"); + return; + } AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - return adjustInstance.getAttribution(); + adjustInstance.getLastDeeplink(context, onLastDeeplinkReadListener); } /** * Called to get native SDK version string. * - * @return Native SDK version string. + * @param onSdkVersionReadListener Callback to get triggered once SDK version is obtained */ - public static String getSdkVersion() { + public static void getSdkVersion(final OnSdkVersionReadListener onSdkVersionReadListener) { + if (onSdkVersionReadListener == null) { + AdjustFactory.getLogger().error("onSdkVersionReadListener cannot be null"); + return; + } AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - return adjustInstance.getSdkVersion(); + adjustInstance.getSdkVersion(onSdkVersionReadListener); } /** @@ -381,9 +490,79 @@ public static String getSdkVersion() { * @param purchase AdjustPurchase object to be tracked * @param callback Callback to obtain verification results */ - public static void verifyPurchase(final AdjustPurchase purchase, OnPurchaseVerificationFinishedListener callback) { + public static void verifyPlayStorePurchase(final AdjustPlayStorePurchase purchase, + final OnPurchaseVerificationFinishedListener callback) { + if (callback == null) { + AdjustFactory.getLogger().error("Purchase verification aborted because verification callback is null"); + return; + } AdjustInstance adjustInstance = Adjust.getDefaultInstance(); - adjustInstance.verifyPurchase(purchase, callback); + adjustInstance.verifyPlayStorePurchase(purchase, callback); + } + + /** + * Verify in app purchase from Google Play and track Adjust event associated with it. + * + * @param event AdjustEvent object to be tracked + * @param callback Callback to obtain verification results + */ + public static void verifyAndTrackPlayStorePurchase(final AdjustEvent event, OnPurchaseVerificationFinishedListener callback) { + AdjustInstance adjustInstance = Adjust.getDefaultInstance(); + adjustInstance.verifyAndTrackPlayStorePurchase(event, callback); + } + + /** + * Called to end the delay for first session to be sent to Adjust. + * + */ + public static void endFirstSessionDelay() { + Adjust.getDefaultInstance().endFirstSessionDelay(); + } + + /** + * Called to enable COPPA (Children's Online Privacy Protection Act) compliance + * for the application when is in first session delay. + * + */ + public static void enableCoppaComplianceInDelay() { + Adjust.getDefaultInstance().enableCoppaComplianceInDelay(); + } + + /** + * Called to disable COPPA (Children's Online Privacy Protection Act) compliance + * for the application when is in first session delay. + * + */ + public static void disableCoppaComplianceInDelay() { + Adjust.getDefaultInstance().disableCoppaComplianceInDelay(); + } + + /** + * Called to enable Play Store Kids App compliance for the application + * when is in first session delay. + * + */ + public static void enablePlayStoreKidsComplianceInDelay() { + Adjust.getDefaultInstance().enablePlayStoreKidsComplianceInDelay(); + } + + /** + * Called to disable Play Store Kids App compliance for the application + * when is in first session delay. + * + */ + public static void disablePlayStoreKidsComplianceInDelay() { + Adjust.getDefaultInstance().disablePlayStoreKidsComplianceInDelay(); + } + + /** + * Called to set a custom defined unique device ID (optional) when is in first session delay. + * Note: Make sure to have a UNIQUE external ID for each user / device. + * + * @param externalDeviceId External device ID + */ + public static void setExternalDeviceIdInDelay(final String externalDeviceId) { + Adjust.getDefaultInstance().setExternalDeviceIdInDelay(externalDeviceId); } /** diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java index 8846dfc96..6323d2b11 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustAttribution.java @@ -23,11 +23,11 @@ public class AdjustAttribution implements Serializable { new ObjectStreamField("adgroup", String.class), new ObjectStreamField("creative", String.class), new ObjectStreamField("clickLabel", String.class), - new ObjectStreamField("adid", String.class), new ObjectStreamField("costType", String.class), new ObjectStreamField("costAmount", Double.class), new ObjectStreamField("costCurrency", String.class), new ObjectStreamField("fbInstallReferrer", String.class), + new ObjectStreamField("jsonResponse", String.class), }; public String trackerToken; @@ -37,49 +37,11 @@ public class AdjustAttribution implements Serializable { public String adgroup; public String creative; public String clickLabel; - public String adid; public String costType; public Double costAmount; public String costCurrency; public String fbInstallReferrer; - - public static AdjustAttribution fromJson(JSONObject jsonObject, String adid, String sdkPlatform) { - if (jsonObject == null) return null; - - AdjustAttribution attribution = new AdjustAttribution(); - - if ("unity".equals(sdkPlatform)) { - // Unity platform. - attribution.trackerToken = jsonObject.optString("tracker_token", ""); - attribution.trackerName = jsonObject.optString("tracker_name", ""); - attribution.network = jsonObject.optString("network", ""); - attribution.campaign = jsonObject.optString("campaign", ""); - attribution.adgroup = jsonObject.optString("adgroup", ""); - attribution.creative = jsonObject.optString("creative", ""); - attribution.clickLabel = jsonObject.optString("click_label", ""); - attribution.adid = adid != null ? adid : ""; - attribution.costType = jsonObject.optString("cost_type", ""); - attribution.costAmount = jsonObject.optDouble("cost_amount", 0); - attribution.costCurrency = jsonObject.optString("cost_currency", ""); - attribution.fbInstallReferrer = jsonObject.optString("fb_install_referrer", ""); - } else { - // Rest of all platforms. - attribution.trackerToken = jsonObject.optString("tracker_token"); - attribution.trackerName = jsonObject.optString("tracker_name"); - attribution.network = jsonObject.optString("network"); - attribution.campaign = jsonObject.optString("campaign"); - attribution.adgroup = jsonObject.optString("adgroup"); - attribution.creative = jsonObject.optString("creative"); - attribution.clickLabel = jsonObject.optString("click_label"); - attribution.adid = adid; - attribution.costType = jsonObject.optString("cost_type"); - attribution.costAmount = jsonObject.optDouble("cost_amount"); - attribution.costCurrency = jsonObject.optString("cost_currency"); - attribution.fbInstallReferrer = jsonObject.optString("fb_install_referrer"); - } - - return attribution; - } + public String jsonResponse; @Override public boolean equals(Object other) { @@ -95,7 +57,6 @@ public boolean equals(Object other) { if (!Util.equalString(adgroup, otherAttribution.adgroup)) return false; if (!Util.equalString(creative, otherAttribution.creative)) return false; if (!Util.equalString(clickLabel, otherAttribution.clickLabel)) return false; - if (!Util.equalString(adid, otherAttribution.adid)) return false; if (!Util.equalString(costType, otherAttribution.costType)) return false; if (!Util.equalsDouble(costAmount, otherAttribution.costAmount)) return false; if (!Util.equalString(costCurrency, otherAttribution.costCurrency)) return false; @@ -113,11 +74,11 @@ public Map toMap() { if (adgroup != null) fields.put("adgroup", adgroup); if (creative != null) fields.put("creative", creative); if (clickLabel != null) fields.put("clickLabel", clickLabel); - if (adid != null) fields.put("adid", adid); if (costType != null) fields.put("costType", costType); if (costAmount != null) fields.put("costAmount", costAmount.toString()); if (costCurrency != null) fields.put("costCurrency", costCurrency); if (fbInstallReferrer != null) fields.put("fbInstallReferrer", fbInstallReferrer); + if (jsonResponse != null) fields.put("jsonResponse", jsonResponse); return fields; } @@ -132,7 +93,6 @@ public int hashCode() { hashCode = Util.hashString(adgroup, hashCode); hashCode = Util.hashString(creative, hashCode); hashCode = Util.hashString(clickLabel, hashCode); - hashCode = Util.hashString(adid, hashCode); hashCode = Util.hashString(costType, hashCode); hashCode = Util.hashDouble(costAmount, hashCode); hashCode = Util.hashString(costCurrency, hashCode); @@ -144,9 +104,9 @@ public int hashCode() { @Override public String toString() { return Util.formatString( - "tt:%s tn:%s net:%s cam:%s adg:%s cre:%s cl:%s adid:%s ct:%s ca:%.2f cc:%s fir:%s", + "tt:%s tn:%s net:%s cam:%s adg:%s cre:%s cl:%s ct:%s ca:%.2f cc:%s fir:%s", trackerToken, trackerName, network, campaign, adgroup, creative, clickLabel, - adid, costType, costAmount, costCurrency, fbInstallReferrer); + costType, costAmount, costCurrency, fbInstallReferrer); } private void writeObject(ObjectOutputStream stream) throws IOException { diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java index ca0b77f42..09eed383e 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustConfig.java @@ -2,6 +2,7 @@ import android.content.Context; +import java.util.ArrayList; import java.util.List; /** @@ -17,61 +18,51 @@ public class AdjustConfig { String environment; String processName; String sdkPrefix; - boolean eventBufferingEnabled; String defaultTracker; OnAttributionChangedListener onAttributionChangedListener; - Boolean deviceKnown; - Class deepLinkComponent; + OnThirdPartySharingSettingsChangedListener onThirdPartySharingSettingsChangedListener; OnEventTrackingSucceededListener onEventTrackingSucceededListener; OnEventTrackingFailedListener onEventTrackingFailedListener; OnSessionTrackingSucceededListener onSessionTrackingSucceededListener; OnSessionTrackingFailedListener onSessionTrackingFailedListener; - OnDeeplinkResponseListener onDeeplinkResponseListener; - boolean sendInBackground; - Double delayStart; + OnDeferredDeeplinkResponseListener onDeferredDeeplinkResponseListener; + OnRemoteTriggerListener onRemoteTriggerListener; + boolean isSendingInBackgroundEnabled; AdjustInstance.PreLaunchActions preLaunchActions; ILogger logger; - String userAgent; String pushToken; Boolean startEnabled; boolean startOffline; - String secretId; - String appSecret; String externalDeviceId; - boolean preinstallTrackingEnabled; - Boolean needsCost; - String urlStrategy; + boolean isPreinstallTrackingEnabled; + Boolean isCostDataInAttributionEnabled; + List urlStrategyDomains; + boolean useSubdomains; + boolean isDataResidency; String preinstallFilePath; - boolean playStoreKidsAppEnabled; - boolean coppaCompliantEnabled; - boolean finalAttributionEnabled; + boolean coppaComplianceEnabled; + boolean playStoreKidsComplianceEnabled; String fbAppId; - boolean readDeviceInfoOnceEnabled; + boolean isDeviceIdsReadingOnceEnabled; OnDeeplinkResolvedListener cachedDeeplinkResolutionCallback; + ArrayList cachedAdidReadCallbacks = new ArrayList<>(); + ArrayList cachedAdidReadTimeoutCallbacks = new ArrayList<>(); + Integer eventDeduplicationIdsMaxSize; + ArrayList cachedAttributionReadCallbacks = new ArrayList<>(); + ArrayList cachedAttributionReadTimeoutCallbacks = new ArrayList<>(); + ArrayList cachedThirdPartySharingTimeoutCallbacks = new ArrayList<>(); + boolean isFirstSessionDelayEnabled; + AdjustStoreInfo storeInfo; + boolean isGoogleAdIdReadingEnabled; + boolean isAndroidIdReadingEnabled; + boolean isAppSetIdReadingEnabled; + boolean isFbIdReadingEnabled; + boolean isFireAdIdReadingEnabled; + boolean isDeviceIdsFromPluginsReadingEnabled; public static final String ENVIRONMENT_SANDBOX = "sandbox"; public static final String ENVIRONMENT_PRODUCTION = "production"; - public static final String URL_STRATEGY_INDIA = "url_strategy_india"; - public static final String URL_STRATEGY_CHINA = "url_strategy_china"; - public static final String URL_STRATEGY_CN = "url_strategy_cn"; - public static final String URL_STRATEGY_CN_ONLY = "url_strategy_cn_only"; - public static final String DATA_RESIDENCY_EU = "data_residency_eu"; - public static final String DATA_RESIDENCY_TR = "data_residency_tr"; - public static final String DATA_RESIDENCY_US = "data_residency_us"; - - public static final String AD_REVENUE_APPLOVIN_MAX = "applovin_max_sdk"; - public static final String AD_REVENUE_MOPUB = "mopub"; - public static final String AD_REVENUE_ADMOB = "admob_sdk"; - public static final String AD_REVENUE_IRONSOURCE = "ironsource_sdk"; - public static final String AD_REVENUE_ADMOST = "admost_sdk"; - public static final String AD_REVENUE_UNITY = "unity_sdk"; - public static final String AD_REVENUE_HELIUM_CHARTBOOST = "helium_chartboost_sdk"; - public static final String AD_REVENUE_SOURCE_PUBLISHER = "publisher_sdk"; - public static final String AD_REVENUE_TOPON = "topon_sdk"; - public static final String AD_REVENUE_ADX = "adx_sdk"; - public static final String AD_REVENUE_TRADPLUS = "tradplus_sdk"; - public AdjustConfig(Context context, String appToken, String environment) { init(context, appToken, environment, false); } @@ -85,7 +76,7 @@ private void init(Context context, String appToken, String environment, boolean logger = AdjustFactory.getLogger(); // default values if (allowSuppressLogLevel && AdjustConfig.ENVIRONMENT_PRODUCTION.equals(environment)) { - setLogLevel(LogLevel.SUPRESS, environment); + setLogLevel(LogLevel.SUPPRESS, environment); } else { setLogLevel(LogLevel.INFO, environment); } @@ -100,163 +91,161 @@ private void init(Context context, String appToken, String environment, boolean this.environment = environment; // default values - this.eventBufferingEnabled = false; - this.sendInBackground = false; - this.preinstallTrackingEnabled = false; - } - - public void setEventBufferingEnabled(Boolean eventBufferingEnabled) { - if (eventBufferingEnabled == null) { - this.eventBufferingEnabled = false; - return; - } - this.eventBufferingEnabled = eventBufferingEnabled; - } - - public void setSendInBackground(boolean sendInBackground) { - this.sendInBackground = sendInBackground; + this.isSendingInBackgroundEnabled = false; + this.isPreinstallTrackingEnabled = false; + this.isDeviceIdsReadingOnceEnabled = false; + this.coppaComplianceEnabled = false; + this.playStoreKidsComplianceEnabled = false; + this.isFirstSessionDelayEnabled = false; + this.isGoogleAdIdReadingEnabled = true; + this.isAndroidIdReadingEnabled = true; + this.isAppSetIdReadingEnabled = true; + this.isFbIdReadingEnabled = true; + this.isFireAdIdReadingEnabled = true; + this.isDeviceIdsFromPluginsReadingEnabled = true; } public void setLogLevel(LogLevel logLevel) { setLogLevel(logLevel, environment); } + private void setLogLevel(LogLevel logLevel, String environment) { + logger.setLogLevel(logLevel, AdjustConfig.ENVIRONMENT_PRODUCTION.equals(environment)); + } + public void setSdkPrefix(String sdkPrefix) { this.sdkPrefix = sdkPrefix; } - public void setProcessName(String processName) { this.processName = processName; } + public void setProcessName(String processName) { + this.processName = processName; + } public void setDefaultTracker(String defaultTracker) { this.defaultTracker = defaultTracker; } - public void setOnAttributionChangedListener(OnAttributionChangedListener onAttributionChangedListener) { - this.onAttributionChangedListener = onAttributionChangedListener; + public void setExternalDeviceId(String externalDeviceId) { + this.externalDeviceId = externalDeviceId; } - public void setDeviceKnown(boolean deviceKnown) { - this.deviceKnown = deviceKnown; + public void setPreinstallFilePath(String preinstallFilePath) { + this.preinstallFilePath = preinstallFilePath; } - public void setDeepLinkComponent(Class deepLinkComponent) { - this.deepLinkComponent = deepLinkComponent; + public void enableCoppaCompliance() { + this.coppaComplianceEnabled = true; } - public void setOnEventTrackingSucceededListener(OnEventTrackingSucceededListener onEventTrackingSucceededListener) { - this.onEventTrackingSucceededListener = onEventTrackingSucceededListener; + public void enablePlayStoreKidsCompliance() { + this.playStoreKidsComplianceEnabled = true; } - public void setOnEventTrackingFailedListener(OnEventTrackingFailedListener onEventTrackingFailedListener) { - this.onEventTrackingFailedListener = onEventTrackingFailedListener; + public void setFbAppId(String fbAppId) { + this.fbAppId = fbAppId; } - public void setOnSessionTrackingSucceededListener(OnSessionTrackingSucceededListener onSessionTrackingSucceededListener) { - this.onSessionTrackingSucceededListener = onSessionTrackingSucceededListener; + public void setEventDeduplicationIdsMaxSize(Integer eventDeduplicationIdsMaxSize) { + this.eventDeduplicationIdsMaxSize = eventDeduplicationIdsMaxSize; } - public void setOnSessionTrackingFailedListener(OnSessionTrackingFailedListener onSessionTrackingFailedListener) { - this.onSessionTrackingFailedListener = onSessionTrackingFailedListener; + public void setUrlStrategy(List domains, boolean useSubdomains, boolean isDataResidency) { + if (domains == null || domains.isEmpty()) { + logger.error("Invalid URL strategy domains array"); + return; + } + this.urlStrategyDomains = domains; + this.useSubdomains = useSubdomains; + this.isDataResidency = isDataResidency; } - public void setOnDeeplinkResponseListener(OnDeeplinkResponseListener onDeeplinkResponseListener) { - this.onDeeplinkResponseListener = onDeeplinkResponseListener; + public void enablePreinstallTracking() { + this.isPreinstallTrackingEnabled = true; } - public void setDelayStart(double delayStart) { - this.delayStart = delayStart; + public void enableCostDataInAttribution() { + this.isCostDataInAttributionEnabled = true; } - public void setUserAgent(String userAgent) { - this.userAgent = userAgent; + public void enableSendingInBackground() { + this.isSendingInBackgroundEnabled = true; } - public void setAppSecret(long secretId, long info1, long info2, long info3, long info4) { - this.secretId = Util.formatString("%d", secretId); - this.appSecret = Util.formatString("%d%d%d%d", info1, info2, info3, info4); + public void enableDeviceIdsReadingOnce() { + this.isDeviceIdsReadingOnceEnabled = true; } - @Deprecated - public void setReadMobileEquipmentIdentity(boolean readMobileEquipmentIdentity) { - logger.warn("This method has been deprecated and shouldn't be used anymore"); + public void enableFirstSessionDelay() { + this.isFirstSessionDelayEnabled = true; } - public void setExternalDeviceId(String externalDeviceId) { - this.externalDeviceId = externalDeviceId; + public void setStoreInfo(AdjustStoreInfo storeInfo) { + this.storeInfo = storeInfo; } - public void setPreinstallTrackingEnabled(boolean preinstallTrackingEnabled) { - this.preinstallTrackingEnabled = preinstallTrackingEnabled; + public void setOnAttributionChangedListener(OnAttributionChangedListener onAttributionChangedListener) { + this.onAttributionChangedListener = onAttributionChangedListener; } - public void setPreinstallFilePath(String preinstallFilePath) { - this.preinstallFilePath = preinstallFilePath; + public void setOnThirdPartySharingSettingsChangedListener(OnThirdPartySharingSettingsChangedListener onThirdPartySharingSettingsChangedListener) { + this.onThirdPartySharingSettingsChangedListener = onThirdPartySharingSettingsChangedListener; } - public void setNeedsCost(boolean needsCost) { - this.needsCost = needsCost; + public void setOnEventTrackingSucceededListener(OnEventTrackingSucceededListener onEventTrackingSucceededListener) { + this.onEventTrackingSucceededListener = onEventTrackingSucceededListener; } - public void setPlayStoreKidsAppEnabled(boolean playStoreKidsAppEnabled) { - this.playStoreKidsAppEnabled = playStoreKidsAppEnabled; + public void setOnEventTrackingFailedListener(OnEventTrackingFailedListener onEventTrackingFailedListener) { + this.onEventTrackingFailedListener = onEventTrackingFailedListener; } - public void setCoppaCompliantEnabled(boolean coppaCompliantEnabled) { - this.coppaCompliantEnabled = coppaCompliantEnabled; + public void setOnSessionTrackingSucceededListener(OnSessionTrackingSucceededListener onSessionTrackingSucceededListener) { + this.onSessionTrackingSucceededListener = onSessionTrackingSucceededListener; } - public void setFinalAttributionEnabled(boolean finalAttributionEnabled) { - this.finalAttributionEnabled = finalAttributionEnabled; + public void setOnSessionTrackingFailedListener(OnSessionTrackingFailedListener onSessionTrackingFailedListener) { + this.onSessionTrackingFailedListener = onSessionTrackingFailedListener; } - public void setFbAppId(String fbAppId) { - this.fbAppId = fbAppId; + public void setOnDeferredDeeplinkResponseListener(OnDeferredDeeplinkResponseListener onDeferredDeeplinkResponseListener) { + this.onDeferredDeeplinkResponseListener = onDeferredDeeplinkResponseListener; } - public boolean isValid() { - if (!checkAppToken(appToken)) return false; - if (!checkEnvironment(environment)) return false; - if (!checkContext(context)) return false; + public void setOnRemoteTriggerListener(OnRemoteTriggerListener onRemoteTriggerListener) { + this.onRemoteTriggerListener = onRemoteTriggerListener; + } - return true; + public void disableGoogleAdIdReading() { + this.isGoogleAdIdReadingEnabled = false; } - public void setUrlStrategy(String urlStrategy) { - if (urlStrategy == null || urlStrategy.isEmpty()) { - logger.error("Invalid url strategy"); - return; - } - if (!urlStrategy.equals(URL_STRATEGY_INDIA) - && !urlStrategy.equals(URL_STRATEGY_CHINA) - && !urlStrategy.equals(URL_STRATEGY_CN) - && !urlStrategy.equals(URL_STRATEGY_CN_ONLY) - && !urlStrategy.equals(DATA_RESIDENCY_EU) - && !urlStrategy.equals(DATA_RESIDENCY_TR) - && !urlStrategy.equals(DATA_RESIDENCY_US)) - { - logger.warn("Unrecognised url strategy %s", urlStrategy); - } - this.urlStrategy = urlStrategy; + public void disableAndroidIdReading() { + this.isAndroidIdReadingEnabled = false; } - public void setReadDeviceInfoOnceEnabled(boolean readDeviceInfoOnceEnabled) { - this.readDeviceInfoOnceEnabled = readDeviceInfoOnceEnabled; + public void disableAppSetIdReading() { + this.isAppSetIdReadingEnabled = false; } - public String getBasePath() { - return basePath; + public void disableFbIdReading() { + this.isFbIdReadingEnabled = false; } - public String getGdprPath() { - return gdprPath; + public void disableFireAdIdReading() { + this.isFireAdIdReadingEnabled = false; } - public String getSubscriptionPath() { - return subscriptionPath; + public void disableDeviceIdsFromPluginsReading() { + this.isDeviceIdsFromPluginsReadingEnabled = false; } - public String getPurchaseVerificationPath() { - return purchaseVerificationPath; + public void disableDeviceIdsReading() { + this.isGoogleAdIdReadingEnabled = false; + this.isAndroidIdReadingEnabled = false; + this.isAppSetIdReadingEnabled = false; + this.isFbIdReadingEnabled = false; + this.isFireAdIdReadingEnabled = false; + this.isDeviceIdsFromPluginsReadingEnabled = false; } public Context getContext() { @@ -279,128 +268,116 @@ public String getSdkPrefix() { return sdkPrefix; } - public boolean isEventBufferingEnabled() { - return eventBufferingEnabled; - } - public String getDefaultTracker() { return defaultTracker; } - public OnAttributionChangedListener getOnAttributionChangedListener() { - return onAttributionChangedListener; + public String getExternalDeviceId() { + return externalDeviceId; } - public Boolean getDeviceKnown() { - return deviceKnown; + public boolean isPreinstallTrackingEnabled() { + return isPreinstallTrackingEnabled; } - public Class getDeepLinkComponent() { - return deepLinkComponent; + public Boolean getCostDataInAttributionEnabled() { + return isCostDataInAttributionEnabled; } - public OnEventTrackingSucceededListener getOnEventTrackingSucceededListener() { - return onEventTrackingSucceededListener; + public boolean isSendingInBackgroundEnabled() { + return isSendingInBackgroundEnabled; } - public OnEventTrackingFailedListener getOnEventTrackingFailedListener() { - return onEventTrackingFailedListener; + public Integer getEventDeduplicationIdsMaxSize() { + return eventDeduplicationIdsMaxSize; } - public OnSessionTrackingSucceededListener getOnSessionTrackingSucceededListener() { - return onSessionTrackingSucceededListener; + public List getUrlStrategyDomains() { + return urlStrategyDomains; } - public OnSessionTrackingFailedListener getOnSessionTrackingFailedListener() { - return onSessionTrackingFailedListener; - } - - public OnDeeplinkResponseListener getOnDeeplinkResponseListener() { - return onDeeplinkResponseListener; - } - - public boolean isSendInBackground() { - return sendInBackground; + public String getPreinstallFilePath() { + return preinstallFilePath; } - public Double getDelayStart() { - return delayStart; + public boolean isCoppaComplianceEnabled() { + return coppaComplianceEnabled; } - public AdjustInstance.PreLaunchActions getPreLaunchActions() { - return preLaunchActions; + public boolean isPlayStoreKidsComplianceEnabled() { + return playStoreKidsComplianceEnabled; } - public ILogger getLogger() { - return logger; + public String getFbAppId() { + return fbAppId; } - public String getUserAgent() { - return userAgent; + public boolean isDeviceIdsReadingOnceEnabled() { + return isDeviceIdsReadingOnceEnabled; } - public String getPushToken() { - return pushToken; + public AdjustStoreInfo getStoreInfo() { + return storeInfo; } - public Boolean getStartEnabled() { - return startEnabled; + public OnAttributionChangedListener getOnAttributionChangedListener() { + return onAttributionChangedListener; } - public boolean isStartOffline() { - return startOffline; + public OnThirdPartySharingSettingsChangedListener getOnThirdPartySharingSettingsChangedListener() { + return onThirdPartySharingSettingsChangedListener; } - public String getSecretId() { - return secretId; + public OnEventTrackingSucceededListener getOnEventTrackingSucceededListener() { + return onEventTrackingSucceededListener; } - public String getAppSecret() { - return appSecret; + public OnEventTrackingFailedListener getOnEventTrackingFailedListener() { + return onEventTrackingFailedListener; } - public String getExternalDeviceId() { - return externalDeviceId; + public OnSessionTrackingSucceededListener getOnSessionTrackingSucceededListener() { + return onSessionTrackingSucceededListener; } - public boolean isPreinstallTrackingEnabled() { - return preinstallTrackingEnabled; + public OnSessionTrackingFailedListener getOnSessionTrackingFailedListener() { + return onSessionTrackingFailedListener; } - public Boolean getNeedsCost() { - return needsCost; + public OnDeferredDeeplinkResponseListener getOnDeeplinkResponseListener() { + return onDeferredDeeplinkResponseListener; } - public String getUrlStrategy() { - return urlStrategy; + public OnRemoteTriggerListener getOnRemoteTriggerListener() { + return onRemoteTriggerListener; } - public String getPreinstallFilePath() { - return preinstallFilePath; + public ILogger getLogger() { + return logger; } - public boolean isPlayStoreKidsAppEnabled() { - return playStoreKidsAppEnabled; + public boolean isGoogleAdIdReadingEnabled() { + return isGoogleAdIdReadingEnabled; } - public boolean isCoppaCompliantEnabled() { - return coppaCompliantEnabled; + public boolean isAndroidIdReadingEnabled() { + return isAndroidIdReadingEnabled; } - public boolean isFinalAttributionEnabled() { - return finalAttributionEnabled; + public boolean isAppSetIdReadingEnabled() { + return isAppSetIdReadingEnabled; } - public String getFbAppId() { - return fbAppId; + public boolean isFbIdReadingEnabled() { + return isFbIdReadingEnabled; } - public boolean isReadDeviceInfoOnceEnabled() { - return readDeviceInfoOnceEnabled; + public boolean isFireAdIdReadingEnabled() { + return isFireAdIdReadingEnabled; } - private void setLogLevel(LogLevel logLevel, String environment) { - logger.setLogLevel(logLevel, AdjustConfig.ENVIRONMENT_PRODUCTION.equals(environment)); + public boolean isDeviceIdsFromPluginsReadingEnabled() { + return isDeviceIdsFromPluginsReadingEnabled; } private boolean checkContext(Context context) { @@ -454,4 +431,17 @@ private boolean checkEnvironment(String environment) { logger.error("Unknown environment '%s'", environment); return false; } -} \ No newline at end of file + + public boolean isValid() { + if (!checkAppToken(appToken)) { + return false; + } + if (!checkEnvironment(environment)) { + return false; + } + if (!checkContext(context)) { + return false; + } + return true; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustDeeplink.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustDeeplink.java new file mode 100644 index 000000000..c10e0f4ce --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustDeeplink.java @@ -0,0 +1,31 @@ +package com.adjust.sdk; + +import android.net.Uri; + +public class AdjustDeeplink { + Uri url; + Uri referrer; + + public AdjustDeeplink(Uri url) { + this.url = url; + } + + public boolean isValid() { + if (url == null || url.toString().isEmpty()) { + return false; + } + return true; + } + + public void setReferrer(Uri referrer) { + this.referrer = referrer; + } + + public Uri getUrl() { + return url; + } + + public Uri getReferrer() { + return referrer; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java index 00da98923..3f59f5749 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustEvent.java @@ -13,6 +13,7 @@ public class AdjustEvent { Map callbackParameters; Map partnerParameters; String orderId; + String deduplicationId; String callbackId; String productId; String purchaseToken; @@ -66,6 +67,10 @@ public void setOrderId(String orderId) { this.orderId = orderId; } + public void setDeduplicationId(String deduplicationId) { + this.deduplicationId = deduplicationId; + } + public void setCallbackId(String callbackId) { this.callbackId = callbackId; } @@ -106,6 +111,10 @@ public String getOrderId() { return orderId; } + public String getDeduplicationId() { + return deduplicationId; + } + public String getCallbackId() { return callbackId; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java index 2bb95e7a4..d66aa0346 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustFactory.java @@ -24,7 +24,6 @@ public class AdjustFactory { private static BackoffStrategy sdkClickBackoffStrategy = null; private static BackoffStrategy packageHandlerBackoffStrategy = null; private static BackoffStrategy installSessionBackoffStrategy = null; - private static long maxDelayStart = -1; private static String baseUrl = null; private static String gdprUrl = null; private static String subscriptionUrl = null; @@ -32,6 +31,8 @@ public class AdjustFactory { private static UtilNetworking.IConnectionOptions connectionOptions = null; private static UtilNetworking.IHttpsURLConnectionProvider httpsURLConnectionProvider = null; private static boolean tryInstallReferrer = true; + private static boolean ignoreSystemLifecycleBootstrap = false; + private static boolean allowUrlStrategyFallback = true; public static class URLGetConnection { HttpsURLConnection httpsURLConnection; @@ -172,13 +173,6 @@ public static IPurchaseVerificationHandler getPurchaseVerificationHandler( return purchaseVerificationHandler; } - public static long getMaxDelayStart() { - if (maxDelayStart == -1) { - return Constants.ONE_SECOND * 10; // 10 seconds - } - return maxDelayStart; - } - public static String getBaseUrl() { return AdjustFactory.baseUrl; } @@ -287,12 +281,22 @@ public static void setTryInstallReferrer(boolean tryInstallReferrer) { AdjustFactory.tryInstallReferrer = tryInstallReferrer; } - public static void enableSigning() { - AdjustSigner.enableSigning(getLogger()); + public static void setIgnoreSystemLifecycleBootstrap( + final boolean ignoreSystemLifecycleBootstrap) + { + AdjustFactory.ignoreSystemLifecycleBootstrap = ignoreSystemLifecycleBootstrap; + } + public static boolean isSystemLifecycleBootstrapIgnored() { + return AdjustFactory.ignoreSystemLifecycleBootstrap; } - public static void disableSigning() { - AdjustSigner.disableSigning(getLogger()); + public static void setAllowUrlStrategyFallback( + final boolean allowUrlStrategyFallback) + { + AdjustFactory.allowUrlStrategyFallback = allowUrlStrategyFallback; + } + public static boolean isAllowUrlStrategyFallback() { + return AdjustFactory.allowUrlStrategyFallback; } private static String byte2HexFormatted(byte[] arr) { @@ -334,7 +338,6 @@ public static void teardown(Context context) { subsessionInterval = -1; sdkClickBackoffStrategy = null; packageHandlerBackoffStrategy = null; - maxDelayStart = -1; baseUrl = Constants.BASE_URL; gdprUrl = Constants.GDPR_URL; subscriptionUrl = Constants.SUBSCRIPTION_URL; diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java index 354636a1f..5acb65a2b 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustInstance.java @@ -2,8 +2,11 @@ import android.net.Uri; import android.content.Context; +import android.os.Handler; -import org.json.JSONObject; +import com.adjust.sdk.scheduler.AsyncTaskExecutor; +import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; +import com.adjust.sdk.scheduler.ThreadExecutor; import java.util.List; import java.util.ArrayList; @@ -17,13 +20,9 @@ public class AdjustInstance { public static class PreLaunchActions { public List preLaunchActionsArray; - public List preLaunchAdjustThirdPartySharingArray; - public Boolean lastMeasurementConsentTracked; public PreLaunchActions() { preLaunchActionsArray = new ArrayList<>(); - preLaunchAdjustThirdPartySharingArray = new ArrayList<>(); - lastMeasurementConsentTracked = null; } } @@ -51,6 +50,11 @@ public PreLaunchActions() { private OnDeeplinkResolvedListener cachedDeeplinkResolutionCallback; + private final ArrayList cachedAdidReadCallbacks = new ArrayList<>(); + private final ArrayList cachedAdidReadTimeoutCallbacks = new ArrayList<>(); + private final ArrayList cachedAttributionReadCallbacks = new ArrayList<>(); + private final ArrayList cachedAttributionReadTimeoutCallbacks = new ArrayList<>(); + private final ArrayList cachedThirdPartySharingTimeoutCallbacks = new ArrayList<>(); /** * Base path for Adjust packages. */ @@ -76,7 +80,11 @@ public PreLaunchActions() { * * @param adjustConfig AdjustConfig object used for SDK initialisation */ - public void onCreate(final AdjustConfig adjustConfig) { + public void initSdk(final AdjustConfig adjustConfig) { + if (!AdjustSigner.isPresent()) { + AdjustFactory.getLogger().error("Missing signature library, SDK can't be initialised"); + return; + } if (adjustConfig == null) { AdjustFactory.getLogger().error("AdjustConfig missing"); return; @@ -99,6 +107,11 @@ public void onCreate(final AdjustConfig adjustConfig) { adjustConfig.subscriptionPath = this.subscriptionPath; adjustConfig.purchaseVerificationPath = this.purchaseVerificationPath; adjustConfig.cachedDeeplinkResolutionCallback = cachedDeeplinkResolutionCallback; + adjustConfig.cachedAdidReadCallbacks = cachedAdidReadCallbacks; + adjustConfig.cachedAdidReadTimeoutCallbacks = cachedAdidReadTimeoutCallbacks; + adjustConfig.cachedAttributionReadCallbacks = cachedAttributionReadCallbacks; + adjustConfig.cachedAttributionReadTimeoutCallbacks = cachedAttributionReadTimeoutCallbacks; + adjustConfig.cachedThirdPartySharingTimeoutCallbacks = cachedThirdPartySharingTimeoutCallbacks; activityHandler = AdjustFactory.getActivityHandler(adjustConfig); setSendingReferrersAsNotSent(adjustConfig.context); @@ -137,89 +150,108 @@ public void onPause() { } /** - * Called to disable/enable SDK. + * Called to enable SDK. * - * @param enabled boolean indicating whether SDK should be enabled or disabled */ - public void setEnabled(final boolean enabled) { - this.startEnabled = enabled; - if (checkActivityHandler(enabled, "enabled mode", "disabled mode")) { - activityHandler.setEnabled(enabled); + public void enable() { + this.startEnabled = true; + if (checkActivityHandler(true, "enabled mode", "disabled mode")) { + activityHandler.setEnabled(true); } } - /** - * Get information if SDK is enabled or not. + * Called to disable SDK. * - * @return boolean indicating whether SDK is enabled or not */ - public boolean isEnabled() { - if (!checkActivityHandler("isEnabled")) { - return isInstanceEnabled(); + public void disable() { + this.startEnabled = false; + if (checkActivityHandler(false, "enabled mode", "disabled mode")) { + activityHandler.setEnabled(false); } - return activityHandler.isEnabled(); } /** - * Called to process deep link. + * Get information if SDK is enabled or not. * - * @param url Deep link URL to process + * @param context Application context + * @param isEnabledListener Callback to get triggered once information is obtained */ - public void appWillOpenUrl(final Uri url) { - if (!checkActivityHandler("appWillOpenUrl")) { + public void isEnabled(final Context context, final OnIsEnabledListener isEnabledListener) { + if (!checkActivityHandler("isEnabled")) { + new AsyncTaskExecutor(){ + @Override + protected Boolean doInBackground(Context... contexts) { + return Util.isEnabledFromActivityStateFile(contexts[0]); + } + + @Override + protected void onPostExecute(Boolean isEnabled) { + isEnabledListener.onIsEnabledRead(isEnabled); + } + }.execute(context); return; } - long clickTime = System.currentTimeMillis(); - activityHandler.readOpenUrl(url, clickTime); + activityHandler.isEnabled(isEnabledListener); } /** - * Called to process deep link. + * Called to process deeplink. * - * @param url Deep link URL to process + * @param adjustDeeplink Deeplink object to process * @param context Application context */ - public void appWillOpenUrl(final Uri url, final Context context) { - // Check for deep link validity. If invalid, return. - if (url == null || url.toString().length() == 0) { + public void processDeeplink(final AdjustDeeplink adjustDeeplink, final Context context) { + // Check for deeplink validity. If invalid, return. + if (adjustDeeplink == null || !adjustDeeplink.isValid()) { AdjustFactory.getLogger().warn( - "Skipping deep link processing (null or empty)"); + "Skipping deeplink processing (null or empty)"); return; } + cacheDeeplink(adjustDeeplink.url, context); + long clickTime = System.currentTimeMillis(); - if (!checkActivityHandler("appWillOpenUrl", true)) { - saveDeeplink(url, clickTime, context); + if (!checkActivityHandler("processDeeplink", true)) { + saveDeeplink(adjustDeeplink, clickTime, context); return; } - activityHandler.readOpenUrl(url, clickTime); + activityHandler.processDeeplink(adjustDeeplink, clickTime); } /** - * Process the deep link that has opened an app and potentially get a resolved link. + * Process the deeplink that has opened an app and potentially get a resolved link. * - * @param url Deep link URL to process - * @param callback Callback where either resolved or echoed deep link will be sent. - * @param context Application context + * @param adjustDeeplink Deeplink object to process + * @param callback Callback where either resolved or echoed deeplink will be sent. + * @param context Application context */ - public void processDeeplink(Uri url, Context context, OnDeeplinkResolvedListener callback) { + public void processAndResolveDeeplink(AdjustDeeplink adjustDeeplink, Context context, OnDeeplinkResolvedListener callback) { + // Check for deeplink validity. If invalid, return. + if (adjustDeeplink == null || !adjustDeeplink.isValid()) { + AdjustFactory.getLogger().warn( + "Skipping deeplink processing (null or empty)"); + return; + } + // if resolution result is not wanted, fallback to default method if (callback == null) { - appWillOpenUrl(url, context); + processDeeplink(adjustDeeplink, context); return; } - // if deep link processing is triggered prior to SDK being initialized + cacheDeeplink(adjustDeeplink.url, context); + + // if deeplink processing is triggered prior to SDK being initialized long clickTime = System.currentTimeMillis(); - if (!checkActivityHandler("processDeeplink", true)) { - saveDeeplink(url, clickTime, context); + if (!checkActivityHandler("processAndResolveDeeplink", true)) { + saveDeeplink(adjustDeeplink, clickTime, context); this.cachedDeeplinkResolutionCallback = callback; return; } - // if deep link processing was triggered with SDK being initialized - activityHandler.readOpenUrl(url, clickTime, callback); + // if deeplink processing was triggered with SDK being initialized + activityHandler.processAndResolveDeeplink(adjustDeeplink, clickTime, callback); } /** @@ -249,8 +281,8 @@ public void sendReferrer(final String rawReferrer, final Context context) { /** * Called to process preinstall payload information sent with SYSTEM_INSTALLER_REFERRER intent. * - * @param referrer Preinstall referrer content - * @param context Application context + * @param referrer Preinstall referrer content + * @param context Application context */ public void sendPreinstallReferrer(final String referrer, final Context context) { // Check for referrer validity. If invalid, return. @@ -271,24 +303,25 @@ public void sendPreinstallReferrer(final String referrer, final Context context) /** * Called to set SDK to offline or online mode. * - * @param enabled boolean indicating should SDK be in offline mode (true) or not (false) */ - public void setOfflineMode(final boolean enabled) { - if (!checkActivityHandler(enabled, "offline mode", "online mode")) { - this.startOffline = enabled; + public void switchToOfflineMode() { + if (!checkActivityHandler(true, "offline mode", "online mode")) { + this.startOffline = true; } else { - activityHandler.setOfflineMode(enabled); + activityHandler.setOfflineMode(true); } } /** - * Called if SDK initialisation was delayed and you would like to stop waiting for timer. + * Called to set SDK to online or online mode. + * */ - public void sendFirstPackages() { - if (!checkActivityHandler("sendFirstPackages")) { - return; + public void switchBackToOnlineMode() { + if (!checkActivityHandler(false, "offline mode", "online mode")) { + this.startOffline = false; + } else { + activityHandler.setOfflineMode(false); } - activityHandler.sendFirstPackages(); } /** @@ -297,16 +330,16 @@ public void sendFirstPackages() { * @param key Global callback parameter key * @param value Global callback parameter value */ - public void addSessionCallbackParameter(final String key, final String value) { - if (checkActivityHandler("adding session callback parameter", true)) { - activityHandler.addSessionCallbackParameter(key, value); + public void addGlobalCallbackParameter(final String key, final String value) { + if (checkActivityHandler("adding global callback parameter", true)) { + activityHandler.addGlobalCallbackParameter(key, value); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.addSessionCallbackParameterI(key, value); + activityHandler.addGlobalCallbackParameterI(key, value); } }); } @@ -317,15 +350,15 @@ public void run(final ActivityHandler activityHandler) { * @param key Global partner parameter key * @param value Global partner parameter value */ - public void addSessionPartnerParameter(final String key, final String value) { - if (checkActivityHandler("adding session partner parameter", true)) { - activityHandler.addSessionPartnerParameter(key, value); + public void addGlobalPartnerParameter(final String key, final String value) { + if (checkActivityHandler("adding global partner parameter", true)) { + activityHandler.addGlobalPartnerParameter(key, value); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.addSessionPartnerParameterI(key, value); + activityHandler.addGlobalPartnerParameterI(key, value); } }); } @@ -335,15 +368,15 @@ public void run(final ActivityHandler activityHandler) { * * @param key Global callback parameter key */ - public void removeSessionCallbackParameter(final String key) { - if (checkActivityHandler("removing session callback parameter", true)) { - activityHandler.removeSessionCallbackParameter(key); + public void removeGlobalCallbackParameter(final String key) { + if (checkActivityHandler("removing global callback parameter", true)) { + activityHandler.removeGlobalCallbackParameter(key); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.removeSessionCallbackParameterI(key); + activityHandler.removeGlobalCallbackParameterI(key); } }); } @@ -353,15 +386,15 @@ public void run(final ActivityHandler activityHandler) { * * @param key Global partner parameter key */ - public void removeSessionPartnerParameter(final String key) { - if (checkActivityHandler("removing session partner parameter", true)) { - activityHandler.removeSessionPartnerParameter(key); + public void removeGlobalPartnerParameter(final String key) { + if (checkActivityHandler("removing global partner parameter", true)) { + activityHandler.removeGlobalPartnerParameter(key); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.removeSessionPartnerParameterI(key); + activityHandler.removeGlobalPartnerParameterI(key); } }); } @@ -369,15 +402,15 @@ public void run(final ActivityHandler activityHandler) { /** * Called to remove all added global callback parameters. */ - public void resetSessionCallbackParameters() { - if (checkActivityHandler("resetting session callback parameters", true)) { - activityHandler.resetSessionCallbackParameters(); + public void removeGlobalCallbackParameters() { + if (checkActivityHandler("resetting global callback parameters", true)) { + activityHandler.removeGlobalCallbackParameters(); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.resetSessionCallbackParametersI(); + activityHandler.removeGlobalCallbackParametersI(); } }); } @@ -385,15 +418,15 @@ public void run(final ActivityHandler activityHandler) { /** * Called to remove all added global partner parameters. */ - public void resetSessionPartnerParameters() { - if (checkActivityHandler("resetting session partner parameters", true)) { - activityHandler.resetSessionPartnerParameters(); + public void removeGlobalPartnerParameters() { + if (checkActivityHandler("resetting global partner parameters", true)) { + activityHandler.removeGlobalPartnerParameters(); return; } preLaunchActions.preLaunchActionsArray.add(new IRunActivityHandler() { @Override public void run(final ActivityHandler activityHandler) { - activityHandler.resetSessionPartnerParametersI(); + activityHandler.removeGlobalPartnerParametersI(); } }); } @@ -410,19 +443,6 @@ public void teardown() { activityHandler = null; } - /** - * Called to set user's push notifications token. - * - * @param token Push notifications token - */ - public void setPushToken(final String token) { - if (!checkActivityHandler("push token", true)) { - this.pushToken = token; - } else { - activityHandler.setPushToken(token, false); - } - } - /** * Called to set user's push notifications token. * @@ -452,23 +472,10 @@ public void gdprForgetMe(final Context context) { } } - /** - * Called to disable the third party sharing. - * - * @param context Application context - */ - public void disableThirdPartySharing(final Context context) { - if (!checkActivityHandler("disable third party sharing", true)) { - saveDisableThirdPartySharing(context); - return; - } - - activityHandler.disableThirdPartySharing(); - } - public void trackThirdPartySharing(final AdjustThirdPartySharing adjustThirdPartySharing) { if (!checkActivityHandler("third party sharing", true)) { - preLaunchActions.preLaunchAdjustThirdPartySharingArray.add(adjustThirdPartySharing); + preLaunchActions.preLaunchActionsArray.add(activityHandlerInner -> + activityHandlerInner.tryTrackThirdPartySharingI(adjustThirdPartySharing)); return; } @@ -477,26 +484,14 @@ public void trackThirdPartySharing(final AdjustThirdPartySharing adjustThirdPart public void trackMeasurementConsent(final boolean consentMeasurement) { if (!checkActivityHandler("measurement consent", true)) { - preLaunchActions.lastMeasurementConsentTracked = consentMeasurement; + preLaunchActions.preLaunchActionsArray.add(activityHandlerInner -> + activityHandlerInner.tryTrackMeasurementConsentI(consentMeasurement)); return; } activityHandler.trackMeasurementConsent(consentMeasurement); } - /** - * Track ad revenue from a source provider - * - * @param source Source of ad revenue information, see AdjustConfig.AD_REVENUE_* for some possible sources - * @param adRevenueJson JsonObject content of the ad revenue information - */ - public void trackAdRevenue(String source, JSONObject adRevenueJson) { - if (!checkActivityHandler("trackAdRevenue")) { - return; - } - activityHandler.trackAdRevenue(source, adRevenueJson); - } - /** * Track ad revenue from a source provider * @@ -525,34 +520,288 @@ public void trackPlayStoreSubscription(AdjustPlayStoreSubscription subscription) /** * Called to get value of unique Adjust device identifier. * - * @return Unique Adjust device indetifier + * @param onAdidReadListener Callback to get triggered once identifier is obtained. */ - public String getAdid() { + public void getAdid(OnAdidReadListener onAdidReadListener) { if (!checkActivityHandler("getAdid")) { - return null; + cachedAdidReadCallbacks.add(onAdidReadListener); + return; + } + activityHandler.getAdid(onAdidReadListener); + } + + /** + * Called to get value of unique Adjust device identifier. + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. + * @param onAdidReadListener Callback to get triggered once identifier is obtained. + */ + public void getAdidWithTimeout(Context context, long timeoutInMilliSec, OnAdidReadListener onAdidReadListener) { + if (!checkActivityHandler("getAdidWithTimeout")) { + ThreadExecutor executor = new SingleThreadCachedScheduler("getAdidWithTimeout"); + executor.submit(new Runnable() { + @Override + public void run() { + String adid = Util.getAdidFromActivityStateFile(context); + if (adid != null) { + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + onAdidReadListener.onAdidRead(adid); + } + }); + return; + } + + // adid not found locally + ActivityHandler.queueGetAdidWithTimeout(timeoutInMilliSec, onAdidReadListener, cachedAdidReadTimeoutCallbacks, context); + } + }); + return; } - return activityHandler.getAdid(); + activityHandler.getAdidWithTimeout(timeoutInMilliSec, onAdidReadListener); } /** * Called to get user's current attribution value. * - * @return AdjustAttribution object with current attribution value + * @param attributionReadListener Callback to get triggered once attribution is obtained. */ - public AdjustAttribution getAttribution() { + public void getAttribution(OnAttributionReadListener attributionReadListener) { if (!checkActivityHandler("getAttribution")) { - return null; + cachedAttributionReadCallbacks.add(attributionReadListener); + return; } - return activityHandler.getAttribution(); + activityHandler.getAttribution(attributionReadListener); + } + + /** + * Called to get user's current attribution value. + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. + * @param attributionReadListener Callback to get triggered once attribution is obtained. + */ + public void getAttributionWithTimeout(Context context, long timeoutInMilliSec, OnAttributionReadListener attributionReadListener) { + if (!checkActivityHandler("getAttributionWithTimeout")) { + ThreadExecutor executor = new SingleThreadCachedScheduler("getAttributionWithTimeout"); + executor.submit(new Runnable() { + @Override + public void run() { + AdjustAttribution adjustAttribution = Util.getAttributionFromAttributionFile(context); + if (adjustAttribution != null) { + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + attributionReadListener.onAttributionRead(adjustAttribution); + } + }); + } else { + // attribution not found locally + ActivityHandler.queueGetAttributionWithTimeout(timeoutInMilliSec, attributionReadListener, cachedAttributionReadTimeoutCallbacks, context); + } + } + }); + return; + } + activityHandler.getAttributionWithTimeout(timeoutInMilliSec, attributionReadListener); + } + + /** + * Called to get user's current third party sharing settings. + * + * @param context Application context + * @param timeoutInMilliSec Timeout in milliseconds. If third party sharing settings + * are not available within this time, the callback will return null. + * @param listener Callback to get triggered once third party sharing settings are obtained + */ + public void getThirdPartySharingSettingsWithTimeout(Context context, long timeoutInMilliSec, OnThirdPartySharingSettingsReadListener listener) { + if (!checkActivityHandler("getThirdPartySharingSettings")) { + ThreadExecutor executor = new SingleThreadCachedScheduler("getThirdPartySharingSettings"); + executor.submit(new Runnable() { + @Override + public void run() { + AdjustThirdPartySharingResult adjustThirdPartySharingResult = SharedPreferencesManager.getDefaultInstance(context).getThirdPartySharingResult(); + if (adjustThirdPartySharingResult != null) { + new Handler(context.getMainLooper()).post(new Runnable() { + @Override + public void run() { + listener.onThirdPartySharingSettingsRead(adjustThirdPartySharingResult); + } + }); + } else { + // third party sharing settings not found locally + ActivityHandler.queueGetThirdPartySharingSettingsWithTimeout(timeoutInMilliSec, listener, cachedThirdPartySharingTimeoutCallbacks, context); + } + } + }); + return; + } + activityHandler.getThirdPartySharingSettingsWithTimeout(timeoutInMilliSec, listener); } /** * Called to get native SDK version string. * - * @return Native SDK version string. + * @param onSdkVersionReadListener Callback to get triggered once SDK version is obtained. + */ + public void getSdkVersion(final OnSdkVersionReadListener onSdkVersionReadListener) { + new AsyncTaskExecutor() { + @Override + protected String doInBackground(Void... voids) { + return Util.getSdkVersion(); + } + + @Override + protected void onPostExecute(String sdkVersion) { + onSdkVersionReadListener.onSdkVersionRead(sdkVersion); + } + }.execute(); + } + + /** + * Called to get Google Install Referrer. + * + * @param context Application context + * @param onGooglePlayInstallReferrerReadListener Callback to obtain install referrer. */ - public String getSdkVersion() { - return Util.getSdkVersion(); + public void getGooglePlayInstallReferrer(final Context context, final OnGooglePlayInstallReferrerReadListener onGooglePlayInstallReferrerReadListener) { + InstallReferrer installReferrer = new InstallReferrer(context, new InstallReferrerReadListener() { + @Override + public void onInstallReferrerRead(ReferrerDetails referrerDetails, String referrerApi) { + onGooglePlayInstallReferrerReadListener.onInstallReferrerRead(new GooglePlayInstallReferrerDetails(referrerDetails)); + } + + @Override + public void onFail(String message) { + onGooglePlayInstallReferrerReadListener.onFail(message); + } + }); + installReferrer.startConnection(); + } + + + /** + * Called to get value of Amazon Advertising Identifier. + * + * @param context Application context + * @param onAmazonAdIdReadListener Callback to get triggered once identifier is obtained + */ + public void getAmazonAdId(final Context context, final OnAmazonAdIdReadListener onAmazonAdIdReadListener) { + DeviceInfo.getFireAdvertisingIdBypassConditions(context.getContentResolver(),onAmazonAdIdReadListener); + } + + /** + * Verify in app purchase from Google Play. + * + * @param purchase AdjustPurchase object to be verified + * @param callback Callback to be pinged with the verification results + */ + public void verifyPlayStorePurchase(final AdjustPlayStorePurchase purchase, + final OnPurchaseVerificationFinishedListener callback) { + if (!checkActivityHandler("verifyPurchase")) { + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 100, + "SDK needs to be initialized before making purchase verification request"); + callback.onVerificationFinished(result); + return; + } + activityHandler.verifyPlayStorePurchase(purchase, callback); + } + + /** + * Verify in app purchase from Google Play and track Adjust event associated with it. + * + * @param event AdjustEvent to be tracked + * @param callback Callback to be pinged with the verification results + */ + public void verifyAndTrackPlayStorePurchase(AdjustEvent event, OnPurchaseVerificationFinishedListener callback) { + if (!checkActivityHandler("verifyAndTrack")) { + if (callback != null) { + AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( + "not_verified", + 100, + "SDK needs to be initialized before making purchase verification request"); + callback.onVerificationFinished(result); + } + return; + } + activityHandler.verifyAndTrackPlayStorePurchase(event, callback); + } + + public void endFirstSessionDelay() { + if (!checkActivityHandler("endFirstSessionDelay")) { + return; + } + + activityHandler.endFirstSessionDelay(); + } + + public void enableCoppaComplianceInDelay() { + if (!checkActivityHandler("enableCoppaComplianceInDelay")) { + return; + } + + activityHandler.setCoppaComplianceInDelay(true); + } + + public void disableCoppaComplianceInDelay() { + if (!checkActivityHandler("disableCoppaComplianceInDelay")) { + return; + } + + activityHandler.setCoppaComplianceInDelay(false); + } + + public void enablePlayStoreKidsComplianceInDelay() { + if (!checkActivityHandler("enablePlayStoreKidsComplianceInDelay")) { + return; + } + + activityHandler.setPlayStoreKidsComplianceInDelay(true); + } + + public void disablePlayStoreKidsComplianceInDelay() { + if (!checkActivityHandler("disablePlayStoreKidsComplianceInDelay")) { + return; + } + + activityHandler.setPlayStoreKidsComplianceInDelay(false); + } + + public void setExternalDeviceIdInDelay(final String externalDeviceId) { + if (!checkActivityHandler("setExternalDeviceIdInDelay")) { + return; + } + + activityHandler.setExternalDeviceIdInDelay(externalDeviceId); + } + + /** + * Called to get last opened deeplink. + * + * @param context Application context + * @param onLastDeeplinkReadListener Callback to obtain last opened deeplink. + */ + public void getLastDeeplink(final Context context, final OnLastDeeplinkReadListener onLastDeeplinkReadListener) { + new AsyncTaskExecutor() { + @Override + protected Uri doInBackground(Void... voids) { + String cachedDeeplink = getCachedDeeplink(context); + try { + return Uri.parse(cachedDeeplink); + } catch (Exception e) { + return null; + } + } + + @Override + protected void onPostExecute(Uri deeplink) { + onLastDeeplinkReadListener.onLastDeeplinkRead(deeplink); + } + }.execute(); } /** @@ -622,8 +871,8 @@ private void saveRawReferrer(final String rawReferrer, final long clickTime, fin /** * Save preinstall referrer to shared preferences. * - * @param referrer Preinstall referrer content - * @param context Application context + * @param referrer Preinstall referrer content + * @param context Application context */ private void savePreinstallReferrer(final String referrer, final Context context) { SharedPreferencesManager.getDefaultInstance(context).savePreinstallReferrer(referrer); @@ -649,23 +898,33 @@ private void saveGdprForgetMe(final Context context) { } /** - * Save disable third party sharing choice to shared preferences. + * Save deeplink to shared preferences. * - * @param context Application context + * @param deeplink Deeplink Uri object + * @param clickTime Time when processDeeplink(Uri, Context) method was called + * @param context Application context */ - private void saveDisableThirdPartySharing(final Context context) { - SharedPreferencesManager.getDefaultInstance(context).setDisableThirdPartySharing(); + private void saveDeeplink(final AdjustDeeplink deeplink, final long clickTime, final Context context) { + SharedPreferencesManager.getDefaultInstance(context).saveDeeplink(deeplink, clickTime); } /** - * Save deep link to shared preferences. + * Cache deeplink to shared preferences. * * @param deeplink Deeplink Uri object - * @param clickTime Time when appWillOpenUrl(Uri, Context) method was called * @param context Application context */ - private void saveDeeplink(final Uri deeplink, final long clickTime, final Context context) { - SharedPreferencesManager.getDefaultInstance(context).saveDeeplink(deeplink, clickTime); + private void cacheDeeplink(final Uri deeplink, final Context context) { + SharedPreferencesManager.getDefaultInstance(context).cacheDeeplink(deeplink); + } + + /** + * Get cached deeplink from shared preferences. + * + * @param context Application context + */ + private String getCachedDeeplink(final Context context) { + return SharedPreferencesManager.getDefaultInstance(context).getCachedDeeplink(); } /** @@ -674,7 +933,8 @@ private void saveDeeplink(final Uri deeplink, final long clickTime, final Contex * @param context Application context */ private void setSendingReferrersAsNotSent(final Context context) { - SharedPreferencesManager.getDefaultInstance(context).setSendingReferrersAsNotSent(); + ThreadExecutor executor = new SingleThreadCachedScheduler("AdjustInstance"); + executor.submit(() -> SharedPreferencesManager.getDefaultInstance(context).setSendingReferrersAsNotSent()); } /** @@ -686,26 +946,6 @@ private boolean isInstanceEnabled() { return this.startEnabled == null || this.startEnabled; } - /** - * Verify in app purchase from Google Play. - * - * @param purchase AdjustPurchase object to be verified - * @param callback Callback to be pinged with the verification results - */ - public void verifyPurchase(AdjustPurchase purchase, OnPurchaseVerificationFinishedListener callback) { - if (!checkActivityHandler("verifyPurchase")) { - if (callback != null) { - AdjustPurchaseVerificationResult result = new AdjustPurchaseVerificationResult( - "not_verified", - 100, - "SDK needs to be initialized before making purchase verification request"); - callback.onVerificationFinished(result); - } - return; - } - activityHandler.verifyPurchase(purchase, callback); - } - /** * Used for testing purposes only. Do NOT use this method. * @@ -755,11 +995,13 @@ public void setTestOptions(AdjustTestOptions testOptions) { AdjustFactory.setPackageHandlerBackoffStrategy(BackoffStrategy.NO_WAIT); AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); } - if (testOptions.enableSigning != null && testOptions.enableSigning) { - AdjustFactory.enableSigning(); + if (testOptions.ignoreSystemLifecycleBootstrap != null) { + AdjustFactory.setIgnoreSystemLifecycleBootstrap( + testOptions.ignoreSystemLifecycleBootstrap.booleanValue()); } - if (testOptions.disableSigning != null && testOptions.disableSigning) { - AdjustFactory.disableSigning(); + if (testOptions.allowUrlStrategyFallback != null) { + AdjustFactory.setAllowUrlStrategyFallback( + testOptions.allowUrlStrategyFallback.booleanValue()); } } } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustLinkResolution.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustLinkResolution.java index 668fa2080..aa8e4eed6 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustLinkResolution.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustLinkResolution.java @@ -20,7 +20,11 @@ public interface AdjustLinkResolutionCallback { private static final String[] expectedUrlHostSuffixArray = { "adjust.com", "adj.st", - "go.link" + "go.link", + "adjust.net.in", + "adjust.cn", + "adjust.world", + "adjust.io" }; private AdjustLinkResolution() { } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPurchase.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStorePurchase.java similarity index 71% rename from Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPurchase.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStorePurchase.java index 25e32ed1d..20361f446 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPurchase.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStorePurchase.java @@ -1,10 +1,10 @@ package com.adjust.sdk; -public class AdjustPurchase { +public class AdjustPlayStorePurchase { private final String productId; private final String purchaseToken; - public AdjustPurchase(final String productId, final String purchaseToken) { + public AdjustPlayStorePurchase(final String productId, final String purchaseToken) { this.productId = productId; this.purchaseToken = purchaseToken; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStoreSubscription.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStoreSubscription.java index 7ee70db57..db4b24144 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStoreSubscription.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustPlayStoreSubscription.java @@ -10,7 +10,6 @@ public class AdjustPlayStoreSubscription { private String orderId; // [M] transaction_id private String signature; // [M] receipt private String purchaseToken; // [M] purchase_token - private String billingStore; // [M] billing_store private long purchaseTime; // [O] transaction_date private Map callbackParameters; // [O] callback_params private Map partnerParameters; // [O] partner_params @@ -32,7 +31,6 @@ public AdjustPlayStoreSubscription(final long price, // default values this.purchaseTime = -1; - this.billingStore = "GooglePlay"; } long getPrice() { @@ -59,10 +57,6 @@ String getSignature() { return signature; } - String getBillingStore() { - return billingStore; - } - String getPurchaseToken() { return purchaseToken; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustRemoteTrigger.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustRemoteTrigger.java new file mode 100644 index 000000000..2e6112bdc --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustRemoteTrigger.java @@ -0,0 +1,32 @@ +package com.adjust.sdk; + +import androidx.annotation.NonNull; + +import org.json.JSONObject; + +public class AdjustRemoteTrigger { + private final String label; + private final JSONObject payload; + + public AdjustRemoteTrigger(String label, JSONObject payload) { + this.label = label; + this.payload = payload; + } + + public String getLabel() { + return label; + } + + public JSONObject getPayload() { + return payload; + } + + @NonNull + @Override + public String toString() { + return "AdjustRemoteTrigger{" + + "label='" + label + '\'' + + ", payload=" + payload + + '}'; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSigner.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSigner.java index a7c0ecbaf..b89c34532 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSigner.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustSigner.java @@ -2,6 +2,7 @@ import android.content.Context; +import java.util.HashMap; import java.util.Map; public class AdjustSigner { @@ -12,32 +13,14 @@ public class AdjustSigner { private AdjustSigner() { } - public static void enableSigning(ILogger logger) { + public static boolean isPresent() { getSignerInstance(); - if (signerInstance == null) { - return; + if (signerInstance != null) { + return true; } - try { - Reflection.invokeInstanceMethod(signerInstance, "enableSigning", null); - } catch (Exception e) { - logger.warn("Invoking Signer enableSigning() received an error [%s]", e.getMessage()); - } - } - - public static void disableSigning(ILogger logger) { - getSignerInstance(); - - if (signerInstance == null) { - return; - } - - try { - Reflection.invokeInstanceMethod(signerInstance, "disableSigning", null); - } catch (Exception e) { - logger.warn("Invoking Signer disableSigning() received an error [%s]", e.getMessage()); - } + return false; } public static void onResume(ILogger logger){ @@ -54,23 +37,26 @@ public static void onResume(ILogger logger){ } } - public static void sign(Map parameters, String activityKind, String clientSdk, - Context context, ILogger logger) { + public static Map sign(final Map packageParams, + final Map extraParams, + final Context context, ILogger logger) { getSignerInstance(); - if (signerInstance == null) { - return; - } + Map outputParams = new HashMap<>(); - try { - logger.debug("Signing all the parameters"); - Reflection.invokeInstanceMethod(signerInstance, "sign", - new Class[]{Context.class, Map.class, String.class, String.class}, - context, parameters, activityKind, clientSdk); + if (signerInstance != null) { + try { + logger.debug("Signing all the parameters"); + Reflection.invokeInstanceMethod(signerInstance, "sign", + new Class[]{Context.class, Map.class, Map.class, Map.class}, + context, packageParams, extraParams, outputParams); - } catch (Exception e) { - logger.warn("Invoking Signer sign() for %s received an error [%s]", activityKind, e.getMessage()); + } catch (Exception e) { + logger.warn("Invoking Signer sign() received an error [%s]", e.getMessage()); + } } + + return outputParams; } private static void getSignerInstance() { diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustStoreInfo.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustStoreInfo.java new file mode 100644 index 000000000..9ea069e1c --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustStoreInfo.java @@ -0,0 +1,32 @@ +package com.adjust.sdk; + +public class AdjustStoreInfo { + String storeName; + String storeAppId; + + private static final ILogger logger = AdjustFactory.getLogger(); + + public AdjustStoreInfo(String storeName) { + if (!isValidStore(storeName)) { + return; + } + + this.storeName = storeName; + } + + public void setStoreAppId(String storeAppId) { + this.storeAppId = storeAppId; + } + + private boolean isValidStore(final String storeName) { + if (storeName == null) { + logger.error("Missing store name"); + return false; + } + if (storeName.isEmpty()) { + logger.error("Store name can't be empty"); + return false; + } + return true; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java index ad86b6f6a..19934b010 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTestOptions.java @@ -23,6 +23,6 @@ public class AdjustTestOptions { public Boolean teardown; public Boolean tryInstallReferrer = false; public Boolean noBackoffWait; - public Boolean enableSigning; - public Boolean disableSigning; + public Boolean ignoreSystemLifecycleBootstrap = true; + public Boolean allowUrlStrategyFallback = false; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustThirdPartySharingResult.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustThirdPartySharingResult.java new file mode 100644 index 000000000..188104ca1 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustThirdPartySharingResult.java @@ -0,0 +1,32 @@ +package com.adjust.sdk; + +public class AdjustThirdPartySharingResult { + private final String thirdPartySharingSettingsJson; + + public AdjustThirdPartySharingResult(final String thirdPartySharingSettingsJson) { + this.thirdPartySharingSettingsJson = thirdPartySharingSettingsJson; + } + + /** + * Returns third party sharing settings as a raw JSON string received from the backend. + */ + public String getThirdPartySharingSettingsJson() { + return thirdPartySharingSettingsJson; + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (other == this) return true; + if (!(other instanceof AdjustThirdPartySharingResult)) return false; + + AdjustThirdPartySharingResult otherResult = (AdjustThirdPartySharingResult) other; + return Util.equalString(thirdPartySharingSettingsJson, otherResult.thirdPartySharingSettingsJson); + } + + @Override + public int hashCode() { + return thirdPartySharingSettingsJson != null ? thirdPartySharingSettingsJson.hashCode() : 0; + } + +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTimeoutCallback.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTimeoutCallback.java new file mode 100644 index 000000000..5d6318ae5 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AdjustTimeoutCallback.java @@ -0,0 +1,54 @@ +package com.adjust.sdk; + +import com.adjust.sdk.scheduler.TimerOnce; + +public class AdjustTimeoutCallback { + private OnAdidReadListener onAdidReadListener; + private OnAttributionReadListener onAttributionReadListener; + private OnThirdPartySharingSettingsReadListener onThirdPartySharingSettingsReadListener; + private TimerOnce timeoutTimer; + + public AdjustTimeoutCallback(OnAdidReadListener onAdidReadListener) { + this.onAdidReadListener = onAdidReadListener; + } + + public AdjustTimeoutCallback(OnAttributionReadListener onAttributionReadListener) { + this.onAttributionReadListener = onAttributionReadListener; + } + + public AdjustTimeoutCallback(OnThirdPartySharingSettingsReadListener onThirdPartySharingSettingsReadListener) { + this.onThirdPartySharingSettingsReadListener = onThirdPartySharingSettingsReadListener; + } + + public void setOnAdidReadListener(OnAdidReadListener onAdidReadListener) { + this.onAdidReadListener = onAdidReadListener; + } + + public void setOnAttributionReadListener(OnAttributionReadListener onAttributionReadListener) { + this.onAttributionReadListener = onAttributionReadListener; + } + + public void setOnThirdPartySharingSettingsReadListener(OnThirdPartySharingSettingsReadListener onThirdPartySharingSettingsReadListener) { + this.onThirdPartySharingSettingsReadListener = onThirdPartySharingSettingsReadListener; + } + + public void setTimer(TimerOnce timer) { + this.timeoutTimer = timer; + } + + public OnAdidReadListener getOnAdidReadListener() { + return onAdidReadListener; + } + + public OnAttributionReadListener getOnAttributionReadListener() { + return onAttributionReadListener; + } + + public OnThirdPartySharingSettingsReadListener getOnThirdPartySharingSettingsReadListener() { + return onThirdPartySharingSettingsReadListener; + } + + public TimerOnce getTimeoutTimer() { + return timeoutTimer; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java index 407429ba4..8937f5f82 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/AttributionHandler.java @@ -19,7 +19,6 @@ import java.lang.ref.WeakReference; import java.util.HashMap; -import java.util.List; import java.util.Map; public class AttributionHandler implements IAttributionHandler, @@ -188,6 +187,7 @@ private void checkSessionResponseI(IActivityHandler activityHandler, SessionResponseData sessionResponseData) { checkAttributionI(activityHandler, sessionResponseData); + checkDeeplinkInSessionResponseI(sessionResponseData); activityHandler.launchSessionResponseTasks(sessionResponseData); } @@ -202,11 +202,11 @@ private void checkAttributionResponseI(IActivityHandler activityHandler, AttributionResponseData attributionResponseData) { checkAttributionI(activityHandler, attributionResponseData); - checkDeeplinkI(attributionResponseData); + checkDeeplinkInAttributionResponseI(attributionResponseData); activityHandler.launchAttributionResponseTasks(attributionResponseData); } - private void checkDeeplinkI(AttributionResponseData attributionResponseData) { + private void checkDeeplinkInAttributionResponseI(AttributionResponseData attributionResponseData) { if (attributionResponseData.jsonResponse == null) { return; } @@ -222,6 +222,18 @@ private void checkDeeplinkI(AttributionResponseData attributionResponseData) { attributionResponseData.deeplink = Uri.parse(deeplinkString); } + private void checkDeeplinkInSessionResponseI(SessionResponseData sessionResponseData) { + if (sessionResponseData.jsonResponse == null) { + return; + } + + String deeplinkString = sessionResponseData.jsonResponse.optString("deeplink", null); + if (deeplinkString == null) { + return; + } + sessionResponseData.deeplink = Uri.parse(deeplinkString); + } + private void sendAttributionRequestI() { if (activityHandlerWeakRef.get().getActivityState().isGdprForgotten) { return; @@ -235,25 +247,12 @@ private void sendAttributionRequestI() { ActivityPackage attributionPackage = buildAndGetAttributionPackage(activityHandlerWeakRef.get().getInternalState()); logger.verbose("%s", attributionPackage.getExtendedString()); - Map sendingParameters = generateSendingParametersI(); - activityPackageSender.sendActivityPackage( attributionPackage, - sendingParameters, + null, this); } - private Map generateSendingParametersI() { - HashMap sendingParameters = new HashMap<>(); - - long now = System.currentTimeMillis(); - String dateString = Util.dateFormatter.format(now); - - PackageBuilder.addString(sendingParameters, "sent_at", dateString); - - return sendingParameters; - } - private ActivityPackage buildAndGetAttributionPackage(ActivityHandler.InternalState internalState) { long now = System.currentTimeMillis(); IActivityHandler activityHandler = activityHandlerWeakRef.get(); @@ -261,7 +260,8 @@ private ActivityPackage buildAndGetAttributionPackage(ActivityHandler.InternalSt activityHandler.getAdjustConfig(), activityHandler.getDeviceInfo(), activityHandler.getActivityState(), - activityHandler.getSessionParameters(), + activityHandler.getGlobalParameters(), + activityHandler.getFirstSessionDelayManager(), now); packageBuilder.internalState = internalState; diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java index 9edad21fe..c709e1cb6 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Constants.java @@ -19,7 +19,8 @@ public interface Constants { int THIRTY_MINUTES = 30 * ONE_MINUTE; int ONE_HOUR = 2 * THIRTY_MINUTES; - int CONNECTION_TIMEOUT = Constants.ONE_MINUTE; + int CONNECTION_TIMEOUT = ONE_MINUTE; + int CONNECTION_TIMEOUT_VERIFY = 30 * ONE_SECOND; int SOCKET_TIMEOUT = Constants.ONE_MINUTE; int MAX_WAIT_INTERVAL = Constants.ONE_MINUTE; @@ -28,12 +29,20 @@ public interface Constants { String SUBSCRIPTION_URL = "https://subscription.adjust.com"; String PURCHASE_VERIFICATION_URL = "https://ssrv.adjust.com"; + String BASE_URL_FORMAT = "https://app.%s"; + String GDPR_URL_FORMAT = "https://gdpr.%s"; + String SUBSCRIPTION_URL_FORMAT = "https://subscription.%s"; + String PURCHASE_VERIFICATION_URL_FORMAT = "https://ssrv.%s"; + + String BASE_URL_NO_SUB_DOMAIN_FORMAT = "https://%s"; + String SCHEME = "https"; String AUTHORITY = "app.adjust.com"; - String CLIENT_SDK = "android4.38.5"; + String CLIENT_SDK = "android5.8.0"; String LOGTAG = "Adjust"; String REFTAG = "reftag"; String INSTALL_REFERRER = "install_referrer"; + String LICENSE_VERIFICATION = "google_lvl"; String REFERRER_API_GOOGLE = "google"; String REFERRER_API_HUAWEI_ADS = "huawei_ads"; String REFERRER_API_HUAWEI_APP_GALLERY = "huawei_app_gallery"; @@ -47,8 +56,9 @@ public interface Constants { String ACTIVITY_STATE_FILENAME = "AdjustIoActivityState"; String ATTRIBUTION_FILENAME = "AdjustAttribution"; - String SESSION_CALLBACK_PARAMETERS_FILENAME = "AdjustSessionCallbackParameters"; - String SESSION_PARTNER_PARAMETERS_FILENAME = "AdjustSessionPartnerParameters"; + String GLOBAL_CALLBACK_PARAMETERS_FILENAME = "AdjustGlobalCallbackParameters"; + String GLOBAL_PARTNER_PARAMETERS_FILENAME = "AdjustGlobalPartnerParameters"; + String EVENT_METADATA_FILENAME = "AdjustEventMetadata"; String MALFORMED = "malformed"; String SMALL = "small"; @@ -62,7 +72,6 @@ public interface Constants { String REFERRER = "referrer"; String ENCODING = "UTF-8"; - String SHA256 = "SHA-256"; int MINIMAL_ERROR_STATUS_CODE = 400; String CALLBACK_PARAMETERS = "callback_params"; @@ -84,6 +93,7 @@ public interface Constants { String CONTENT_PROVIDER = "content_provider"; String CONTENT_PROVIDER_INTENT_ACTION = "content_provider_intent_action"; String CONTENT_PROVIDER_NO_PERMISSION = "content_provider_no_permission"; + String CONTENT_PROVIDER_SAMSUNG_MAPS = "content_provider_samsung_maps"; String FILE_SYSTEM = "file_system"; String SYSTEM_INSTALLER_REFERRER = "system_installer_referrer"; @@ -94,4 +104,14 @@ public interface Constants { String ADJUST_PREINSTALL_CONTENT_PROVIDER_INTENT_ACTION = "com.attribution.REFERRAL_PROVIDER"; String ADJUST_PREINSTALL_FILE_SYSTEM_PATH = "/data/local/tmp/adjust.preinstall"; String EXTRA_SYSTEM_INSTALLER_REFERRER = "com.attribution.EXTRA_SYSTEM_INSTALLER_REFERRER"; + + String SAMSUNG_PREINSTALL_CONTENT_URI_AUTHORITY = "com.samsung.android.mapsagent.providers.apptracking"; + String SAMSUNG_PREINSTALL_CONTENT_URI_PATH = "info"; + String SAMSUNG_PREINSTALL_APP_TRACKING_ID = "ADJUSTSS0001"; + String SAMSUNG_PREINSTALL_PAYLOAD_PROVIDER = "samsung_maps"; + + String ADID_TIMEOUT_TIMER_NAME = "Get Adid timeout timer"; + String ATTRIBUTION_TIMEOUT_TIMER_NAME = "Get Attribution timeout timer"; + String TPS_SETTINGS_TIMEOUT_TIMER_NAME = "Get Third party sharing settings timeout timer"; + } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java index 3f939a42d..9989518f0 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/DeviceInfo.java @@ -59,13 +59,13 @@ class DeviceInfo { "0d247663b26a9031e15f84bc1c74d141ff98a02d76f85b2c8ab2571b6469b232d8e768a7f7" + "ca04f7abe4a775615916c07940656b58717457b42bd928a2"; - String playAdId; - String playAdIdSource; - int playAdIdAttempt = -1; + String googleAdId; + String googleAdIdSource; + int googleAdIdReadAttempt = -1; Boolean isTrackingEnabled; - private boolean nonGoogleIdsReadOnce = false; - private boolean playIdsReadOnce = false; - private boolean otherDeviceInfoParamsReadOnce = false; + private boolean androidIdReadOnce = false; + private boolean googleAdIdReadOnce = false; + private boolean otherDeviceIdsParamsReadOnce = false; String androidId; String fbAttributionId; String clientSdk; @@ -87,12 +87,11 @@ class DeviceInfo { String hardwareName; String abi; String buildName; - String appInstallTime; + long appInstallTime; String appUpdateTime; int uiMode; String appSetId; boolean isGooglePlayGamesForPC; - Boolean isSamsungCloudEnvironment; Map imeiParameters; Map oaidParameters; @@ -101,6 +100,12 @@ class DeviceInfo { int connectivityType; String mcc; String mnc; + AdjustStoreInfo storeInfoFromClient; + String storeIdFromSystem; + String initiatingPackageName; + String originatingPackageName; + Boolean isSystemApp; + Boolean isUpdatedSystemApp; DeviceInfo(AdjustConfig adjustConfig) { Context context = adjustConfig.context; @@ -128,44 +133,56 @@ class DeviceInfo { displayWidth = getDisplayWidth(displayMetrics); displayHeight = getDisplayHeight(displayMetrics); clientSdk = getClientSdk(adjustConfig.sdkPrefix); - fbAttributionId = getFacebookAttributionId(context); + if (Util.isFbIdReadingEnabled(adjustConfig)) { + fbAttributionId = getFacebookAttributionId(context); + } hardwareName = getHardwareName(); abi = getABI(); buildName = getBuildName(); appInstallTime = getAppInstallTime(packageInfo); appUpdateTime = getAppUpdateTime(packageInfo); uiMode = getDeviceUiMode(configuration); - if (Reflection.isAppRunningInSamsungCloudEnvironment(context, adjustConfig.logger)) { - isSamsungCloudEnvironment = true; - playAdId = Reflection.getSamsungCloudDevGoogleAdId(context, adjustConfig.logger); - playAdIdSource = "samsung_cloud_sdk"; - } - if (Util.canReadPlayIds(adjustConfig)) { + if (Util.isAppSetIdReadingEnabled(adjustConfig)) { appSetId = Reflection.getAppSetId(context); } + storeInfoFromClient = StoreInfoUtil.getStoreInfoFromClient(adjustConfig, context); + storeIdFromSystem = StoreInfoUtil.getStoreIdFromSystem(context); + initiatingPackageName = StoreInfoUtil.getInitiatingPackageName(context); + originatingPackageName = StoreInfoUtil.getOriginatingPackageName(context); + isSystemApp = StoreInfoUtil.getIsSystemApp(context); + isUpdatedSystemApp = StoreInfoUtil.getIsUpdatedSystemApp(context); } - void reloadPlayIds(final AdjustConfig adjustConfig) { - if (isSamsungCloudEnvironment != null && isSamsungCloudEnvironment) { + void reloadGoogleAdId(final AdjustConfig adjustConfig) { + if (googleAdIdReadOnce && adjustConfig.isDeviceIdsReadingOnceEnabled) { + if (!Util.isGoogleAdIdReadingEnabled(adjustConfig)) { + googleAdId = null; + isTrackingEnabled = null; + googleAdIdSource = null; + googleAdIdReadAttempt = -1; + } return; } - if (!Util.canReadPlayIds(adjustConfig)) { - return; - } + googleAdId = null; + isTrackingEnabled = null; + googleAdIdSource = null; + googleAdIdReadAttempt = -1; - if (playIdsReadOnce && adjustConfig.readDeviceInfoOnceEnabled) { + if (!Util.isGoogleAdIdReadingEnabled(adjustConfig)) { return; } Context context = adjustConfig.context; - String previousPlayAdId = playAdId; - Boolean previousIsTrackingEnabled = isTrackingEnabled; - playAdId = null; - isTrackingEnabled = null; - playAdIdSource = null; - playAdIdAttempt = -1; + if (Reflection.isAppRunningInSamsungCloudEnvironment(context, adjustConfig.logger)) { + googleAdId = Reflection.getSamsungCloudDevGoogleAdId(context, adjustConfig.logger); + googleAdIdSource = "samsung_cloud_sdk"; + googleAdIdReadOnce = true; + } + + String previousGoogleAdId = googleAdId; + Boolean previousIsTrackingEnabled = isTrackingEnabled; // attempt connecting to Google Play Service by own for (int serviceAttempt = 1; serviceAttempt <= 3; serviceAttempt += 1) { @@ -176,17 +193,17 @@ void reloadPlayIds(final AdjustConfig adjustConfig) { GooglePlayServicesClient.GooglePlayServicesInfo gpsInfo = GooglePlayServicesClient.getGooglePlayServicesInfo(context, timeoutServiceMilli); - if (playAdId == null) { - playAdId = gpsInfo.getGpsAdid(); - playIdsReadOnce = true; + if (googleAdId == null) { + googleAdId = gpsInfo.getGpsAdid(); + googleAdIdReadOnce = true; } if (isTrackingEnabled == null) { isTrackingEnabled = gpsInfo.isTrackingEnabled(); } - if (playAdId != null && isTrackingEnabled != null) { - playAdIdSource = "service"; - playAdIdAttempt = serviceAttempt; + if (googleAdId != null && isTrackingEnabled != null) { + googleAdIdSource = "service"; + googleAdIdReadAttempt = serviceAttempt; return; } } catch (Exception e) {} @@ -202,50 +219,51 @@ void reloadPlayIds(final AdjustConfig adjustConfig) { continue; } - if (playAdId == null) { + if (googleAdId == null) { // just needs a short timeout since it should be just accessing a POJO - playAdId = Util.getPlayAdId( + googleAdId = Util.getGoogleAdId( context, advertisingInfoObject, Constants.ONE_SECOND); - playIdsReadOnce = true; + googleAdIdReadOnce = true; } if (isTrackingEnabled == null) { // just needs a short timeout since it should be just accessing a POJO - isTrackingEnabled = Util.isPlayTrackingEnabled( + isTrackingEnabled = Util.isGoogleAdIdTrackingEnabled( context, advertisingInfoObject, Constants.ONE_SECOND); } - if (playAdId != null && isTrackingEnabled != null) { - playAdIdSource = "library"; - playAdIdAttempt = libAttempt; + if (googleAdId != null && isTrackingEnabled != null) { + googleAdIdSource = "library"; + googleAdIdReadAttempt = libAttempt; return; } } // if both weren't found, use previous values - if (playAdId == null) { - playAdId = previousPlayAdId; - playIdsReadOnce = true; + if (googleAdId == null) { + googleAdId = previousGoogleAdId; + googleAdIdReadOnce = true; } if (isTrackingEnabled == null) { isTrackingEnabled = previousIsTrackingEnabled; } } - void reloadNonPlayIds(final AdjustConfig adjustConfig) { - if (!Util.canReadNonPlayIds(adjustConfig)) { + void readAndroidId(final AdjustConfig adjustConfig) { + if (!Util.isAndroidIdReadingEnabled(adjustConfig)) { return; } - if (nonGoogleIdsReadOnce) { + if (androidIdReadOnce) { return; } androidId = Util.getAndroidId(adjustConfig.context); - nonGoogleIdsReadOnce = true; + androidIdReadOnce = true; } - void reloadOtherDeviceInfoParams(final AdjustConfig adjustConfig, final ILogger logger) { - if (adjustConfig.readDeviceInfoOnceEnabled && otherDeviceInfoParamsReadOnce) { + void reloadOtherDeviceInfoParams(final AdjustConfig adjustConfig, + final ILogger logger) { + if (adjustConfig.isDeviceIdsReadingOnceEnabled && otherDeviceIdsParamsReadOnce) { return; } @@ -257,10 +275,10 @@ void reloadOtherDeviceInfoParams(final AdjustConfig adjustConfig, final ILogger mcc = UtilDeviceIds.getMcc(adjustConfig.context, logger); mnc = UtilDeviceIds.getMnc(adjustConfig.context, logger); - otherDeviceInfoParamsReadOnce = true; + otherDeviceIdsParamsReadOnce = true; } - public static String getFireAdvertisingIdBypassConditions(ContentResolver contentResolver) { - return UtilDeviceIds.getFireAdvertisingId(contentResolver); + public static void getFireAdvertisingIdBypassConditions(ContentResolver contentResolver, OnAmazonAdIdReadListener onAmazonAdIdReadListener) { + UtilDeviceIds.getFireAdvertisingIdAsync(contentResolver, onAmazonAdIdReadListener); } private String getPackageName(Context context) { @@ -480,12 +498,11 @@ private String getABI() { return SupportedABIS[0]; } - private String getAppInstallTime(PackageInfo packageInfo) { - try { - return Util.dateFormatter.format(new Date(packageInfo.firstInstallTime)); - } catch (Exception ex) { - return null; + private long getAppInstallTime(PackageInfo packageInfo) { + if (packageInfo == null){ + return 0L; } + return packageInfo.firstInstallTime; } private String getAppUpdateTime(PackageInfo packageInfo) { @@ -500,7 +517,7 @@ private static class UtilDeviceIds { private static Map getImeiParameters(final AdjustConfig adjustConfig, final ILogger logger) { - if (adjustConfig.coppaCompliantEnabled) { + if (!Util.isDeviceIdsFromPluginsReadingEnabled(adjustConfig)) { return null; } @@ -509,14 +526,15 @@ private static Map getImeiParameters(final AdjustConfig adjustCo private static Map getOaidParameters(final AdjustConfig adjustConfig, final ILogger logger) { - if (adjustConfig.coppaCompliantEnabled) { + if (!Util.isDeviceIdsFromPluginsReadingEnabled(adjustConfig)) { return null; } return Reflection.getOaidParameters(adjustConfig.context, logger); } - private static String getFireAdvertisingId(final AdjustConfig adjustConfig) { - if (adjustConfig.coppaCompliantEnabled) { + private static String getFireAdvertisingId(final AdjustConfig adjustConfig) + { + if (!Util.isFireAdIdReadingEnabled(adjustConfig)) { return null; } @@ -534,13 +552,29 @@ private static String getFireAdvertisingId(final ContentResolver contentResolver } return null; } + + private static void getFireAdvertisingIdAsync(final ContentResolver contentResolver,final OnAmazonAdIdReadListener onAmazonAdIdReadListener) { + if (contentResolver == null) { + AdjustFactory.getLogger().error("contentResolver could not be retrieved"); + return; + } + try { + // get advertising + String amazonAdId = Settings.Secure.getString(contentResolver, "advertising_id"); + onAmazonAdIdReadListener.onAmazonAdIdRead(amazonAdId); + } catch (Exception ex) { + AdjustFactory.getLogger().error(ex.getMessage()); + } + } + private static Boolean getFireTrackingEnabled(final AdjustConfig adjustConfig) { - if (adjustConfig.coppaCompliantEnabled) { + if (!Util.isFireAdIdReadingEnabled(adjustConfig)) { return null; } return getFireTrackingEnabled(adjustConfig.context.getContentResolver()); } + private static Boolean getFireTrackingEnabled(final ContentResolver contentResolver) { try { // get user's tracking preference diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/EventMetadata.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/EventMetadata.java new file mode 100644 index 000000000..e3ea0e735 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/EventMetadata.java @@ -0,0 +1,65 @@ +package com.adjust.sdk; + + +import androidx.annotation.Nullable; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +public class EventMetadata implements Serializable { + private static final long serialVersionUID = 1L; + @SuppressWarnings("unchecked") + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("eventSequence", (Class>)(Class)Map.class), + }; + + private Map eventSequence; + + public EventMetadata() { + eventSequence = new HashMap<>(); + } + + public int incrementSequenceForEvent(String eventToken) { + @Nullable final Integer oldSequence = eventSequence.get(eventToken); + + // Sequence start at 1 when it does not exist + final int newSequence = (oldSequence != null ? oldSequence : 0) + 1; + + eventSequence.put(eventToken, newSequence); + + return newSequence; + } + + @Override + public boolean equals(Object other) { + if (other == this) return true; + if (other == null) return false; + if (getClass() != other.getClass()) return false; + EventMetadata otherEventMetadata = (EventMetadata) other; + + if (!Util.equalObject(eventSequence, otherEventMetadata.eventSequence)) return false; + + return true; + } + + @Override + public int hashCode() { + int hashCode = 17; + hashCode = Util.hashObject(eventSequence, hashCode); + return hashCode; + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + } + + private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { + ObjectInputStream.GetField fields = stream.readFields(); + eventSequence = Util.readObjectField(fields, "eventSequence", new HashMap<>()); + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/FirstSessionDelayManager.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/FirstSessionDelayManager.java new file mode 100644 index 000000000..8a6662ade --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/FirstSessionDelayManager.java @@ -0,0 +1,115 @@ +package com.adjust.sdk; + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +@Retention(RetentionPolicy.SOURCE) +@IntDef({ + DelayState.BEFORE_FILE_READ, + DelayState.NOT_STARTED, + DelayState.NOT_SET, + DelayState.STARTED, + DelayState.ENDED +}) +@interface DelayState { + int BEFORE_FILE_READ = 0; + int NOT_STARTED = 1; + int NOT_SET = 2; + int STARTED = 3; + int ENDED = 4; +} + +class FirstSessionDelayManager { + private final ActivityHandler activityHandler; + private final List apiActions; + private @DelayState int delayState; + + public FirstSessionDelayManager(final ActivityHandler activityHandler) { + this.activityHandler = activityHandler; + + apiActions = new ArrayList<>(); + + delayState = DelayState.BEFORE_FILE_READ; + } + + public void endFirstSessionDelayI() { + if (delayState != DelayState.STARTED) { + return; + } + delayState = DelayState.ENDED; + + runInitActions(); + } + + public void activityStateFileReadI() { + if (activityHandler.getActivityState() == null + && activityHandler.getAdjustConfig().isFirstSessionDelayEnabled) + { + delayState = DelayState.STARTED; + } else { + delayState = DelayState.NOT_SET; + + runInitActions(); + } + } + + private void runInitActions() { + activityHandler.initI(); + + for (final Runnable apiAction : apiActions) { + apiAction.run(); + } + } + + public void setCoppaComplianceInDelayI(final boolean isCoppaComplianceEnabled) { + if (delayState != DelayState.STARTED) { + return; + } + + activityHandler.getAdjustConfig().coppaComplianceEnabled = isCoppaComplianceEnabled; + } + + public void setPlayStoreKidsComplianceInDelayI(final boolean isPlayStoreKidsComplianceEnabled) { + if (delayState != DelayState.STARTED) { + return; + } + + activityHandler.getAdjustConfig().playStoreKidsComplianceEnabled = isPlayStoreKidsComplianceEnabled; + } + + public void setExternalDeviceIdInDelayI(final String externalDeviceId) { + if (delayState != DelayState.STARTED) { + return; + } + + activityHandler.getAdjustConfig().externalDeviceId = externalDeviceId; + } + + public void apiActionI(final String message, final Runnable runnable) { + if (delayState == DelayState.STARTED) { + activityHandler.getAdjustConfig().getLogger().debug( + "Enqueuing \"" + message + "\" action to be executed after first session delay ends"); + apiActions.add(runnable); + } else { + runnable.run(); + } + } + + public void preLaunchActionI(final String message, final IRunActivityHandler runnableAH) { + if (delayState == DelayState.STARTED) { + activityHandler.getAdjustConfig().getLogger().debug( + "Enqueuing \"" + message + "\" action to be executed after first session delay ends"); + activityHandler.getAdjustConfig().preLaunchActions.preLaunchActionsArray.add(runnableAH); + } else { + runnableAH.run(activityHandler); + } + } + + public boolean wasSet() { + return delayState != DelayState.NOT_SET && delayState != DelayState.BEFORE_FILE_READ; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionParameters.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/GlobalParameters.java similarity index 53% rename from Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionParameters.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/GlobalParameters.java index a49a81912..71f300dc9 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionParameters.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/GlobalParameters.java @@ -6,7 +6,7 @@ /** * Created by pfms on 29/07/2016. */ -public class SessionParameters { +public class GlobalParameters { Map callbackParameters; Map partnerParameters; @@ -15,10 +15,10 @@ public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (getClass() != other.getClass()) return false; - SessionParameters otherSessionParameters = (SessionParameters) other; + GlobalParameters otherGlobalParameters = (GlobalParameters) other; - if (!Util.equalObject(callbackParameters, otherSessionParameters.callbackParameters)) return false; - if (!Util.equalObject(partnerParameters, otherSessionParameters.partnerParameters)) return false; + if (!Util.equalObject(callbackParameters, otherGlobalParameters.callbackParameters)) return false; + if (!Util.equalObject(partnerParameters, otherGlobalParameters.partnerParameters)) return false; return true; } @@ -31,14 +31,14 @@ public int hashCode() { return hashCode; } - public SessionParameters deepCopy() { - SessionParameters newSessionParameters = new SessionParameters(); + public GlobalParameters deepCopy() { + GlobalParameters newGlobalParameters = new GlobalParameters(); if (this.callbackParameters != null) { - newSessionParameters.callbackParameters = new HashMap(this.callbackParameters); + newGlobalParameters.callbackParameters = new HashMap(this.callbackParameters); } if (this.partnerParameters != null) { - newSessionParameters.partnerParameters = new HashMap(this.partnerParameters); + newGlobalParameters.partnerParameters = new HashMap(this.partnerParameters); } - return newSessionParameters; + return newGlobalParameters; } } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/GooglePlayInstallReferrerDetails.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/GooglePlayInstallReferrerDetails.java new file mode 100644 index 000000000..04a03ce0a --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/GooglePlayInstallReferrerDetails.java @@ -0,0 +1,42 @@ +package com.adjust.sdk; + +public class GooglePlayInstallReferrerDetails { + public String installReferrer; // The referrer URL of the installed package. + public long referrerClickTimestampSeconds; // The client-side timestamp, when the referrer click happened. + public long installBeginTimestampSeconds; // The client-side timestamp, when app installation began. + public long referrerClickTimestampServerSeconds; // The server-side timestamp, when the referrer click happened. + public long installBeginTimestampServerSeconds; // The server-side timestamp, when app installation began. + public String installVersion; // The app's version at the time when the app was first installed. + public Boolean googlePlayInstant; // Indicates whether app's instant experience was launched within the past 7 days. + + GooglePlayInstallReferrerDetails(ReferrerDetails referrerDetails){ + if (referrerDetails == null){ + return; + } + this.installReferrer = referrerDetails.installReferrer; + this.referrerClickTimestampSeconds = referrerDetails.referrerClickTimestampSeconds; + this.installBeginTimestampSeconds = referrerDetails.installBeginTimestampSeconds; + this.referrerClickTimestampServerSeconds = referrerDetails.referrerClickTimestampServerSeconds; + this.installBeginTimestampServerSeconds = referrerDetails.installBeginTimestampServerSeconds; + this.installVersion = referrerDetails.installVersion; + this.googlePlayInstant = referrerDetails.googlePlayInstant; + } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " referrerClickTimestampSeconds : %d" + + " installBeginTimestampSeconds : %d" + + " referrerClickTimestampServerSeconds : %d" + + " installBeginTimestampServerSeconds : %d" + + " installVersion : %s" + + " googlePlayInstant : %s", + installReferrer, + referrerClickTimestampSeconds, + installBeginTimestampSeconds, + referrerClickTimestampServerSeconds, + installBeginTimestampServerSeconds, + installVersion, + googlePlayInstant); + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java index d4c527f05..753ec3cf5 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IActivityHandler.java @@ -1,9 +1,6 @@ package com.adjust.sdk; import android.content.Context; -import android.net.Uri; - -import org.json.JSONObject; /** * Created by pfms on 15/12/14. @@ -22,10 +19,13 @@ public interface IActivityHandler { void setEnabled(boolean enabled); boolean isEnabled(); + void isEnabled(OnIsEnabledListener onIsEnabledListener); + + void processDeeplink(AdjustDeeplink deeplink, long clickTime); - void readOpenUrl(Uri url, long clickTime); + void processAndResolveDeeplink(AdjustDeeplink deeplink, long clickTime, OnDeeplinkResolvedListener callback); - void readOpenUrl(Uri url, long clickTime, OnDeeplinkResolvedListener callback); + void processRemoteTriggers(ResponseData responseData); boolean updateAttributionI(AdjustAttribution attribution); @@ -45,23 +45,23 @@ public interface IActivityHandler { void sendInstallReferrer(ReferrerDetails referrerDetails, String referrerApi); + void sendLicenseVerificationData(LicenseData licenseVerificationData); + void setOfflineMode(boolean enabled); void setAskingAttribution(boolean askingAttribution); - void sendFirstPackages(); - - void addSessionCallbackParameter(String key, String value); + void addGlobalCallbackParameter(String key, String value); - void addSessionPartnerParameter(String key, String value); + void addGlobalPartnerParameter(String key, String value); - void removeSessionCallbackParameter(String key); + void removeGlobalCallbackParameter(String key); - void removeSessionPartnerParameter(String key); + void removeGlobalPartnerParameter(String key); - void resetSessionCallbackParameters(); + void removeGlobalCallbackParameters(); - void resetSessionPartnerParameters(); + void removeGlobalPartnerParameters(); void teardown(); @@ -69,27 +69,39 @@ public interface IActivityHandler { void gdprForgetMe(); - void disableThirdPartySharing(); - void trackThirdPartySharing(AdjustThirdPartySharing adjustThirdPartySharing); void trackMeasurementConsent(boolean consentMeasurement); - void trackAdRevenue(String source, JSONObject adRevenueJson); - void trackAdRevenue(AdjustAdRevenue adjustAdRevenue); void trackPlayStoreSubscription(AdjustPlayStoreSubscription subscription); - void verifyPurchase(AdjustPurchase purchase, OnPurchaseVerificationFinishedListener callback); + void verifyPlayStorePurchase(AdjustPlayStorePurchase purchase, OnPurchaseVerificationFinishedListener callback); + + void verifyAndTrackPlayStorePurchase(AdjustEvent event, OnPurchaseVerificationFinishedListener callback); + + void endFirstSessionDelay(); + + void setCoppaComplianceInDelay(final boolean isCoppaComplianceEnabled); + + void setPlayStoreKidsComplianceInDelay(final boolean isPlayStoreKidsComplianceEnabled); + + void setExternalDeviceIdInDelay(final String externalDeviceId); void gotOptOutResponse(); Context getContext(); - String getAdid(); + void getAdid(OnAdidReadListener onAdidReadListener); + + void getAdidWithTimeout(long timeoutInMilliSec, OnAdidReadListener onAdidReadListener); - AdjustAttribution getAttribution(); + void getAttribution(OnAttributionReadListener onAttributionReadListener); + + void getAttributionWithTimeout(long timeoutInMilliSec, OnAttributionReadListener onAttributionReadListener); + + void getThirdPartySharingSettingsWithTimeout(long timeoutInMilliSec, OnThirdPartySharingSettingsReadListener onThirdPartySharingSettingsReadListener); AdjustConfig getAdjustConfig(); @@ -97,7 +109,10 @@ public interface IActivityHandler { ActivityState getActivityState(); - SessionParameters getSessionParameters(); + GlobalParameters getGlobalParameters(); + + FirstSessionDelayManager getFirstSessionDelayManager(); ActivityHandler.InternalState getInternalState(); + } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java index 46ab4d532..bd447e60b 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/IPackageHandler.java @@ -18,8 +18,6 @@ void init(IActivityHandler activityHandler, void resumeSending(); - void updatePackages(SessionParameters sessionParameters); - void flush(); void teardown(); diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java index 100079033..d1f3398c9 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrer.java @@ -64,8 +64,8 @@ public class InstallReferrer implements InvocationHandler { /** * Boolean indicating whether service should be tried to read. * Either because it has not yet tried, - * or it did and it was successful - * or it did, was not successful, but it should not retry + * or it did and it was successful + * or it did, was not successful, but it should not retry */ private final AtomicBoolean shouldTryToRead; @@ -94,19 +94,16 @@ public class InstallReferrer implements InvocationHandler { */ private final InstallReferrerReadListener referrerCallback; - private Object playInstallReferrer; - private ThreadExecutor executor; /** * Default constructor. * - * @param context Application context + * @param context Application context * @param referrerCallback Callback for referrer information */ public InstallReferrer(final Context context, final InstallReferrerReadListener referrerCallback) { this.logger = AdjustFactory.getLogger(); - this.playInstallReferrer = createInstallReferrer(context, referrerCallback, logger); this.context = context; this.shouldTryToRead = new AtomicBoolean(true); this.retries = 0; @@ -120,51 +117,41 @@ public void run() { this.executor = new SingleThreadCachedScheduler("InstallReferrer"); } - private Object createInstallReferrer(Context context, InstallReferrerReadListener referrerCallback, ILogger logger) { - return Reflection.createInstance("com.adjust.sdk.play.InstallReferrer", - new Class[]{Context.class, InstallReferrerReadListener.class, ILogger.class}, - context, referrerCallback, logger); - } - /** * Start connection with install referrer service. */ public void startConnection() { - if (this.playInstallReferrer != null) { - try { - Reflection.invokeInstanceMethod(this.playInstallReferrer, "startConnection", null); - return; - } catch (Exception e) { - logger.error("Call to Play startConnection error: %s", e.getMessage()); - } - } - - if (!AdjustFactory.getTryInstallReferrer()) { + if (! AdjustFactory.getTryInstallReferrer()) { + this.referrerCallback.onFail("Sdk has been configured to not try install referrer"); return; } closeReferrerClient(); - if (!shouldTryToRead.get()) { - logger.debug("Should not try to read Install referrer"); + if (! shouldTryToRead.get()) { + this.referrerCallback.onFail("Should not try to read the install referrer any longer"); return; } if (context == null) { + this.referrerCallback.onFail("Requires context to read the install referrer"); return; } this.referrerClient = createInstallReferrerClient(context); if (this.referrerClient == null) { + // this.referrerCallback.onFail called inside createInstallReferrerClient(context) return; } - Class listenerClass = getInstallReferrerStateListenerClass(); + final Class listenerClass = getInstallReferrerStateListenerClass(); if (listenerClass == null) { + // this.referrerCallback.onFail called inside getInstallReferrerStateListenerClass() return; } - Object listenerProxy = createProxyInstallReferrerStateListener(listenerClass); + final Object listenerProxy = createProxyInstallReferrerStateListener(listenerClass); if (listenerProxy == null) { + // this.referrerCallback.onFail called inside createProxyInstallReferrerStateListener(listenerClass) return; } @@ -183,14 +170,14 @@ private Object createInstallReferrerClient(final Context context) { "newBuilder", new Class[]{Context.class}, context); return Reflection.invokeInstanceMethod(builder, "build", null); - } catch (ClassNotFoundException ex) { - logger.warn("InstallReferrer not integrated in project (%s) thrown by (%s)", - ex.getMessage(), - ex.getClass().getCanonicalName()); - } catch (Exception ex) { - logger.error("createInstallReferrerClient error (%s) from (%s)", - ex.getMessage(), - ex.getClass().getCanonicalName()); + } catch (final ClassNotFoundException ex) { + this.referrerCallback.onFail( + Util.formatString("InstallReferrer not integrated in project (%s) thrown by (%s)", + ex.getMessage(), ex.getClass().getCanonicalName())); + } catch (final Exception ex) { + this.referrerCallback.onFail( + Util.formatString("createInstallReferrerClient error (%s) from (%s)", + ex.getMessage(), ex.getClass().getCanonicalName())); } return null; @@ -205,9 +192,9 @@ private Class getInstallReferrerStateListenerClass() { try { return Class.forName(PACKAGE_BASE_NAME + "api.InstallReferrerStateListener"); } catch (Exception ex) { - logger.error("getInstallReferrerStateListenerClass error (%s) from (%s)", - ex.getMessage(), - ex.getClass().getCanonicalName()); + this.referrerCallback.onFail( + Util.formatString("getInstallReferrerStateListenerClass error (%s) from (%s)", + ex.getMessage(), ex.getClass().getCanonicalName())); } return null; } @@ -227,10 +214,10 @@ private Object createProxyInstallReferrerStateListener(final Class installReferr new Class[]{installReferrerStateListenerClass}, this ); - } catch (IllegalArgumentException ex) { - logger.error("InstallReferrer proxy violating parameter restrictions"); - } catch (NullPointerException ex) { - logger.error("Null argument passed to InstallReferrer proxy"); + } catch (final IllegalArgumentException ex) { + this.referrerCallback.onFail("InstallReferrer proxy violating parameter restrictions"); + } catch (final NullPointerException ex) { + this.referrerCallback.onFail("Null argument passed to InstallReferrer proxy"); } return proxyInstance; @@ -246,16 +233,18 @@ private void startConnection(final Class listenerClass, final Object listenerPro try { Reflection.invokeInstanceMethod(this.referrerClient, "startConnection", new Class[]{listenerClass}, listenerProxy); - } catch (InvocationTargetException ex) { - // Check for an underlying root cause in the stack trace + } catch (final InvocationTargetException ex) { if (Util.hasRootCause(ex)) { - logger.error("InstallReferrer encountered an InvocationTargetException %s", - Util.getRootCause(ex)); + // Check for an underlying root cause in the stack trace + referrerCallback.onFail( + Util.formatString("InstallReferrer encountered an InvocationTargetException %s", + Util.getRootCause(ex))); + } else { + referrerCallback.onFail("InstallReferrer encountered an InvocationTargetException"); } - } catch (Exception ex) { - logger.error("startConnection error (%s) thrown by (%s)", - ex.getMessage(), - ex.getClass().getCanonicalName()); + } catch (final Exception ex) { + referrerCallback.onFail(Util.formatString("startConnection error (%s) thrown by (%s)", + ex.getMessage(), ex.getClass().getCanonicalName())); } } @@ -264,18 +253,15 @@ private void startConnection(final Class listenerClass, final Object listenerPro */ @Override public Object invoke(final Object proxy, final Method method, final Object[] args) - throws Throwable - { + throws Throwable { executor.submit(new Runnable() { @Override - public - void run() { + public void run() { try { invokeI(proxy, method, args); - } catch (Throwable throwable) { - logger.error("invoke error (%s) thrown by (%s)", - throwable.getMessage(), - throwable.getClass().getCanonicalName()); + } catch (final Throwable throwable) { + referrerCallback.onFail(Util.formatString("invoke error (%s) thrown by (%s)", + throwable.getMessage(), throwable.getClass().getCanonicalName())); } } }); @@ -284,15 +270,15 @@ void run() { } private Object invokeI(final Object proxy, final Method method, Object[] args) - throws Throwable + throws Throwable { if (method == null) { - logger.error("InstallReferrer invoke method null"); + this.referrerCallback.onFail("InstallReferrer invoke method null"); return null; } String methodName = method.getName(); if (methodName == null) { - logger.error("InstallReferrer invoke method name null"); + this.referrerCallback.onFail("InstallReferrer invoke method name null"); return null; } // Prints the method being invoked @@ -308,26 +294,31 @@ private Object invokeI(final Object proxy, final Method method, Object[] args) // if the method name equals some method's name then call your method if (methodName.equals("onInstallReferrerSetupFinished")) { if (args.length != 1) { - logger.error("InstallReferrer invoke onInstallReferrerSetupFinished args lenght not 1: %d", args.length); + this.referrerCallback.onFail(Util.formatString( + "InstallReferrer invoke onInstallReferrerSetupFinished args lenght not 1: %d", + args.length)); return null; } Object arg = args[0]; if (!(arg instanceof Integer)) { - logger.error("InstallReferrer invoke onInstallReferrerSetupFinished arg not int"); + this.referrerCallback.onFail("InstallReferrer invoke onInstallReferrerSetupFinished arg not int"); return null; } Integer responseCode = (Integer) arg; if (responseCode == null) { - logger.error("InstallReferrer invoke onInstallReferrerSetupFinished responseCode arg is null"); + this.referrerCallback.onFail("InstallReferrer invoke onInstallReferrerSetupFinished responseCode arg is null"); return null; } onInstallReferrerSetupFinishedIntI(responseCode); } else if (methodName.equals("onInstallReferrerServiceDisconnected")) { logger.debug("Connection to install referrer service was lost. Retrying ..."); - retryI(); + retryI("onInstallReferrerServiceDisconnected"); + } else { + this.referrerCallback.onFail( + Util.formatString("Reflection call method name not expected: %s", methodName)); } return null; } @@ -369,19 +360,24 @@ private void onInstallReferrerSetupFinishedIntI(final int responseCode) { // Stuff successfully read, try to send it. referrerCallback.onInstallReferrerRead(installReferrerDetails, Constants.REFERRER_API_GOOGLE); } catch (Exception e) { - logger.warn("Couldn't get install referrer from client (%s). Retrying...", e.getMessage()); + logger.warn( + "Couldn't get install referrer from client (%s). Retrying...", + e.getMessage()); + // retrying, so no need to referrerCallback.onFail retryAtEnd = true; } break; /** Install Referrer API not supported by the installed Play Store app. */ case STATUS_FEATURE_NOT_SUPPORTED: // API not available on the current Play Store app - logger.debug("Install Referrer API not supported by the installed Play Store app. Closing connection"); + this.referrerCallback.onFail( + "Install Referrer API not supported by the installed Play Store app. Closing connection"); break; /** Could not initiate connection to the Install Referrer service. */ case STATUS_SERVICE_UNAVAILABLE: // Connection could not be established logger.debug("Could not initiate connection to the Install Referrer service. Retrying..."); + // retrying, so no need to referrerCallback.onFail retryAtEnd = true; break; /** @@ -395,19 +391,23 @@ private void onInstallReferrerSetupFinishedIntI(final int responseCode) { case STATUS_SERVICE_DISCONNECTED: // Play Store service is not connected now - potentially transient state logger.debug("Play Store service is not connected now. Retrying..."); + // retrying, so no need to referrerCallback.onFail retryAtEnd = true; break; /** General errors caused by incorrect usage */ case STATUS_DEVELOPER_ERROR: logger.debug("Install Referrer API general errors caused by incorrect usage. Retrying..."); + // retrying, so no need to referrerCallback.onFail retryAtEnd = true; break; default: - logger.debug("Unexpected response code of install referrer response: %d. Closing connection", responseCode); + this.referrerCallback.onFail(Util.formatString( + "Unexpected response code of install referrer response: %d. Closing connection", + responseCode)); break; } if (retryAtEnd) { - retryI(); + retryI("end of onInstallReferrerSetupFinishedIntI"); } else { shouldTryToRead.set(false); closeReferrerClient(); @@ -583,15 +583,18 @@ private Boolean getBooleanGooglePlayInstantParam(final Object referrerDetails) { /** * Retry connection to install referrer service. */ - private void retryI() { - if (!shouldTryToRead.get()) { - logger.debug("Should not try to read Install referrer"); + private void retryI(final String source) { + if (! shouldTryToRead.get()) { + this.referrerCallback.onFail( + Util.formatString("Should not try to read Install referrer from %s", source)); closeReferrerClient(); return; } // Check increase retry counter if (retries + 1 > Constants.MAX_INSTALL_REFERRER_RETRIES) { - logger.debug("Limit number of retry of %d for install referrer surpassed", Constants.MAX_INSTALL_REFERRER_RETRIES); + this.referrerCallback.onFail( + Util.formatString("Limit number of retry of %d for install referrer surpassed from %s", + Constants.MAX_INSTALL_REFERRER_RETRIES, source)); return; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerHuawei.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerHuawei.java deleted file mode 100644 index 990efe54f..000000000 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerHuawei.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.adjust.sdk; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class InstallReferrerHuawei { - - /** - * Huawei install referrer provider content authority. - */ - private static final String REFERRER_PROVIDER_AUTHORITY = "com.huawei.appmarket.commondata"; - - /** - * Huawei install referrer provider content uri. - */ - private static final String REFERRER_PROVIDER_URI = "content://" + REFERRER_PROVIDER_AUTHORITY + "/item/5"; - - /** - * Huawei install referrer provider column index referrer. - */ - private static final int COLUMN_INDEX_REFERRER = 0; - - /** - * Huawei install referrer provider column index click time. - */ - private static final int COLUMN_INDEX_CLICK_TIME = 1; - - /** - * Huawei install referrer provider column index install time. - */ - private static final int COLUMN_INDEX_INSTALL_TIME = 2; - - /** - * Huawei install referrer provider column index track ID. - */ - private static final int COLUMN_INDEX_TRACK_ID = 4; - - /** - * Adjust logger instance. - */ - private ILogger logger; - - /** - * Application context. - */ - private Context context; - - /** - * Huawei Referrer callback. - */ - private final InstallReferrerReadListener referrerCallback; - - /** - * Boolean indicating whether service should be tried to read. - * Either because it has not yet tried, - * or it did and it was successful - * or it did, was not successful, but it should not retry - */ - private final AtomicBoolean shouldTryToRead; - - /** - * Default constructor. - * - * @param context Application context - * @param referrerCallback Callback for referrer information - */ - public InstallReferrerHuawei(final Context context, - final InstallReferrerReadListener referrerCallback) - { - this.logger = AdjustFactory.getLogger(); - this.context = context; - this.referrerCallback = referrerCallback; - this.shouldTryToRead = new AtomicBoolean(true); - } - - public void readReferrer() { - if (!shouldTryToRead.get()) { - logger.debug("Should not try to read Install referrer Huawei"); - return; - } - - if (!Util.resolveContentProvider(context, REFERRER_PROVIDER_AUTHORITY)) { - return; - } - - Cursor cursor = null; - Uri uri = Uri.parse(REFERRER_PROVIDER_URI); - ContentResolver contentResolver = context.getContentResolver(); - - String[] packageName = new String[] { context.getPackageName() }; - try { - cursor = contentResolver.query(uri, null, null, packageName, null); - - if (cursor != null && cursor.moveToFirst()) { - - String referrerHuaweiAds = cursor.getString(COLUMN_INDEX_REFERRER); - String referrerHuaweiAppGallery = cursor.getString(COLUMN_INDEX_TRACK_ID); - - logger.debug("InstallReferrerHuawei reads " + - "index_referrer[%s] index_track_id[%s]", - referrerHuaweiAds, referrerHuaweiAppGallery); - - String clickTime = cursor.getString(COLUMN_INDEX_CLICK_TIME); - String installTime = cursor.getString(COLUMN_INDEX_INSTALL_TIME); - - logger.debug("InstallReferrerHuawei reads " + - "clickTime[%s] installTime[%s]", clickTime, installTime ); - - long referrerClickTimestampSeconds = Long.parseLong(clickTime); - long installBeginTimestampSeconds = Long.parseLong(installTime); - - if (isValidReferrerHuaweiAds(referrerHuaweiAds)) { - ReferrerDetails referrerDetails = - new ReferrerDetails(referrerHuaweiAds, - referrerClickTimestampSeconds, - installBeginTimestampSeconds); - - referrerCallback.onInstallReferrerRead(referrerDetails, - Constants.REFERRER_API_HUAWEI_ADS); - } - - if (isValidReferrerHuaweiAppGallery(referrerHuaweiAppGallery)) { - ReferrerDetails referrerDetails = - new ReferrerDetails(referrerHuaweiAppGallery, - referrerClickTimestampSeconds, - installBeginTimestampSeconds); - - referrerCallback.onInstallReferrerRead(referrerDetails, - Constants.REFERRER_API_HUAWEI_APP_GALLERY); - } - - } else { - logger.debug("InstallReferrerHuawei fail to read referrer for " + - "package [%s] and content uri [%s]", - context.getPackageName(), uri.toString()); - } - } catch (Exception e) { - logger.debug("InstallReferrerHuawei error [%s]", e.getMessage()); - } finally { - if (cursor != null) { - cursor.close(); - } - } - - shouldTryToRead.set(false); - } - - private boolean isValidReferrerHuaweiAds(String referrerHuaweiAds) { - if (referrerHuaweiAds == null) { - return false; - } - - if (referrerHuaweiAds.isEmpty()) { - return false; - } - - return true; - } - - private boolean isValidReferrerHuaweiAppGallery(String referrerHuaweiAppGallery) { - if (referrerHuaweiAppGallery == null) { - return false; - } - - if (referrerHuaweiAppGallery.isEmpty()) { - return false; - } - - return true; - } - - -} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java index dff0121d3..3a226ed28 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/InstallReferrerReadListener.java @@ -2,4 +2,6 @@ public interface InstallReferrerReadListener { void onInstallReferrerRead(ReferrerDetails referrerDetails, String referrerApi); + void onFail(String message); + } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/LicenseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/LicenseData.java new file mode 100644 index 000000000..3dd4bfafc --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/LicenseData.java @@ -0,0 +1,37 @@ +package com.adjust.sdk; + +public class LicenseData { + private final String signedData; + private final String signature; + private final int responseCode; + + public LicenseData(String signedData, String signature, int responseCode) { + this.signedData = signedData; + this.signature = signature; + this.responseCode = responseCode; + } + + public String getSignedData() { + return signedData; + } + + public String getSignature() { + return signature; + } + + public int getResponseCode() { + return responseCode; + } + + public boolean isValid() { + + if (this.signedData == null || this.signature == null) { + return false; + } + + if (this.signedData.isEmpty() || this.signature.isEmpty()){ + return false; + } + return true; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java index ea9a1eb23..82a88c5e1 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/LogLevel.java @@ -6,7 +6,7 @@ * Created by pfms on 11/03/15. */ public enum LogLevel { - VERBOSE(Log.VERBOSE), DEBUG(Log.DEBUG), INFO(Log.INFO), WARN(Log.WARN), ERROR(Log.ERROR), ASSERT(Log.ASSERT), SUPRESS(8); + VERBOSE(Log.VERBOSE), DEBUG(Log.DEBUG), INFO(Log.INFO), WARN(Log.WARN), ERROR(Log.ERROR), ASSERT(Log.ASSERT), SUPPRESS(8); final int androidLogLevel; LogLevel(final int androidLogLevel) { diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ObjectInputFilterStream.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ObjectInputFilterStream.java new file mode 100644 index 000000000..6f2a040d5 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ObjectInputFilterStream.java @@ -0,0 +1,45 @@ +package com.adjust.sdk; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class ObjectInputFilterStream extends ObjectInputStream { + static final Set ALLOWED_CLASSES = new HashSet<>(Arrays.asList( + "java.lang.Boolean", + "java.lang.Double", + "java.lang.Enum", + "java.lang.Float", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Number", + "java.lang.String", + "java.util.ArrayList", + "java.util.HashMap", + "java.util.LinkedHashMap", + "java.util.LinkedList", + "com.adjust.sdk.ActivityKind", + "com.adjust.sdk.ActivityPackage", + "com.adjust.sdk.ActivityState", + "com.adjust.sdk.AdjustAttribution", + "com.adjust.sdk.EventMetadata" + )); + + public ObjectInputFilterStream(InputStream in) throws IOException { + super(in); + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundException, IOException { + // Block any unknown classes + if (!ALLOWED_CLASSES.contains(desc.getName())) { + throw new InvalidClassException("Blocked deserialization", desc.getName()); + } + return super.resolveClass(desc); + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAdidReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAdidReadListener.java new file mode 100644 index 000000000..35d128e4d --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAdidReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnAdidReadListener { + void onAdidRead(String adid); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAmazonAdIdReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAmazonAdIdReadListener.java new file mode 100644 index 000000000..a5351f848 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAmazonAdIdReadListener.java @@ -0,0 +1,6 @@ +package com.adjust.sdk; + +public interface OnAmazonAdIdReadListener { + + void onAmazonAdIdRead(String amazonAdId); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAttributionReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAttributionReadListener.java new file mode 100644 index 000000000..3ac276b43 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnAttributionReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnAttributionReadListener { + void onAttributionRead(AdjustAttribution attribution); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeferredDeeplinkResponseListener.java similarity index 72% rename from Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java rename to Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeferredDeeplinkResponseListener.java index 6075055ad..70762d87a 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeeplinkResponseListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeferredDeeplinkResponseListener.java @@ -5,6 +5,6 @@ /** * Created by pfms on 22/03/16. */ -public interface OnDeeplinkResponseListener { +public interface OnDeferredDeeplinkResponseListener { boolean launchReceivedDeeplink(Uri deeplink); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java deleted file mode 100644 index dcc7929b6..000000000 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnDeviceIdsRead.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 29/01/16. - */ -public interface OnDeviceIdsRead { - void onGoogleAdIdRead(String googleAdId); -} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java index dd57eeee1..315a1682c 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingFailedListener.java @@ -4,5 +4,5 @@ * Created by pfms on 04/01/16. */ public interface OnEventTrackingFailedListener { - void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData); + void onEventTrackingFailed(AdjustEventFailure eventFailureResponseData); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java index 5223a90cf..0ac249012 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnEventTrackingSucceededListener.java @@ -4,5 +4,5 @@ * Created by pfms on 04/01/16. */ public interface OnEventTrackingSucceededListener { - void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData); + void onEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGoogleAdIdReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGoogleAdIdReadListener.java new file mode 100644 index 000000000..b5a5bc2d7 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGoogleAdIdReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnGoogleAdIdReadListener { + void onGoogleAdIdRead(String googleAdId); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGooglePlayInstallReferrerReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGooglePlayInstallReferrerReadListener.java new file mode 100644 index 000000000..46c3212ae --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnGooglePlayInstallReferrerReadListener.java @@ -0,0 +1,7 @@ +package com.adjust.sdk; + +public interface OnGooglePlayInstallReferrerReadListener { + void onInstallReferrerRead(GooglePlayInstallReferrerDetails referrerDetails); + void onFail(String message); + +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnIsEnabledListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnIsEnabledListener.java new file mode 100644 index 000000000..2f98b7dc4 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnIsEnabledListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnIsEnabledListener { + void onIsEnabledRead(boolean isEnabled); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnLastDeeplinkReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnLastDeeplinkReadListener.java new file mode 100644 index 000000000..2c34061c3 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnLastDeeplinkReadListener.java @@ -0,0 +1,7 @@ +package com.adjust.sdk; + +import android.net.Uri; + +public interface OnLastDeeplinkReadListener { + void onLastDeeplinkRead(Uri deeplink); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnRemoteTriggerListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnRemoteTriggerListener.java new file mode 100644 index 000000000..9f59e7d8c --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnRemoteTriggerListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnRemoteTriggerListener { + void onRemoteTrigger(AdjustRemoteTrigger trigger); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSdkVersionReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSdkVersionReadListener.java new file mode 100644 index 000000000..7732e1de4 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSdkVersionReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnSdkVersionReadListener { + void onSdkVersionRead(String sdkVersion); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java index 66a01f5d8..17bdb1b21 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingFailedListener.java @@ -4,5 +4,5 @@ * Created by pfms on 16/02/16. */ public interface OnSessionTrackingFailedListener { - void onFinishedSessionTrackingFailed(AdjustSessionFailure failureResponseData); + void onSessionTrackingFailed(AdjustSessionFailure failureResponseData); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java index 24d576ad8..138d12ed4 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnSessionTrackingSucceededListener.java @@ -4,5 +4,5 @@ * Created by pfms on 16/02/16. */ public interface OnSessionTrackingSucceededListener { - void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData); + void onSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsChangedListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsChangedListener.java new file mode 100644 index 000000000..d6755b8dc --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsChangedListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnThirdPartySharingSettingsChangedListener { + void onThirdPartySharingSettingsChanged(AdjustThirdPartySharingResult adjustThirdPartySharingResult); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsReadListener.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsReadListener.java new file mode 100644 index 000000000..d47080663 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/OnThirdPartySharingSettingsReadListener.java @@ -0,0 +1,5 @@ +package com.adjust.sdk; + +public interface OnThirdPartySharingSettingsReadListener { + void onThirdPartySharingSettingsRead(AdjustThirdPartySharingResult adjustThirdPartySharingResult); +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java index 158610ca1..627f76851 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageBuilder.java @@ -22,7 +22,8 @@ public class PackageBuilder { private DeviceInfo deviceInfo; private AdjustConfig adjustConfig; private ActivityStateCopy activityStateCopy; - private SessionParameters sessionParameters; + private GlobalParameters globalParameters; + private FirstSessionDelayManager firstSessionDelayManager; long clickTimeInSeconds = -1; long clickTimeInMilliseconds = -1; @@ -42,13 +43,13 @@ public class PackageBuilder { Map extraParameters; Boolean isClick; ActivityHandler.InternalState internalState; + LicenseData licenseData; - private class ActivityStateCopy { + static class ActivityStateCopy { int eventCount = -1; int sessionCount = -1; int subsessionCount = -1; long timeSpent = -1; - long lastInterval = -1; long sessionLength = -1; String uuid = null; String pushToken = null; @@ -61,7 +62,6 @@ private class ActivityStateCopy { this.sessionCount = activityState.sessionCount; this.subsessionCount = activityState.subsessionCount; this.timeSpent = activityState.timeSpent; - this.lastInterval = activityState.lastInterval; this.sessionLength = activityState.sessionLength; this.uuid = activityState.uuid; this.pushToken = activityState.pushToken; @@ -71,17 +71,19 @@ private class ActivityStateCopy { PackageBuilder(AdjustConfig adjustConfig, DeviceInfo deviceInfo, ActivityState activityState, - SessionParameters sessionParameters, + GlobalParameters globalParameters, + FirstSessionDelayManager firstSessionDelayManager, long createdAt) { this.createdAt = createdAt; this.deviceInfo = deviceInfo; this.adjustConfig = adjustConfig; this.activityStateCopy = new ActivityStateCopy(activityState); - this.sessionParameters = sessionParameters; + this.firstSessionDelayManager = firstSessionDelayManager; + this.globalParameters = globalParameters; } - ActivityPackage buildSessionPackage(boolean isInDelay) { - Map parameters = getSessionParameters(isInDelay); + ActivityPackage buildSessionPackage() { + Map parameters = getSessionParameters(); ActivityPackage sessionPackage = getDefaultActivityPackage(ActivityKind.SESSION); sessionPackage.setPath("/session"); sessionPackage.setSuffix(""); @@ -90,18 +92,16 @@ ActivityPackage buildSessionPackage(boolean isInDelay) { return sessionPackage; } - ActivityPackage buildEventPackage(AdjustEvent event, boolean isInDelay) { - Map parameters = getEventParameters(event, isInDelay); + ActivityPackage buildEventPackage(AdjustEvent event, int sequence) { + Map parameters = getEventParameters(event, sequence); ActivityPackage eventPackage = getDefaultActivityPackage(ActivityKind.EVENT); eventPackage.setPath("/event"); eventPackage.setSuffix(getEventSuffix(event)); eventPackage.setParameters(parameters); - if (isInDelay) { - eventPackage.setCallbackParameters(event.callbackParameters); - eventPackage.setPartnerParameters(event.partnerParameters); - } + eventPackage.setCallbackParameters(event.callbackParameters); + eventPackage.setPartnerParameters(event.partnerParameters); return eventPackage; } @@ -154,16 +154,6 @@ ActivityPackage buildGdprPackage() { return gdprPackage; } - ActivityPackage buildDisableThirdPartySharingPackage() { - Map parameters = getDisableThirdPartySharingParameters(); - ActivityPackage activityPackage = getDefaultActivityPackage(ActivityKind.DISABLE_THIRD_PARTY_SHARING); - activityPackage.setPath("/disable_third_party_sharing"); - activityPackage.setSuffix(""); - - activityPackage.setParameters(parameters); - return activityPackage; - } - ActivityPackage buildThirdPartySharingPackage( final AdjustThirdPartySharing adjustThirdPartySharing) { @@ -187,34 +177,22 @@ ActivityPackage buildMeasurementConsentPackage(final boolean consentMeasurement) return activityPackage; } - ActivityPackage buildAdRevenuePackage(String source, JSONObject adRevenueJson) { - Map parameters = getAdRevenueParameters(source, adRevenueJson); - ActivityPackage adRevenuePackage = getDefaultActivityPackage(ActivityKind.AD_REVENUE); - adRevenuePackage.setPath("/ad_revenue"); - adRevenuePackage.setSuffix(""); - - adRevenuePackage.setParameters(parameters); - return adRevenuePackage; - } - - ActivityPackage buildAdRevenuePackage(AdjustAdRevenue adjustAdRevenue, boolean isInDelay) { - Map parameters = getAdRevenueParameters(adjustAdRevenue, isInDelay); + ActivityPackage buildAdRevenuePackage(AdjustAdRevenue adjustAdRevenue) { + Map parameters = getAdRevenueParameters(adjustAdRevenue); ActivityPackage adRevenuePackage = getDefaultActivityPackage(ActivityKind.AD_REVENUE); adRevenuePackage.setPath("/ad_revenue"); adRevenuePackage.setSuffix(""); adRevenuePackage.setParameters(parameters); - if (isInDelay) { - adRevenuePackage.setCallbackParameters(adjustAdRevenue.callbackParameters); - adRevenuePackage.setPartnerParameters(adjustAdRevenue.partnerParameters); - } + adRevenuePackage.setCallbackParameters(adjustAdRevenue.callbackParameters); + adRevenuePackage.setPartnerParameters(adjustAdRevenue.partnerParameters); return adRevenuePackage; } - ActivityPackage buildSubscriptionPackage(AdjustPlayStoreSubscription subscription, boolean isInDelay) { - Map parameters = getSubscriptionParameters(subscription, isInDelay); + ActivityPackage buildSubscriptionPackage(AdjustPlayStoreSubscription subscription) { + Map parameters = getSubscriptionParameters(subscription); ActivityPackage subscriptionPackage = getDefaultActivityPackage(ActivityKind.SUBSCRIPTION); subscriptionPackage.setPath("/v2/purchase"); subscriptionPackage.setSuffix(""); @@ -223,7 +201,7 @@ ActivityPackage buildSubscriptionPackage(AdjustPlayStoreSubscription subscriptio return subscriptionPackage; } - ActivityPackage buildVerificationPackage(AdjustPurchase purchase, OnPurchaseVerificationFinishedListener callback) { + ActivityPackage buildVerificationPackage(AdjustPlayStorePurchase purchase, OnPurchaseVerificationFinishedListener callback) { Map parameters = getVerificationParameters(purchase); ActivityPackage purchaseVerificationPackage = getDefaultActivityPackage(ActivityKind.PURCHASE_VERIFICATION); purchaseVerificationPackage.setPath("/verify"); @@ -234,7 +212,18 @@ ActivityPackage buildVerificationPackage(AdjustPurchase purchase, OnPurchaseVeri return purchaseVerificationPackage; } - private Map getSessionParameters(boolean isInDelay) { + ActivityPackage buildVerificationPackage(AdjustEvent event, OnPurchaseVerificationFinishedListener callback) { + Map parameters = getVerificationParameters(event); + ActivityPackage purchaseVerificationPackage = getDefaultActivityPackage(ActivityKind.PURCHASE_VERIFICATION); + purchaseVerificationPackage.setPath("/verify"); + purchaseVerificationPackage.setSuffix(""); + purchaseVerificationPackage.setPurchaseVerificationCallback(callback); + + purchaseVerificationPackage.setParameters(parameters); + return purchaseVerificationPackage; + } + + private Map getSessionParameters() { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -250,32 +239,29 @@ private Map getSessionParameters(boolean isInDelay) { } // Callback and partner parameters. - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, "callback_params", this.sessionParameters.callbackParameters); - PackageBuilder.addMapJson(parameters, "partner_params", this.sessionParameters.partnerParameters); - } + PackageBuilder.addMapJson(parameters, "callback_params", this.globalParameters.callbackParameters); + PackageBuilder.addMapJson(parameters, "partner_params", this.globalParameters.partnerParameters); // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -284,8 +270,7 @@ private Map getSessionParameters(boolean isInDelay) { PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -293,13 +278,11 @@ private Map getSessionParameters(boolean isInDelay) { PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -311,7 +294,6 @@ private Map getSessionParameters(boolean isInDelay) { PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); @@ -321,13 +303,20 @@ private Map getSessionParameters(boolean isInDelay) { // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + + // store info + injectStoreInfoToParameters(parameters); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); return parameters; } - public Map getEventParameters(AdjustEvent event, boolean isInDelay) { + public Map getEventParameters(AdjustEvent event, int sequence) { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -343,32 +332,29 @@ public Map getEventParameters(AdjustEvent event, boolean isInDel } // Callback and partner parameters. - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.sessionParameters.callbackParameters, event.callbackParameters, "Callback")); - PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.sessionParameters.partnerParameters, event.partnerParameters, "Partner")); - } + PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.globalParameters.callbackParameters, event.callbackParameters, "Callback")); + PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.globalParameters.partnerParameters, event.partnerParameters, "Partner")); // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -377,8 +363,7 @@ public Map getEventParameters(AdjustEvent event, boolean isInDel PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "currency", event.currency); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -388,7 +373,6 @@ public Map getEventParameters(AdjustEvent event, boolean isInDel PackageBuilder.addString(parameters, "environment", adjustConfig.environment); PackageBuilder.addString(parameters, "event_callback_id", event.callbackId); PackageBuilder.addLong(parameters, "event_count", activityStateCopy.eventCount); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "event_token", event.eventToken); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); @@ -405,19 +389,24 @@ public Map getEventParameters(AdjustEvent event, boolean isInDel PackageBuilder.addString(parameters, "purchase_token", event.purchaseToken); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); PackageBuilder.addDouble(parameters, "revenue", event.revenue); - PackageBuilder.addString(parameters, "deduplication_id", event.orderId); + PackageBuilder.addString(parameters, "order_id", event.orderId); + PackageBuilder.addString(parameters, "deduplication_id", event.deduplicationId); PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); + PackageBuilder.addInteger(parameters, "seq", sequence); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); @@ -440,41 +429,41 @@ private Map getInfoParameters(String source) { } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addBoolean(parameters, "needs_response_details", true); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addString(parameters, "source", source); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); @@ -497,20 +486,20 @@ private Map getClickParameters(String source) { } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } @@ -524,11 +513,10 @@ private Map getClickParameters(String source) { // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); - PackageBuilder.addMapJson(parameters, "callback_params", this.sessionParameters.callbackParameters); + PackageBuilder.addMapJson(parameters, "callback_params", this.globalParameters.callbackParameters); PackageBuilder.addDateInMilliseconds(parameters, "click_time", clickTimeInMilliseconds); PackageBuilder.addDateInSeconds(parameters, "click_time", clickTimeInSeconds); PackageBuilder.addDateInSeconds(parameters, "click_time_server", clickTimeServerInSeconds); @@ -537,8 +525,7 @@ private Map getClickParameters(String source) { PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "deeplink", deeplink); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -546,7 +533,6 @@ private Map getClickParameters(String source) { PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addBoolean(parameters, "google_play_instant", googlePlayInstant); @@ -555,9 +541,8 @@ private Map getClickParameters(String source) { PackageBuilder.addDateInSeconds(parameters, "install_begin_time", installBeginTimeInSeconds); PackageBuilder.addDateInSeconds(parameters, "install_begin_time_server", installBeginTimeServerInSeconds); PackageBuilder.addString(parameters, "install_version", installVersion); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -566,7 +551,7 @@ private Map getClickParameters(String source) { PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); PackageBuilder.addMapJson(parameters, "params", extraParameters); - PackageBuilder.addMapJson(parameters, "partner_params", this.sessionParameters.partnerParameters); + PackageBuilder.addMapJson(parameters, "partner_params", this.globalParameters.partnerParameters); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); PackageBuilder.addString(parameters, "raw_referrer", rawReferrer); PackageBuilder.addString(parameters, "referrer", referrer); @@ -575,7 +560,6 @@ private Map getClickParameters(String source) { PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addString(parameters, "source", source); @@ -584,10 +568,19 @@ private Map getClickParameters(String source) { PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); PackageBuilder.addString(parameters, "payload", preinstallPayload); PackageBuilder.addString(parameters, "found_location", preinstallLocation); + if (licenseData != null) { + PackageBuilder.addInteger(parameters, "lvl_response_code", licenseData.getResponseCode()); + PackageBuilder.addString(parameters, "lvl_signed_data", licenseData.getSignedData()); + PackageBuilder.addString(parameters, "lvl_signature", licenseData.getSignature()); + } // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); @@ -610,37 +603,34 @@ private Map getAttributionParameters(String initiatedBy) { } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); PackageBuilder.addLong(parameters, "ui_mode", deviceInfo.uiMode); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "initiated_by", initiatedBy); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -648,11 +638,14 @@ private Map getAttributionParameters(String initiatedBy) { PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); @@ -675,111 +668,47 @@ private Map getGdprParameters() { } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); PackageBuilder.addLong(parameters, "ui_mode", deviceInfo.uiMode); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addBoolean(parameters, "needs_response_details", true); PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); - injectFeatureFlagsWithParameters(parameters); - - checkDeviceIds(parameters); - return parameters; - } - - private Map getDisableThirdPartySharingParameters() { - Map parameters = new HashMap(); - - deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); - - // Check if plugin is used and if yes, add read parameters. - if (deviceInfo.imeiParameters != null) { - parameters.putAll(deviceInfo.imeiParameters); - } - - // Check if oaid plugin is used and if yes, add the parameter - if (deviceInfo.oaidParameters != null) { - parameters.putAll(deviceInfo.oaidParameters); - } - - // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); - PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); - PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); - PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); - PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); - PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { - logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + - "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); - PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); - } - - // Rest of the parameters. - PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); - PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); - PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); - PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); - PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); - PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); - PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); - PackageBuilder.addLong(parameters, "ui_mode", deviceInfo.uiMode); - PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); - PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); - PackageBuilder.addBoolean(parameters, "needs_response_details", true); - PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); - PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); - PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); - PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); - - // google play games - PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); injectFeatureFlagsWithParameters(parameters); @@ -817,47 +746,47 @@ private Map getDisableThirdPartySharingParameters() { adjustThirdPartySharing.partnerSharingSettings); // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); PackageBuilder.addLong(parameters, "ui_mode", deviceInfo.uiMode); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addBoolean(parameters, "needs_response_details", true); PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); @@ -886,54 +815,54 @@ private Map getMeasurementConsentParameters( consentMeasurement ? "enable" : "disable"); // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); PackageBuilder.addLong(parameters, "ui_mode", deviceInfo.uiMode); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addBoolean(parameters, "needs_response_details", true); PackageBuilder.addString(parameters, "os_name", deviceInfo.osName); PackageBuilder.addString(parameters, "os_version", deviceInfo.osVersion); PackageBuilder.addString(parameters, "package_name", deviceInfo.packageName); PackageBuilder.addString(parameters, "push_token", activityStateCopy.pushToken); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); return parameters; } - private Map getAdRevenueParameters(String source, JSONObject adRevenueJson) { + private Map getAdRevenueParameters(AdjustAdRevenue adjustAdRevenue) { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -948,27 +877,30 @@ private Map getAdRevenueParameters(String source, JSONObject adR parameters.putAll(deviceInfo.oaidParameters); } + // Callback and partner parameters. + PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.globalParameters.callbackParameters, adjustAdRevenue.callbackParameters, "Callback")); + PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.globalParameters.partnerParameters, adjustAdRevenue.partnerParameters, "Partner")); + // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + - "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + "fallback to non Google Play and Fire identifiers will take place"); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -977,8 +909,7 @@ private Map getAdRevenueParameters(String source, JSONObject adR PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -986,13 +917,11 @@ private Map getAdRevenueParameters(String source, JSONObject adR PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -1004,9 +933,13 @@ private Map getAdRevenueParameters(String source, JSONObject adR PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); - PackageBuilder.addString(parameters, "source", source); - PackageBuilder.addJsonObject(parameters, "payload", adRevenueJson); + PackageBuilder.addString(parameters, "source", adjustAdRevenue.source); + PackageBuilder.addDoubleWithoutRounding(parameters, "revenue", adjustAdRevenue.revenue); + PackageBuilder.addString(parameters, "currency", adjustAdRevenue.currency); + PackageBuilder.addInteger(parameters, "ad_impressions_count", adjustAdRevenue.adImpressionsCount); + PackageBuilder.addString(parameters, "ad_revenue_network", adjustAdRevenue.adRevenueNetwork); + PackageBuilder.addString(parameters, "ad_revenue_unit", adjustAdRevenue.adRevenueUnit); + PackageBuilder.addString(parameters, "ad_revenue_placement", adjustAdRevenue.adRevenuePlacement); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); @@ -1016,13 +949,17 @@ private Map getAdRevenueParameters(String source, JSONObject adR // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); return parameters; } - private Map getAdRevenueParameters(AdjustAdRevenue adjustAdRevenue, boolean isInDelay) { + private Map getSubscriptionParameters(AdjustPlayStoreSubscription subscription) { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -1037,33 +974,30 @@ private Map getAdRevenueParameters(AdjustAdRevenue adjustAdReven parameters.putAll(deviceInfo.oaidParameters); } - // Callback and partner parameters. - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.sessionParameters.callbackParameters, adjustAdRevenue.callbackParameters, "Callback")); - PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.sessionParameters.partnerParameters, adjustAdRevenue.partnerParameters, "Partner")); - } - // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + - "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + "fallback to non Google Play and Fire identifiers will take place"); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } + // Callback and partner parameters. + PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.globalParameters.callbackParameters, subscription.getCallbackParameters(), "Callback")); + PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.globalParameters.partnerParameters, subscription.getPartnerParameters(), "Partner")); + // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -1072,8 +1006,7 @@ private Map getAdRevenueParameters(AdjustAdRevenue adjustAdReven PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -1081,13 +1014,11 @@ private Map getAdRevenueParameters(AdjustAdRevenue adjustAdReven PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -1099,30 +1030,35 @@ private Map getAdRevenueParameters(AdjustAdRevenue adjustAdReven PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); - PackageBuilder.addString(parameters, "source", adjustAdRevenue.source); - PackageBuilder.addDoubleWithoutRounding(parameters, "revenue", adjustAdRevenue.revenue); - PackageBuilder.addString(parameters, "currency", adjustAdRevenue.currency); - PackageBuilder.addInteger(parameters, "ad_impressions_count", adjustAdRevenue.adImpressionsCount); - PackageBuilder.addString(parameters, "ad_revenue_network", adjustAdRevenue.adRevenueNetwork); - PackageBuilder.addString(parameters, "ad_revenue_unit", adjustAdRevenue.adRevenueUnit); - PackageBuilder.addString(parameters, "ad_revenue_placement", adjustAdRevenue.adRevenuePlacement); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); + // subscription specific parameters + PackageBuilder.addString(parameters, "currency", subscription.getCurrency()); + PackageBuilder.addString(parameters, "product_id", subscription.getSku()); + PackageBuilder.addString(parameters, "purchase_token", subscription.getPurchaseToken()); + PackageBuilder.addString(parameters, "receipt", subscription.getSignature()); + PackageBuilder.addLong(parameters, "revenue", subscription.getPrice()); + PackageBuilder.addDateInMilliseconds(parameters, "transaction_date", subscription.getPurchaseTime()); + PackageBuilder.addString(parameters, "transaction_id", subscription.getOrderId()); + // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); return parameters; } - private Map getSubscriptionParameters(AdjustPlayStoreSubscription subscription, boolean isInDelay) { + private Map getVerificationParameters(AdjustPlayStorePurchase purchase) { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -1138,32 +1074,24 @@ private Map getSubscriptionParameters(AdjustPlayStoreSubscriptio } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); - PackageBuilder.addString(parameters, "google_app_set_id", deviceInfo.appSetId); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } - // Callback and partner parameters. - if (!isInDelay) { - PackageBuilder.addMapJson(parameters, "callback_params", Util.mergeParameters(this.sessionParameters.callbackParameters, subscription.getCallbackParameters(), "Callback")); - PackageBuilder.addMapJson(parameters, "partner_params", Util.mergeParameters(this.sessionParameters.partnerParameters, subscription.getPartnerParameters(), "Partner")); - } - // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -1172,8 +1100,7 @@ private Map getSubscriptionParameters(AdjustPlayStoreSubscriptio PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -1181,13 +1108,11 @@ private Map getSubscriptionParameters(AdjustPlayStoreSubscriptio PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -1199,33 +1124,30 @@ private Map getSubscriptionParameters(AdjustPlayStoreSubscriptio PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); PackageBuilder.addDuration(parameters, "time_spent", activityStateCopy.timeSpent); PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); - // subscription specific parameters - PackageBuilder.addString(parameters, "billing_store", subscription.getBillingStore()); - PackageBuilder.addString(parameters, "currency", subscription.getCurrency()); - PackageBuilder.addString(parameters, "product_id", subscription.getSku()); - PackageBuilder.addString(parameters, "purchase_token", subscription.getPurchaseToken()); - PackageBuilder.addString(parameters, "receipt", subscription.getSignature()); - PackageBuilder.addLong(parameters, "revenue", subscription.getPrice()); - PackageBuilder.addDateInMilliseconds(parameters, "transaction_date", subscription.getPurchaseTime()); - PackageBuilder.addString(parameters, "transaction_id", subscription.getOrderId()); + // purchase verification specific parameters + PackageBuilder.addString(parameters, "product_id", purchase.getProductId()); + PackageBuilder.addString(parameters, "purchase_token", purchase.getPurchaseToken()); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); + // control params json + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(adjustConfig.context).getControlParamsJson(); + PackageBuilder.addJsonObject(parameters, "control_params", controlParams); + injectFeatureFlagsWithParameters(parameters); checkDeviceIds(parameters); return parameters; } - private Map getVerificationParameters(AdjustPurchase purchase) { + private Map getVerificationParameters(AdjustEvent event) { Map parameters = new HashMap(); deviceInfo.reloadOtherDeviceInfoParams(adjustConfig, logger); @@ -1241,25 +1163,24 @@ private Map getVerificationParameters(AdjustPurchase purchase) { } // Device identifiers. - deviceInfo.reloadPlayIds(adjustConfig); + deviceInfo.reloadGoogleAdId(adjustConfig); PackageBuilder.addString(parameters, "android_uuid", activityStateCopy.uuid); - PackageBuilder.addString(parameters, "gps_adid", deviceInfo.playAdId); - PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.playAdIdAttempt); - PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.playAdIdSource); + PackageBuilder.addString(parameters, "gps_adid", deviceInfo.googleAdId); + PackageBuilder.addLong(parameters, "gps_adid_attempt", deviceInfo.googleAdIdReadAttempt); + PackageBuilder.addString(parameters, "gps_adid_src", deviceInfo.googleAdIdSource); PackageBuilder.addBoolean(parameters, "tracking_enabled", deviceInfo.isTrackingEnabled); PackageBuilder.addString(parameters, "fire_adid", deviceInfo.fireAdId); PackageBuilder.addBoolean(parameters, "fire_tracking_enabled", deviceInfo.fireTrackingEnabled); - if (!containsPlayIds(parameters) && !containsFireIds(parameters)) { + if (!containsGoogleAdId(parameters) && !containsFireAdId(parameters)) { logger.warn("Google Advertising ID or Fire Advertising ID not detected, " + "fallback to non Google Play and Fire identifiers will take place"); - deviceInfo.reloadNonPlayIds(adjustConfig); + deviceInfo.readAndroidId(adjustConfig); PackageBuilder.addString(parameters, "android_id", deviceInfo.androidId); } // Rest of the parameters. PackageBuilder.addString(parameters, "api_level", deviceInfo.apiLevel); - PackageBuilder.addString(parameters, "app_secret", adjustConfig.appSecret); PackageBuilder.addString(parameters, "app_token", adjustConfig.appToken); PackageBuilder.addString(parameters, "app_version", deviceInfo.appVersion); PackageBuilder.addBoolean(parameters, "attribution_deeplink", true); @@ -1268,8 +1189,7 @@ private Map getVerificationParameters(AdjustPurchase purchase) { PackageBuilder.addString(parameters, "cpu_type", deviceInfo.abi); PackageBuilder.addDateInMilliseconds(parameters, "created_at", createdAt); PackageBuilder.addString(parameters, "default_tracker", adjustConfig.defaultTracker); - PackageBuilder.addBoolean(parameters, "device_known", adjustConfig.deviceKnown); - PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.needsCost); + PackageBuilder.addBoolean(parameters, "needs_cost", adjustConfig.isCostDataInAttributionEnabled); PackageBuilder.addString(parameters, "device_manufacturer", deviceInfo.deviceManufacturer); PackageBuilder.addString(parameters, "device_name", deviceInfo.deviceName); PackageBuilder.addString(parameters, "device_type", deviceInfo.deviceType); @@ -1277,13 +1197,11 @@ private Map getVerificationParameters(AdjustPurchase purchase) { PackageBuilder.addString(parameters, "display_height", deviceInfo.displayHeight); PackageBuilder.addString(parameters, "display_width", deviceInfo.displayWidth); PackageBuilder.addString(parameters, "environment", adjustConfig.environment); - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); PackageBuilder.addString(parameters, "external_device_id", adjustConfig.externalDeviceId); PackageBuilder.addString(parameters, "fb_id", deviceInfo.fbAttributionId); PackageBuilder.addString(parameters, "hardware_name", deviceInfo.hardwareName); - PackageBuilder.addString(parameters, "installed_at", deviceInfo.appInstallTime); + PackageBuilder.addDateInMilliseconds(parameters, "installed_at", deviceInfo.appInstallTime); PackageBuilder.addString(parameters, "language", deviceInfo.language); - PackageBuilder.addDuration(parameters, "last_interval", activityStateCopy.lastInterval); PackageBuilder.addString(parameters, "mcc", deviceInfo.mcc); PackageBuilder.addString(parameters, "mnc", deviceInfo.mnc); PackageBuilder.addBoolean(parameters, "needs_response_details", true); @@ -1295,7 +1213,6 @@ private Map getVerificationParameters(AdjustPurchase purchase) { PackageBuilder.addString(parameters, "screen_density", deviceInfo.screenDensity); PackageBuilder.addString(parameters, "screen_format", deviceInfo.screenFormat); PackageBuilder.addString(parameters, "screen_size", deviceInfo.screenSize); - PackageBuilder.addString(parameters, "secret_id", adjustConfig.secretId); PackageBuilder.addLong(parameters, "session_count", activityStateCopy.sessionCount); PackageBuilder.addDuration(parameters, "session_length", activityStateCopy.sessionLength); PackageBuilder.addLong(parameters, "subsession_count", activityStateCopy.subsessionCount); @@ -1303,8 +1220,11 @@ private Map getVerificationParameters(AdjustPurchase purchase) { PackageBuilder.addString(parameters, "updated_at", deviceInfo.appUpdateTime); // purchase verification specific parameters - PackageBuilder.addString(parameters, "product_id", purchase.getProductId()); - PackageBuilder.addString(parameters, "purchase_token", purchase.getPurchaseToken()); + PackageBuilder.addString(parameters, "product_id", event.getProductId()); + PackageBuilder.addString(parameters, "purchase_token", event.getPurchaseToken()); + PackageBuilder.addString(parameters, "event_token", event.getEventToken()); + PackageBuilder.addString(parameters, "currency", event.getCurrency()); + PackageBuilder.addDouble(parameters, "revenue", event.getRevenue()); // google play games PackageBuilder.addBoolean(parameters, "gpg_pc_enabled", deviceInfo.isGooglePlayGamesForPC ? true : null); @@ -1322,9 +1242,9 @@ private ActivityPackage getDefaultActivityPackage(ActivityKind activityKind) { } private void injectFeatureFlagsWithParameters(Map parameters) { - - PackageBuilder.addBoolean(parameters, "event_buffering_enabled", adjustConfig.eventBufferingEnabled); - PackageBuilder.addBoolean(parameters, "send_in_background_enabled", adjustConfig.sendInBackground); + if (adjustConfig.coppaComplianceEnabled) { + PackageBuilder.addLong(parameters, "ff_coppa", 1); + } if (internalState != null) { PackageBuilder.addBoolean(parameters, "offline_mode_enabled", internalState.offline); @@ -1334,17 +1254,59 @@ private void injectFeatureFlagsWithParameters(Map parameters) { PackageBuilder.addBoolean(parameters, "background", true); } } + if (adjustConfig.playStoreKidsComplianceEnabled) { + PackageBuilder.addLong(parameters, "ff_play_store_kids_app", 1); + } - if (adjustConfig.coppaCompliantEnabled) { - PackageBuilder.addLong(parameters, "ff_coppa", 1); + if (firstSessionDelayManager.wasSet()) { + PackageBuilder.addBoolean(parameters, "ff_first_session_delay", true); } - if (adjustConfig.playStoreKidsAppEnabled) { - PackageBuilder.addLong(parameters, "ff_play_store_kids_app", 1); + if (!adjustConfig.isGoogleAdIdReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_gps_adid_disabled", true); + } + + if (!adjustConfig.isAndroidIdReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_android_id_disabled", true); + } + + if (!adjustConfig.isAppSetIdReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_app_set_id_disabled", true); } + + if (!adjustConfig.isFbIdReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_fb_id_disabled", true); + } + + if (!adjustConfig.isFireAdIdReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_fire_adid_disabled", true); + } + + if (!adjustConfig.isDeviceIdsFromPluginsReadingEnabled) { + PackageBuilder.addBoolean(parameters, "ff_plugins_device_ids_disabled", true); + } + + if (adjustConfig.onRemoteTriggerListener != null) { + PackageBuilder.addBoolean(parameters, "ff_remote_triggers_callback", true); + } + } + + private void injectStoreInfoToParameters(Map parameters) { + if (deviceInfo.storeInfoFromClient != null) { + PackageBuilder.addString(parameters, "store_name_from_client", deviceInfo.storeInfoFromClient.storeName); + PackageBuilder.addString(parameters, "store_app_id_from_client", deviceInfo.storeInfoFromClient.storeAppId); + } + PackageBuilder.addString(parameters, "store_name_from_system", deviceInfo.storeIdFromSystem); + PackageBuilder.addString(parameters, "initiating_package_name", deviceInfo.initiatingPackageName); + PackageBuilder.addString(parameters, "originating_package_name", deviceInfo.originatingPackageName); + PackageBuilder.addBoolean(parameters, "is_system_app", deviceInfo.isSystemApp); + PackageBuilder.addBoolean(parameters, "is_updated_system_app", deviceInfo.isUpdatedSystemApp); } public static void addString(Map parameters, String key, String value) { + if (parameters == null) { + return; + } if (TextUtils.isEmpty(value)) { return; } @@ -1352,6 +1314,9 @@ public static void addString(Map parameters, String key, String } public static void addBoolean(Map parameters, String key, Boolean value) { + if (parameters == null) { + return; + } if (value == null) { return; } @@ -1360,6 +1325,9 @@ public static void addBoolean(Map parameters, String key, Boolea } static void addJsonObject(Map parameters, String key, JSONObject jsonObject) { + if (parameters == null) { + return; + } if (jsonObject == null) { return; } @@ -1368,6 +1336,9 @@ static void addJsonObject(Map parameters, String key, JSONObject } static void addMapJson(Map parameters, String key, Map map) { + if (parameters == null) { + return; + } if (map == null) { return; } @@ -1381,6 +1352,9 @@ static void addMapJson(Map parameters, String key, Map map) { } public static void addLong(Map parameters, String key, long value) { + if (parameters == null) { + return; + } if (value < 0) { return; } @@ -1389,6 +1363,9 @@ public static void addLong(Map parameters, String key, long valu } public static void addDouble(Map parameters, String key, double value) { + if (parameters == null) { + return; + } if (value < 0.0) { return; } @@ -1397,6 +1374,9 @@ public static void addDouble(Map parameters, String key, double } private static void addDateInMilliseconds(Map parameters, String key, long value) { + if (parameters == null) { + return; + } if (value <= 0) { return; } @@ -1405,6 +1385,9 @@ private static void addDateInMilliseconds(Map parameters, String } private static void addDateInSeconds(Map parameters, String key, long value) { + if (parameters == null) { + return; + } if (value <= 0) { return; } @@ -1413,6 +1396,9 @@ private static void addDateInSeconds(Map parameters, String key, } private static void addDate(Map parameters, String key, Date value) { + if (parameters == null) { + return; + } if (value == null) { return; } @@ -1421,6 +1407,9 @@ private static void addDate(Map parameters, String key, Date val } private static void addDuration(Map parameters, String key, long durationInMilliSeconds) { + if (parameters == null) { + return; + } if (durationInMilliSeconds < 0) { return; } @@ -1429,6 +1418,9 @@ private static void addDuration(Map parameters, String key, long } private static void addDouble(Map parameters, String key, Double value) { + if (parameters == null) { + return; + } if (value == null) { return; } @@ -1437,6 +1429,9 @@ private static void addDouble(Map parameters, String key, Double } private static void addDoubleWithoutRounding(Map parameters, String key, Double value) { + if (parameters == null) { + return; + } if (value == null) { return; } @@ -1445,6 +1440,9 @@ private static void addDoubleWithoutRounding(Map parameters, Str } private static void addInteger(Map parameters, String key, Integer value) { + if (parameters == null) { + return; + } if (value == null) { return; } @@ -1452,14 +1450,14 @@ private static void addInteger(Map parameters, String key, Integ PackageBuilder.addString(parameters, key, intString); } - private boolean containsPlayIds(Map parameters) { + private boolean containsGoogleAdId(Map parameters) { if (parameters == null) { return false; } return parameters.containsKey("gps_adid"); } - private boolean containsFireIds(Map parameters) { + private boolean containsFireAdId(Map parameters) { if (parameters == null) { return false; } @@ -1477,8 +1475,16 @@ private void checkDeviceIds(Map parameters) { && !parameters.containsKey("imeis") && !parameters.containsKey("meids") && !parameters.containsKey("device_ids")) { - if (adjustConfig.coppaCompliantEnabled) { + if (adjustConfig.coppaComplianceEnabled) { logger.info("Missing Device IDs. COPPA enabled."); + } else if (adjustConfig.playStoreKidsComplianceEnabled) { + logger.info("Missing Device IDs. Play store kids compliance enabled."); + } else if (!adjustConfig.isGoogleAdIdReadingEnabled) { + logger.info("Missing Google Advertising ID, reading disabled."); + } else if (!adjustConfig.isAndroidIdReadingEnabled) { + logger.info("Missing Android ID, reading disabled."); + } else if (!adjustConfig.isFireAdIdReadingEnabled) { + logger.info("Missing Fire Advertising ID, reading disabled."); } else { logger.error("Missing Device IDs. Please check if Proguard is correctly set with Adjust SDK"); } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java index 568529575..e4b17fde3 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageFactory.java @@ -20,12 +20,13 @@ public class PackageFactory { private static final String ADJUST_PREFIX = "adjust_"; public static ActivityPackage buildReftagSdkClickPackage(final String rawReferrer, - final long clickTime, - final ActivityState activityState, - final AdjustConfig adjustConfig, - final DeviceInfo deviceInfo, - final SessionParameters sessionParameters, - final ActivityHandler.InternalState internalState) { + final long clickTime, + final ActivityState activityState, + final AdjustConfig adjustConfig, + final DeviceInfo deviceInfo, + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager, + final ActivityHandler.InternalState internalState) { if (rawReferrer == null || rawReferrer.length() == 0) { return null; } @@ -57,7 +58,8 @@ public static ActivityPackage buildReftagSdkClickPackage(final String rawReferre activityState, adjustConfig, deviceInfo, - sessionParameters, + globalParameters, + firstSessionDelayManager, internalState); if (clickPackageBuilder == null) { @@ -74,11 +76,13 @@ public static ActivityPackage buildReftagSdkClickPackage(final String rawReferre } public static ActivityPackage buildDeeplinkSdkClickPackage(final Uri url, + final Uri referrer, final long clickTime, final ActivityState activityState, final AdjustConfig adjustConfig, final DeviceInfo deviceInfo, - final SessionParameters sessionParameters, + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager, final ActivityHandler.InternalState internalState) { if (url == null) { return null; @@ -117,7 +121,8 @@ public static ActivityPackage buildDeeplinkSdkClickPackage(final Uri url, activityState, adjustConfig, deviceInfo, - sessionParameters, + globalParameters, + firstSessionDelayManager, internalState); if (clickPackageBuilder == null) { @@ -127,6 +132,10 @@ public static ActivityPackage buildDeeplinkSdkClickPackage(final Uri url, clickPackageBuilder.deeplink = url.toString(); clickPackageBuilder.clickTimeInMilliseconds = clickTime; + if (referrer != null) { + clickPackageBuilder.referrer = referrer.toString(); + } + ActivityPackage clickPackage = clickPackageBuilder.buildClickPackage(Constants.DEEPLINK); return clickPackage; @@ -137,7 +146,8 @@ public static ActivityPackage buildInstallReferrerSdkClickPackage(final Referrer final ActivityState activityState, final AdjustConfig adjustConfig, final DeviceInfo deviceInfo, - final SessionParameters sessionParameters, + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager, final ActivityHandler.InternalState internalState) { long now = System.currentTimeMillis(); @@ -145,7 +155,8 @@ public static ActivityPackage buildInstallReferrerSdkClickPackage(final Referrer adjustConfig, deviceInfo, activityState, - sessionParameters, + globalParameters, + firstSessionDelayManager, now); clickPackageBuilder.internalState = internalState; @@ -164,12 +175,38 @@ public static ActivityPackage buildInstallReferrerSdkClickPackage(final Referrer return clickPackage; } + public static ActivityPackage buildLicenseVerificationSdkClickPackage(final LicenseData licenseData, + final ActivityState activityState, + final AdjustConfig adjustConfig, + final DeviceInfo deviceInfo, + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager, + final ActivityHandler.InternalState internalState) { + long now = System.currentTimeMillis(); + + PackageBuilder clickPackageBuilder = new PackageBuilder( + adjustConfig, + deviceInfo, + activityState, + globalParameters, + firstSessionDelayManager, + now); + clickPackageBuilder.internalState = internalState; + + clickPackageBuilder.licenseData = licenseData; + + ActivityPackage clickPackage = clickPackageBuilder.buildClickPackage(Constants.LICENSE_VERIFICATION); + + return clickPackage; + } + public static ActivityPackage buildPreinstallSdkClickPackage(final String preinstallPayload, final String preinstallLocation, final ActivityState activityState, final AdjustConfig adjustConfig, final DeviceInfo deviceInfo, - final SessionParameters sessionParameters) { + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager) { if (preinstallPayload == null || preinstallPayload.length() == 0) { return null; } @@ -180,7 +217,8 @@ public static ActivityPackage buildPreinstallSdkClickPackage(final String preins adjustConfig, deviceInfo, activityState, - sessionParameters, + globalParameters, + firstSessionDelayManager, now); clickPackageBuilder.preinstallPayload = preinstallPayload; @@ -196,7 +234,8 @@ private static PackageBuilder queryStringClickPackageBuilder( final ActivityState activityState, final AdjustConfig adjustConfig, final DeviceInfo deviceInfo, - final SessionParameters sessionParameters, + final GlobalParameters globalParameters, + final FirstSessionDelayManager firstSessionDelayManager, final ActivityHandler.InternalState internalState) { if (queryList == null) { return null; @@ -227,7 +266,8 @@ private static PackageBuilder queryStringClickPackageBuilder( adjustConfig, deviceInfo, activityState, - sessionParameters, + globalParameters, + firstSessionDelayManager, now); builder.internalState = internalState; diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java index cda86689d..6bec143c0 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PackageHandler.java @@ -22,8 +22,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import static com.adjust.sdk.Constants.CALLBACK_PARAMETERS; -import static com.adjust.sdk.Constants.PARTNER_PARAMETERS; // persistent public class PackageHandler implements IPackageHandler, @@ -140,7 +138,7 @@ public void onResponseDataCallback(final ResponseData responseData) { scheduler.submit(new Runnable() { @Override public void run() { - sendNextI(); + sendNextI(responseData.continueIn); } }); @@ -172,8 +170,9 @@ public void run() { } }; - if (responseData.activityPackage == null) { - runnable.run(); + if (responseData.retryIn != null && responseData.retryIn > 0) { + long retryIn = responseData.retryIn; + scheduler.schedule(runnable, retryIn); return; } @@ -183,8 +182,7 @@ public void run() { SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(context); if (responseData.activityPackage.getActivityKind() == - ActivityKind.SESSION && !sharedPreferencesManager.getInstallTracked()) - { + ActivityKind.SESSION && !sharedPreferencesManager.getInstallTracked()) { waitTimeMilliSeconds = Util.getWaitingTime(retries, backoffStrategyForInstallSession); } else { waitTimeMilliSeconds = Util.getWaitingTime(retries, backoffStrategy); @@ -195,7 +193,10 @@ public void run() { totalWaitTimeSeconds += waitTimeSeconds; - logger.verbose("Waiting for %s seconds before retrying the %d time", secondsString, retries); + logger.verbose("Waiting for %s seconds before retrying %s for the %d time", + secondsString, + responseData.activityPackage.getActivityKind().toString(), + retries); scheduler.schedule(runnable, waitTimeMilliSeconds); responseData.activityPackage.setWaitBeforeSendTimeSeconds(responseData.activityPackage.getWaitBeforeSendTimeSeconds() + waitTimeSeconds); } @@ -212,22 +213,6 @@ public void resumeSending() { paused = false; } - @Override - public void updatePackages(SessionParameters sessionParameters) { - final SessionParameters sessionParametersCopy; - if (sessionParameters != null) { - sessionParametersCopy = sessionParameters.deepCopy(); - } else { - sessionParametersCopy = null; - } - scheduler.submit(new Runnable() { - @Override - public void run() { - updatePackagesI(sessionParametersCopy); - } - }); - } - @Override public void flush() { scheduler.submit(new Runnable() { @@ -292,11 +277,6 @@ private void sendFirstI() { private Map generateSendingParametersI() { HashMap sendingParameters = new HashMap<>(); - long now = System.currentTimeMillis(); - String dateString = Util.dateFormatter.format(now); - - PackageBuilder.addString(sendingParameters, "sent_at", dateString); - int queueSize = packageQueue.size() - 1; if (queueSize > 0) { PackageBuilder.addLong(sendingParameters, "queue_size", queueSize); @@ -304,7 +284,7 @@ private Map generateSendingParametersI() { return sendingParameters; } - private void sendNextI() { + private void sendNextI(Long previousResponseContinueIn) { isRetrying = false; retryStartedAtTimeMilliSeconds = 0; @@ -317,37 +297,25 @@ private void sendNextI() { packageQueue.remove(0); writePackageQueueI(); - isSending.set(false); - logger.verbose("Package handler can send"); - sendFirstI(); - } - - public void updatePackagesI(SessionParameters sessionParameters) { - if (sessionParameters == null) { - return; - } - - logger.debug("Updating package handler queue"); - logger.verbose("Session callback parameters: %s", sessionParameters.callbackParameters); - logger.verbose("Session partner parameters: %s", sessionParameters.partnerParameters); - for (ActivityPackage activityPackage : packageQueue) { - Map parameters = activityPackage.getParameters(); - // callback parameters - Map mergedCallbackParameters = Util.mergeParameters(sessionParameters.callbackParameters, - activityPackage.getCallbackParameters(), - "Callback"); + if (previousResponseContinueIn != null && previousResponseContinueIn > 0) { + Runnable runnable = new Runnable() { + @Override + public void run() { + logger.verbose("Package handler finished waiting to continue"); + isSending.set(false); + sendFirstPackage(); + } + }; - PackageBuilder.addMapJson(parameters, CALLBACK_PARAMETERS, mergedCallbackParameters); - // partner parameters - Map mergedPartnerParameters = Util.mergeParameters(sessionParameters.partnerParameters, - activityPackage.getPartnerParameters(), - "Partner"); + logger.verbose("Waiting for %d seconds before continuing for next package in continue_in", previousResponseContinueIn / 1000.0); + scheduler.schedule(runnable, previousResponseContinueIn); - PackageBuilder.addMapJson(parameters, PARTNER_PARAMETERS, mergedPartnerParameters); + } else { + logger.verbose("Package handler can send"); + isSending.set(false); + sendFirstI(); } - - writePackageQueueI(); } private void flushI() { diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PreinstallUtil.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PreinstallUtil.java index 78c350a6e..4c7db8cca 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PreinstallUtil.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PreinstallUtil.java @@ -10,12 +10,14 @@ import android.database.Cursor; import android.net.Uri; import android.os.Build; +import android.util.Base64; import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -25,17 +27,22 @@ import static com.adjust.sdk.Constants.ADJUST_PREINSTALL_FILE_SYSTEM_PATH; import static com.adjust.sdk.Constants.ADJUST_PREINSTALL_CONTENT_URI_AUTHORITY; import static com.adjust.sdk.Constants.ADJUST_PREINSTALL_CONTENT_URI_PATH; +import static com.adjust.sdk.Constants.SAMSUNG_PREINSTALL_APP_TRACKING_ID; +import static com.adjust.sdk.Constants.SAMSUNG_PREINSTALL_CONTENT_URI_AUTHORITY; +import static com.adjust.sdk.Constants.SAMSUNG_PREINSTALL_CONTENT_URI_PATH; +import static com.adjust.sdk.Constants.SAMSUNG_PREINSTALL_PAYLOAD_PROVIDER; public class PreinstallUtil { - private static final long SYSTEM_PROPERTY_BITMASK = 1; //00...000000001 - private static final long SYSTEM_PROPERTY_REFLECTION_BITMASK = 2; //00...000000010 - private static final long SYSTEM_PROPERTY_PATH_BITMASK = 4; //00...000000100 - private static final long SYSTEM_PROPERTY_PATH_REFLECTION_BITMASK = 8; //00...000001000 - private static final long CONTENT_PROVIDER_BITMASK = 16; //00...000010000 - private static final long CONTENT_PROVIDER_INTENT_ACTION_BITMASK = 32; //00...000100000 - private static final long FILE_SYSTEM_BITMASK = 64; //00...001000000 - private static final long CONTENT_PROVIDER_NO_PERMISSION_BITMASK = 128; //00...010000000 + private static final long SYSTEM_PROPERTY_BITMASK = 1; //00...0000000001 + private static final long SYSTEM_PROPERTY_REFLECTION_BITMASK = 2; //00...0000000010 + private static final long SYSTEM_PROPERTY_PATH_BITMASK = 4; //00...0000000100 + private static final long SYSTEM_PROPERTY_PATH_REFLECTION_BITMASK = 8; //00...0000001000 + private static final long CONTENT_PROVIDER_BITMASK = 16; //00...0000010000 + private static final long CONTENT_PROVIDER_INTENT_ACTION_BITMASK = 32; //00...0000100000 + private static final long FILE_SYSTEM_BITMASK = 64; //00...0001000000 + private static final long CONTENT_PROVIDER_NO_PERMISSION_BITMASK = 128; //00...0010000000 + private static final long CONTENT_PROVIDER_MAPS_BITMASK = 256; //00...0100000000 // bitwise OR (|) of all above locations private static final long ALL_LOCATION_BITMASK = (SYSTEM_PROPERTY_BITMASK | @@ -45,7 +52,8 @@ public class PreinstallUtil { CONTENT_PROVIDER_BITMASK | CONTENT_PROVIDER_INTENT_ACTION_BITMASK | FILE_SYSTEM_BITMASK | - CONTENT_PROVIDER_NO_PERMISSION_BITMASK); //00...011111111 + CONTENT_PROVIDER_NO_PERMISSION_BITMASK | + CONTENT_PROVIDER_MAPS_BITMASK); //00...0111111111 public static boolean hasAllLocationsBeenRead(long status) { // Check if the given status has none of the valid location with bit `0`, indicating it has @@ -72,6 +80,8 @@ public static boolean hasNotBeenRead(String location, long status) { return (status & FILE_SYSTEM_BITMASK) != FILE_SYSTEM_BITMASK; case Constants.CONTENT_PROVIDER_NO_PERMISSION: return (status & CONTENT_PROVIDER_NO_PERMISSION_BITMASK) != CONTENT_PROVIDER_NO_PERMISSION_BITMASK; + case Constants.CONTENT_PROVIDER_SAMSUNG_MAPS: + return (status & CONTENT_PROVIDER_MAPS_BITMASK) != CONTENT_PROVIDER_MAPS_BITMASK; } return false; } @@ -95,6 +105,8 @@ public static long markAsRead(String location, long status) { return (status | FILE_SYSTEM_BITMASK); case Constants.CONTENT_PROVIDER_NO_PERMISSION: return (status | CONTENT_PROVIDER_NO_PERMISSION_BITMASK); + case Constants.CONTENT_PROVIDER_SAMSUNG_MAPS: + return (status | CONTENT_PROVIDER_MAPS_BITMASK); } return status; } @@ -183,6 +195,82 @@ public static List getPayloadsFromContentProviderNoPermission( logger); } + public static String getPayloadFromContentProviderSamsungMaps(final Context context, + final String packageName, + final ILogger logger) + { + if (!Util.resolveContentProvider(context, SAMSUNG_PREINSTALL_CONTENT_URI_AUTHORITY)) { + return null; + } + + JSONObject appTrackingInfoJsonObject = getSamsungMapsAppTrackingInfo(context, packageName, logger); + if (appTrackingInfoJsonObject == null || appTrackingInfoJsonObject.length() <= 0) { + return null; + } + + boolean result = Boolean.parseBoolean(appTrackingInfoJsonObject.optString("RESULT", "false")); + if (!result) { + return null; + } + + try { + String appTrackingInfoJsonString = appTrackingInfoJsonObject.toString(); + String base64EncodedAppTrackingInfo = Base64.encodeToString(appTrackingInfoJsonString.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP); + if (base64EncodedAppTrackingInfo == null || base64EncodedAppTrackingInfo.isEmpty()) { + return null; + } + + JSONObject payloadJsonObject = new JSONObject(); + payloadJsonObject.put("provider", SAMSUNG_PREINSTALL_PAYLOAD_PROVIDER); + payloadJsonObject.put("details", base64EncodedAppTrackingInfo); + + return payloadJsonObject.toString(); + } catch (Exception e) { + logger.error("Samsung MAPS Exception during payload json object creation from content provider Samsung maps [%s]", e.getMessage()); + } + + return null; + } + + private static JSONObject getSamsungMapsAppTrackingInfo(Context context, String packageName, ILogger logger) { + Cursor cursor = null; + try { + String contentUriString = Util.formatString("content://%s/%s", SAMSUNG_PREINSTALL_CONTENT_URI_AUTHORITY, SAMSUNG_PREINSTALL_CONTENT_URI_PATH); + Uri contentUri = Uri.parse(contentUriString); + cursor = context.getContentResolver().query(contentUri, null, packageName, new String[]{SAMSUNG_PREINSTALL_APP_TRACKING_ID}, null); + + if (cursor == null) { + return null; + } + + if (!cursor.moveToFirst()) { + cursor.close(); + return null; + } + + JSONObject jsonObject = new JSONObject(); + + for (int col = 0; col < cursor.getColumnCount(); col++) { + jsonObject.put(cursor.getColumnName(col), cursor.getString(col)); + } + cursor.close(); + if (jsonObject.length() <= 0) { + return null; + } + + return jsonObject; + + } catch (Exception e) { + logger.error("Samsung MAPS Exception read content provider error [%s]", e.getMessage()); + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return null; + } + public static String getPayloadFromFileSystem(final String packageName, final String filePath, final ILogger logger) diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PurchaseVerificationHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PurchaseVerificationHandler.java index 2f4ea0737..2e2a01879 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/PurchaseVerificationHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/PurchaseVerificationHandler.java @@ -6,9 +6,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * PurchaseVerificationHandler class. @@ -39,9 +37,9 @@ public class PurchaseVerificationHandler implements IPurchaseVerificationHandler private ILogger logger; /** - * Backoff strategy. + * Flag to indicate if Purchase Verification package is being sent. */ - private BackoffStrategy backoffStrategy; + private boolean isSendingPurchaseVerificationPackage; /** * Sending queue. @@ -60,6 +58,8 @@ public class PurchaseVerificationHandler implements IPurchaseVerificationHandler private IActivityPackageSender activityPackageSender; + private long lastPackageRetryInMilli= 0L; + /** * PurchaseVerificationHandler constructor. * @@ -72,7 +72,6 @@ public PurchaseVerificationHandler(final IActivityHandler activityHandler, { init(activityHandler, startsSending, purchaseVerificationHandlerActivityPackageSender); this.logger = AdjustFactory.getLogger(); - backoffStrategy = AdjustFactory.getSdkClickBackoffStrategy(); scheduler = new SingleThreadCachedScheduler(SCHEDULED_EXECUTOR_SOURCE); } @@ -87,6 +86,8 @@ public void init(final IActivityHandler activityHandler, packageQueue = new ArrayList(); activityHandlerWeakRef = new WeakReference(activityHandler); activityPackageSender = purchaseVerificationHandlerActivityPackageSender; + isSendingPurchaseVerificationPackage = false; + lastPackageRetryInMilli = 0L; } /** @@ -95,6 +96,8 @@ public void init(final IActivityHandler activityHandler, @Override public void pauseSending() { paused = true; + isSendingPurchaseVerificationPackage = false; + lastPackageRetryInMilli = 0L; } /** @@ -115,10 +118,7 @@ public void sendPurchaseVerificationPackage(final ActivityPackage purchaseVerifi scheduler.submit(new Runnable() { @Override public void run() { - packageQueue.add(purchaseVerification); - logger.debug("Added purchase_verification %d", packageQueue.size()); - logger.verbose("%s", purchaseVerification.getExtendedString()); - sendNextPurchaseVerificationPackage(); + sendPurchaseVerificationPackageI(purchaseVerification); } }); } @@ -144,8 +144,19 @@ public void teardown() { logger = null; packageQueue = null; - backoffStrategy = null; scheduler = null; + isSendingPurchaseVerificationPackage = false; + lastPackageRetryInMilli = 0L; + } + + /** + * Add purchase_verification package to the queue and send. + */ + private void sendPurchaseVerificationPackageI(final ActivityPackage purchaseVerification) { + packageQueue.add(purchaseVerification); + logger.debug("Added purchase_verification %d", packageQueue.size()); + logger.verbose("%s", purchaseVerification.getExtendedString()); + sendNextPurchaseVerificationPackage(); } /** @@ -168,38 +179,40 @@ private void sendNextPurchaseVerificationPackageI() { if (activityHandler.getActivityState() == null) { return; } + if (packageQueue.isEmpty()) { + return; + } if (activityHandler.getActivityState().isGdprForgotten) { + logger.debug("purchase_verification request won't be sent for GDPR forgotten user"); return; } if (paused) { + logger.debug("PurchaseVerificationHandler is paused"); return; } - if (packageQueue.isEmpty()) { + if (isSendingPurchaseVerificationPackage) { + logger.debug("PurchaseVerificationHandler is is already sending a package"); return; } - final ActivityPackage purchaseVerificationPackage = packageQueue.remove(0); - int retries = purchaseVerificationPackage.getRetries(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - sendPurchaseVerificationPackageI(purchaseVerificationPackage); - sendNextPurchaseVerificationPackage(); - } - }; - - if (retries <= 0) { - runnable.run(); + long waitTimeMilliSeconds = waitTime(); + + if (waitTimeMilliSeconds > 0) { + Runnable runnable = new Runnable() { + @Override + public void run() { + lastPackageRetryInMilli = 0L; + sendNextPurchaseVerificationPackage(); + } + }; + scheduler.schedule(runnable, waitTimeMilliSeconds); return; } - long waitTimeMilliSeconds = Util.getWaitingTime(retries, backoffStrategy); - double waitTimeSeconds = waitTimeMilliSeconds / MILLISECONDS_TO_SECONDS_DIVISOR; - String secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds); - - logger.verbose("Waiting for %s seconds before retrying purchase_verification for the %d time", secondsString, retries); - scheduler.schedule(runnable, waitTimeMilliSeconds); + // get the package but keep it in the queue until processing is complete + final ActivityPackage purchaseVerificationPackage = packageQueue.get(0); + isSendingPurchaseVerificationPackage = true; + sendPurchaseVerificationPackageSync(purchaseVerificationPackage); } /** @@ -207,54 +220,73 @@ public void run() { * * @param purchaseVerificationPackage purchase_verification package to be sent. */ - private void sendPurchaseVerificationPackageI(final ActivityPackage purchaseVerificationPackage) { + private void sendPurchaseVerificationPackageSync(final ActivityPackage purchaseVerificationPackage) { IActivityHandler activityHandler = activityHandlerWeakRef.get(); - Map sendingParameters = generateSendingParametersI(); ResponseData responseData = activityPackageSender.sendActivityPackageSync( purchaseVerificationPackage, - sendingParameters); + null); if (!(responseData instanceof PurchaseVerificationResponseData)) { return; } + // reset flag to indicate we're done processing this package + isSendingPurchaseVerificationPackage = false; + PurchaseVerificationResponseData purchaseVerificationResponseData = (PurchaseVerificationResponseData)responseData; - if (purchaseVerificationResponseData.willRetry) { - retrySendingI(purchaseVerificationPackage); - return; - } - if (activityHandler == null) { - return; + if (purchaseVerificationResponseData.jsonResponse == null) { + logger.error("Could not get purchase_verification JSON response with message: %s", + purchaseVerificationResponseData.message); + } else { + + if (activityHandler == null) { + return; + } + // check if any package response contains information that user has opted out. + // if yes, disable SDK and flush any potentially stored packages that happened afterwards. + if (purchaseVerificationResponseData.trackingState == TrackingState.OPTED_OUT) { + activityHandler.gotOptOutResponse(); + return; + } + + // check if backend requested retry_in delay + if (purchaseVerificationResponseData.willRetry) { + if (responseData.retryIn != null && responseData.retryIn > 0) { + lastPackageRetryInMilli = responseData.retryIn; + logger.error("Retrying purchase_verification package with retry in %d ms", + lastPackageRetryInMilli); + } + + // package stays in queue - schedule retry + sendNextPurchaseVerificationPackage(); + return; + } + + lastPackageRetryInMilli = 0L; } - if (purchaseVerificationResponseData.trackingState == TrackingState.OPTED_OUT) { - activityHandler.gotOptOutResponse(); - return; + + // processing is complete - remove the package from queue + if (!packageQueue.isEmpty()) { + packageQueue.remove(0); } + // finish package tracking without retrying / backoff activityHandler.finishedTrackingActivity(purchaseVerificationResponseData); + + // process next package in queue if any + sendNextPurchaseVerificationPackage(); } - private Map generateSendingParametersI() { - HashMap sendingParameters = new HashMap<>(); - long now = System.currentTimeMillis(); - String dateString = Util.dateFormatter.format(now); - PackageBuilder.addString(sendingParameters, "sent_at", dateString); - int queueSize = packageQueue.size() - 1; - if (queueSize > 0) { - PackageBuilder.addLong(sendingParameters, "queue_size", queueSize); + + private long waitTime() { + // handle backend-requested retry_in delay + if (lastPackageRetryInMilli > 0) { + logger.verbose("Waiting for %d ms before retrying purchase_verification with retry_in", + lastPackageRetryInMilli); + return lastPackageRetryInMilli; } - return sendingParameters; - } - /** - * Retry sending of the purchase_verification package passed as the parameter (runs within scheduled executor). - * - * @param purchaseVerificationPackage purchase_verification package to be retried. - */ - private void retrySendingI(final ActivityPackage purchaseVerificationPackage) { - int retries = purchaseVerificationPackage.increaseRetries(); - logger.error("Retrying purchase_verification package for the %d time", retries); - sendPurchaseVerificationPackage(purchaseVerificationPackage); + return 0L; } } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ReferrerDetails.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ReferrerDetails.java index e84beaa8a..ef2f0c770 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ReferrerDetails.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ReferrerDetails.java @@ -58,4 +58,24 @@ public ReferrerDetails(final String installReferrer, isClick); } + + public String toString() { + return Util.formatString( + " installReferrer : %s" + + " referrerClickTimestampSeconds : %d" + + " installBeginTimestampSeconds : %d" + + " referrerClickTimestampServerSeconds : %d" + + " installBeginTimestampServerSeconds : %d" + + " installVersion : %s" + + " googlePlayInstant : %s" + + " isClick: %s", + installReferrer, + referrerClickTimestampSeconds, + installBeginTimestampSeconds, + referrerClickTimestampServerSeconds, + installBeginTimestampServerSeconds, + installVersion, + googlePlayInstant, + isClick); + } } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java index 57a388e87..0e31dbfaf 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Reflection.java @@ -4,9 +4,9 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; +import java.util.concurrent.TimeUnit; public class Reflection { public static Object getAdvertisingInfoObject(Context context) throws Exception { @@ -41,25 +41,73 @@ static Map getOaidParameters(Context context, ILogger logger) { return null; } - public static String getPlayAdId(Context context, Object AdvertisingInfoObject) { + public static String getGoogleAdId(Context context, Object AdvertisingInfoObject) { try { - String playAdid = (String) invokeInstanceMethod(AdvertisingInfoObject, "getId", null); - return playAdid; + String googleAdId = (String) invokeInstanceMethod(AdvertisingInfoObject, "getId", null); + return googleAdId; } catch (Throwable t) { return null; } } - public static Boolean isPlayTrackingEnabled(Context context, Object AdvertisingInfoObject) { + public static Boolean isGoogleAdIdTrackingEnabled(Context context, Object AdvertisingInfoObject) { try { Boolean isLimitedTrackingEnabled = (Boolean) invokeInstanceMethod(AdvertisingInfoObject, "isLimitAdTrackingEnabled", null); - Boolean isPlayTrackingEnabled = (isLimitedTrackingEnabled == null ? null : !isLimitedTrackingEnabled); - return isPlayTrackingEnabled; + Boolean isGoogleAdIdTrackingEnabled = (isLimitedTrackingEnabled == null ? null : !isLimitedTrackingEnabled); + return isGoogleAdIdTrackingEnabled; } catch (Throwable t) { return null; } } + public static ReferrerDetails getMetaReferrer(Context context, String fbAppId, ILogger logger) { + ReferrerDetails referrerDetails = null; + try { + referrerDetails = (ReferrerDetails) invokeStaticMethod("com.adjust.sdk.meta.Util", + "getMetaInstallReferrerDetails", + new Class[]{Context.class, String.class, ILogger.class}, + context, fbAppId, logger); + } catch (Exception e) { + } + return referrerDetails; + } + + public static LicenseData getLicenseRequiredData(Context context, ILogger logger, long timestamp) { + LicenseData licenseData = null; + try { + licenseData = (LicenseData) invokeStaticMethod("com.adjust.sdk.google.lvl.Util", + "getLicenseRequiredData", + new Class[]{Context.class, ILogger.class, long.class}, + context, logger, timestamp); + } catch (Exception e) { + } + return licenseData; + } + + public static ReferrerDetails getHuaweiAdsReferrer(Context context, ILogger logger) { + ReferrerDetails referrerDetails = null; + try { + referrerDetails = (ReferrerDetails) invokeStaticMethod("com.adjust.sdk.huawei.Util", + "getHuaweiAdsInstallReferrerDetails", + new Class[]{Context.class, ILogger.class}, + context, logger); + } catch (Exception e) { + } + return referrerDetails; + } + + public static ReferrerDetails getHuaweiAppGalleryReferrer(Context context, ILogger logger) { + ReferrerDetails referrerDetails = null; + try { + referrerDetails = (ReferrerDetails) invokeStaticMethod("com.adjust.sdk.huawei.Util", + "getHuaweiAppGalleryInstallReferrerDetails", + new Class[]{Context.class, ILogger.class}, + context, logger); + } catch (Exception e) { + } + return referrerDetails; + } + public static ReferrerDetails getSamsungReferrer(Context context, ILogger logger) { ReferrerDetails referrerDetails = null; try { @@ -68,7 +116,6 @@ public static ReferrerDetails getSamsungReferrer(Context context, ILogger logger new Class[]{Context.class, ILogger.class}, context, logger); } catch (Exception e) { - logger.info("invoke getSamsungInstallReferrerDetails : " + e.getMessage()); } return referrerDetails; } @@ -81,7 +128,6 @@ public static ReferrerDetails getXiaomiReferrer(Context context, ILogger logger) new Class[]{Context.class, ILogger.class}, context, logger); } catch (Exception e) { - logger.info("invoke getXiaomiInstallReferrerDetails : " + e.getMessage()); } return referrerDetails; } @@ -94,7 +140,6 @@ public static ReferrerDetails getVivoReferrer(Context context, ILogger logger) { new Class[]{Context.class, ILogger.class}, context, logger); } catch (Exception e) { - logger.info("invoke getVivoInstallReferrerDetails : " + e.getMessage()); } return referrerDetails; } @@ -113,8 +158,8 @@ public static String getAppSetId(Context context) { Object appSetInfoObject = invokeStaticMethod("com.google.android.gms.tasks.Tasks", "await", - new Class[]{forName("com.google.android.gms.tasks.Task")}, - taskWithAppSetInfoObject); + new Class[]{forName("com.google.android.gms.tasks.Task"), long.class, TimeUnit.class}, + taskWithAppSetInfoObject, 1L, TimeUnit.SECONDS); return (String) invokeInstanceMethod(appSetInfoObject, "getId", null); @@ -127,11 +172,10 @@ public static String getSamsungCloudDevGoogleAdId(Context context, ILogger logge String googleAdId = null; try { googleAdId = (String) invokeStaticMethod("com.adjust.sdk.samsung.clouddev.Util", - "getGoogleAdId", + "getGoogleAdIdInCloudEnvironment", new Class[]{Context.class, ILogger.class}, context, logger); } catch (Exception e) { - logger.info("invoke getGoogleAdId : " + e.getMessage()); } return googleAdId; } @@ -144,7 +188,6 @@ public static boolean isAppRunningInSamsungCloudEnvironment(Context context, ILo new Class[]{Context.class, ILogger.class}, context, logger); } catch (Exception e) { - logger.info("invoke isAppRunningInCloudEnvironment : " + e.getMessage()); } return isCloudEnvironment; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java index 95a6ea5a9..72fbbdb55 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ResponseData.java @@ -25,7 +25,9 @@ public class ResponseData { public ActivityPackage activityPackage; public Map sendingParameters; + public Map signedParameters; public String resolvedDeeplink; + public JSONObject controlParams; protected ResponseData() { success = false; @@ -34,7 +36,8 @@ protected ResponseData() { public static ResponseData buildResponseData( ActivityPackage activityPackage, - Map sendingParameters) + Map sendingParameters, + Map signedParameters) { ResponseData responseData; ActivityKind activityKind = activityPackage.getActivityKind(); @@ -54,6 +57,9 @@ public static ResponseData buildResponseData( case PURCHASE_VERIFICATION: responseData = new PurchaseVerificationResponseData(); break; + case THIRD_PARTY_SHARING: + responseData = new ThirdPartySharingResponseData(); + break; default: responseData = new ResponseData(); break; @@ -61,6 +67,7 @@ public static ResponseData buildResponseData( responseData.activityKind = activityKind; responseData.activityPackage = activityPackage; responseData.sendingParameters = sendingParameters; + responseData.signedParameters = signedParameters; return responseData; } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java index e2fbf1e4b..0476f668b 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SdkClickHandler.java @@ -73,6 +73,8 @@ public class SdkClickHandler implements ISdkClickHandler { private IActivityPackageSender activityPackageSender; + private long lastPackageRetryInMilli = 0L; + /** * SdkClickHandler constructor. * @@ -177,7 +179,8 @@ public void run() { activityHandler.getActivityState(), activityHandler.getAdjustConfig(), activityHandler.getDeviceInfo(), - activityHandler.getSessionParameters(), + activityHandler.getGlobalParameters(), + activityHandler.getFirstSessionDelayManager(), activityHandler.getInternalState()); // Send referrer sdk_click package. @@ -215,7 +218,8 @@ public void run() { activityHandler.getActivityState(), activityHandler.getAdjustConfig(), activityHandler.getDeviceInfo(), - activityHandler.getSessionParameters()); + activityHandler.getGlobalParameters(), + activityHandler.getFirstSessionDelayManager()); // Send preinstall info sdk_click package. sendSdkClick(sdkClickPackage); @@ -289,18 +293,12 @@ public void run() { } }; - if (retries <= 0) { + long waitTimeMilliSeconds = waitTime(retries); + if (waitTimeMilliSeconds > 0) { + scheduler.schedule(runnable, waitTimeMilliSeconds); + } else { runnable.run(); - return; } - - long waitTimeMilliSeconds = Util.getWaitingTime(retries, backoffStrategy); - double waitTimeSeconds = waitTimeMilliSeconds / MILLISECONDS_TO_SECONDS_DIVISOR; - String secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds); - - logger.verbose("Waiting for %s seconds before retrying sdk_click for the %d time", secondsString, retries); - - scheduler.schedule(runnable, waitTimeMilliSeconds); } /** @@ -353,6 +351,8 @@ private void sendSdkClickI(final ActivityPackage sdkClickPackage) { boolean isPreinstall = source != null && source.equals(Constants.PREINSTALL); + boolean isLicenseVerification = source != null && source.equals(Constants.LICENSE_VERIFICATION); + Map sendingParameters = generateSendingParametersI(); ResponseData responseData = activityPackageSender.sendActivityPackageSync( @@ -366,10 +366,12 @@ private void sendSdkClickI(final ActivityPackage sdkClickPackage) { SdkClickResponseData sdkClickResponseData = (SdkClickResponseData)responseData; if (sdkClickResponseData.willRetry) { - retrySendingI(sdkClickPackage); + retrySendingI(sdkClickPackage, sdkClickResponseData.retryIn); return; } + lastPackageRetryInMilli = 0L; + if (activityHandler == null) { return; } @@ -418,16 +420,19 @@ private void sendSdkClickI(final ActivityPackage sdkClickPackage) { } } + if (isLicenseVerification){ + // update preinstall flag in shared preferences after sdk_click is sent. + SharedPreferencesManager sharedPreferencesManager + = SharedPreferencesManager.getDefaultInstance(activityHandler.getContext()); + + sharedPreferencesManager.setLicenseVerificationTracked(); + } + activityHandler.finishedTrackingActivity(sdkClickResponseData); } private Map generateSendingParametersI() { HashMap sendingParameters = new HashMap<>(); - long now = System.currentTimeMillis(); - String dateString = Util.dateFormatter.format(now); - - PackageBuilder.addString(sendingParameters, "sent_at", dateString); - int queueSize = packageQueue.size() - 1; if (queueSize > 0) { PackageBuilder.addLong(sendingParameters, "queue_size", queueSize); @@ -439,11 +444,16 @@ private Map generateSendingParametersI() { * Retry sending of the sdk_click package passed as the parameter (runs within scheduled executor). * * @param sdkClickPackage sdk_click package to be retried. + * @param retryIn */ - private void retrySendingI(final ActivityPackage sdkClickPackage) { - int retries = sdkClickPackage.increaseRetries(); + private void retrySendingI(final ActivityPackage sdkClickPackage, Long retryIn) { + if (retryIn != null && retryIn > 0) { + lastPackageRetryInMilli = retryIn; + } else { + int retries = sdkClickPackage.increaseRetries(); - logger.error("Retrying sdk_click package for the %d time", retries); + logger.error("Retrying sdk_click package for the %d time", retries); + } sendSdkClick(sdkClickPackage); } @@ -464,4 +474,26 @@ private void logErrorMessageI(final ActivityPackage sdkClickPackage, logger.error(finalMessage); } + + /** + * calculate wait time (runs within scheduled executor). + * @param retries count of retries + * @return calculated wait time depends on the number of retry in and backoff strategy + */ + private long waitTime(int retries) { + if (lastPackageRetryInMilli > 0) { + return lastPackageRetryInMilli; + } + + if (retries > 0) { + long waitTimeMilliSeconds = Util.getWaitingTime(retries, backoffStrategy); + double waitTimeSeconds = waitTimeMilliSeconds / MILLISECONDS_TO_SECONDS_DIVISOR; + String secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds); + logger.verbose("Waiting for %s seconds before retrying sdk_click for the %d time", secondsString, retries); + return waitTimeMilliSeconds; + } + + return 0L; + } + } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java index e6e2fc178..77b7c580f 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SessionResponseData.java @@ -1,5 +1,7 @@ package com.adjust.sdk; +import android.net.Uri; + import org.json.JSONObject; /** @@ -9,6 +11,7 @@ */ public class SessionResponseData extends ResponseData { private String sdkPlatform; + public Uri deeplink; public SessionResponseData(final ActivityPackage activityPackage) { this.sdkPlatform = Util.getSdkPrefixPlatform(activityPackage.getClientSdk()); diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java index d3209ff03..2415d4c26 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SharedPreferencesManager.java @@ -2,10 +2,12 @@ import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; +import android.text.TextUtils; /** * Class used for shared preferences manipulation. @@ -37,19 +39,26 @@ public class SharedPreferencesManager { private static final String PREFS_KEY_GDPR_FORGET_ME = "gdpr_forget_me"; - private static final String PREFS_KEY_DISABLE_THIRD_PARTY_SHARING - = "disable_third_party_sharing"; - private static final String PREFS_KEY_DEEPLINK_URL = "deeplink_url"; + private static final String PREFS_KEY_DEEPLINK_REFERRER = "deeplink_referrer"; + private static final String PREFS_KEY_DEEPLINK_CLICK_TIME = "deeplink_click_time"; + private static final String PREFS_KEY_DEEPLINK_URL_CACHED = "deeplink_url_cached"; + private static final String PREFS_KEY_PREINSTALL_PAYLOAD_READ_STATUS = "preinstall_payload_read_status"; private static final String PREFS_KEY_PREINSTALL_SYSTEM_INSTALLER_REFERRER = "preinstall_system_installer_referrer"; + private static final String PREFS_KEY_CONTROL_PARAMS = "control_params"; + + private static final String PREFS_KEY_LVL_TRACKED = "lvl_tracked"; + + private static final String PREFS_KEY_TPS_RESULT_SETTINGS = "tps_result_settings"; + /** * Index for raw referrer string content in saved JSONArray object. */ @@ -372,40 +381,53 @@ public synchronized void removeGdprForgetMe() { remove(PREFS_KEY_GDPR_FORGET_ME); } - public synchronized void setDisableThirdPartySharing() { - saveBoolean(PREFS_KEY_DISABLE_THIRD_PARTY_SHARING, true); - } - - public synchronized boolean getDisableThirdPartySharing() { - return getBoolean(PREFS_KEY_DISABLE_THIRD_PARTY_SHARING, false); - } - - public synchronized void removeDisableThirdPartySharing() { - remove(PREFS_KEY_DISABLE_THIRD_PARTY_SHARING); - } - - public synchronized void saveDeeplink(final Uri deeplink, final long clickTime) { + public synchronized void saveDeeplink(final AdjustDeeplink deeplink, final long clickTime) { if (deeplink == null) { return; } - saveString(PREFS_KEY_DEEPLINK_URL, deeplink.toString()); + if (deeplink.url == null) { + return; + } + + saveString(PREFS_KEY_DEEPLINK_URL, deeplink.url.toString()); saveLong(PREFS_KEY_DEEPLINK_CLICK_TIME, clickTime); + + if (deeplink.referrer != null) { + saveString(PREFS_KEY_DEEPLINK_REFERRER, deeplink.referrer.toString()); + } } public synchronized String getDeeplinkUrl() { return getString(PREFS_KEY_DEEPLINK_URL); } + public synchronized String getDeeplinkReferrer() { + return getString(PREFS_KEY_DEEPLINK_REFERRER); + } + public synchronized long getDeeplinkClickTime() { return getLong(PREFS_KEY_DEEPLINK_CLICK_TIME, -1); } public synchronized void removeDeeplink() { remove(PREFS_KEY_DEEPLINK_URL); + remove(PREFS_KEY_DEEPLINK_REFERRER); remove(PREFS_KEY_DEEPLINK_CLICK_TIME); } + public synchronized void cacheDeeplink(final Uri deeplink) { + if (deeplink == null) { + return; + } + + saveString(PREFS_KEY_DEEPLINK_URL_CACHED, deeplink.toString()); + } + + public synchronized String getCachedDeeplink() { + return getString(PREFS_KEY_DEEPLINK_URL_CACHED); + } + /** * Save information that preinstall tracker has been tracked to shared preferences. */ @@ -423,6 +445,71 @@ public synchronized long getPreinstallPayloadReadStatus() { return getLong(PREFS_KEY_PREINSTALL_PAYLOAD_READ_STATUS, 0); } + /** + * Save control params json to shared preferences. + * + * @param controlParams Control params json to be saved + */ + public synchronized void saveControlParams(final JSONObject controlParams) { + try { + saveString(PREFS_KEY_CONTROL_PARAMS, controlParams.toString()); + } catch (Throwable t) { + } + } + + /** + * Get saved control params json object. + * + * @return JSONObject containing control params information. Defaults to null if not found. + */ + public synchronized JSONObject getControlParamsJson() { + String controlParamsString = getString(PREFS_KEY_CONTROL_PARAMS); + + if (controlParamsString != null) { + try { + return new JSONObject(controlParamsString); + } catch (JSONException e) { + } catch (Throwable t) { + } + } + + return null; + } + + + /** + * Save information that license verification has been tracked to shared preferences. + */ + public synchronized void setLicenseVerificationTracked() { + saveBoolean(PREFS_KEY_LVL_TRACKED, true); + } + + /** + * Get information if license verification has been tracked from shared preferences. If no info, default to false. + * + * @return boolean indicating whether license verification has been tracked or not + */ + public synchronized boolean getLicenseVerificationTracked() { + return getBoolean(PREFS_KEY_LVL_TRACKED, false); + } + + public synchronized void saveThirdPartySharingResult(final AdjustThirdPartySharingResult thirdPartySharingResult) { + try { + saveString(PREFS_KEY_TPS_RESULT_SETTINGS, thirdPartySharingResult.getThirdPartySharingSettingsJson()); + } catch (Throwable t) { + } + } + + public synchronized AdjustThirdPartySharingResult getThirdPartySharingResult() { + String thirdPartySharingSettingsJson = getString(PREFS_KEY_TPS_RESULT_SETTINGS); + + if (TextUtils.isEmpty(thirdPartySharingSettingsJson)) { + return null; + } + + return new AdjustThirdPartySharingResult(thirdPartySharingSettingsJson); + } + /** * Remove all key-value pairs from shared preferences. */ diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/StoreInfoUtil.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/StoreInfoUtil.java new file mode 100644 index 000000000..8319011c3 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/StoreInfoUtil.java @@ -0,0 +1,104 @@ +package com.adjust.sdk; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.InstallSourceInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; + +public class StoreInfoUtil { + + public static Boolean getIsSystemApp(final Context context) { + try { + ApplicationInfo ai = + context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + return ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) + ? Boolean.TRUE + : null; + } catch (Exception e) { + return null; + } + } + + public static Boolean getIsUpdatedSystemApp(final Context context) { + try { + ApplicationInfo ai = + context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + return ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) + ? Boolean.TRUE + : null; + } catch (Exception e) { + return null; + } + } + + @SuppressWarnings("deprecation") + public static String getStoreIdFromSystem(final Context context) { + try { + PackageManager packageManager = context.getPackageManager(); + String packageName = context.getPackageName(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + InstallSourceInfo installSourceInfo = packageManager.getInstallSourceInfo(packageName); + return installSourceInfo.getInstallingPackageName(); + } else { + return packageManager.getInstallerPackageName(packageName); + } + } catch (Exception e) { + return null; + } + } + + public static AdjustStoreInfo getStoreInfoFromClient(final AdjustConfig adjustConfig, final Context context) { + try { + ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); + Bundle metaData = applicationInfo.metaData; + if (metaData == null) { + return adjustConfig.storeInfo; + } + + String storeName = metaData.getString("ADJUST_STORE_NAME"); + if (storeName == null || storeName.isEmpty()) { + return adjustConfig.storeInfo; + } + + String storeAppId = metaData.getString("ADJUST_STORE_APP_ID"); + + AdjustStoreInfo storeInfo = new AdjustStoreInfo(storeName); + storeInfo.setStoreAppId(storeAppId); + return storeInfo; + + } catch (Exception e) { + return adjustConfig.storeInfo; + } + } + + public static String getInitiatingPackageName(final Context context) { + try { + PackageManager packageManager = context.getPackageManager(); + String packageName = context.getPackageName(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + InstallSourceInfo installSourceInfo = packageManager.getInstallSourceInfo(packageName); + return installSourceInfo.getInitiatingPackageName(); + } + } catch (Exception e) { + } + return null; + } + + public static String getOriginatingPackageName(final Context context) { + try { + PackageManager packageManager = context.getPackageManager(); + String packageName = context.getPackageName(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + InstallSourceInfo installSourceInfo = packageManager.getInstallSourceInfo(packageName); + return installSourceInfo.getOriginatingPackageName(); + } + } catch (Exception e) { + } + return null; + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycle.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycle.java new file mode 100644 index 000000000..96a6fe4b6 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycle.java @@ -0,0 +1,131 @@ +package com.adjust.sdk; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.concurrent.CopyOnWriteArrayList; + +public class SystemLifecycle implements Application.ActivityLifecycleCallbacks +{ + public interface SystemLifecycleCallback { + void onActivityLifecycle(final boolean foregroundOrElseBackground); + } + + public static class SystemLifecycleCache implements SystemLifecycleCallback { + public volatile @Nullable Boolean foregroundOrElseBackgroundCache = null; + + @Override + public void onActivityLifecycle(final boolean foregroundOrElseBackground) { + this.foregroundOrElseBackgroundCache = foregroundOrElseBackground; + } + } + + // region Injected dependencies + private @Nullable Application application; + + private volatile @NonNull SystemLifecycleCallback callback; + // endregion + + // region Internal variables + private static volatile SystemLifecycle instance; + // CopyOnWrite to allow iterating and mutation in different threads + public @NonNull final CopyOnWriteArrayList logMessageList; + private final @NonNull SystemLifecycleCache callbackCache; + // endregion + + // region Instantiation + public SystemLifecycle() { + this.application = null; + this.callbackCache = new SystemLifecycleCache(); + this.callback = callbackCache; + this.logMessageList = new CopyOnWriteArrayList<>(); + } + + @NonNull + public static SystemLifecycle getSingletonInstance() { + @Nullable SystemLifecycle localInstance = instance; + if (localInstance == null) { + synchronized (SystemLifecycle.class) { + localInstance = instance; + if (localInstance == null) { + localInstance = new SystemLifecycle(); + instance = localInstance; + } + } + } + return localInstance; + } + // endregion + + // region Application.ActivityLifecycleCallbacks + @Override public void onActivityResumed(@NonNull final Activity activity) { + callback.onActivityLifecycle(true); + } + + @Override public void onActivityPaused(@NonNull final Activity activity) { + callback.onActivityLifecycle(false); + } + // region Unused + @Override + public void onActivityCreated(@NonNull final Activity activity, + @Nullable final Bundle savedInstanceState) + { } + + @Override public void onActivityStarted(@NonNull final Activity activity) { } + + @Override public void onActivityStopped(@NonNull final Activity activity) { } + + @Override + public void onActivitySaveInstanceState(@NonNull final Activity activity, + @NonNull final Bundle outState) + { } + + @Override public void onActivityDestroyed(@NonNull final Activity activity) { } + // endregion + // endregion + + // region Public API + // synchronized to prevent double registering + public synchronized void registerActivityLifecycleCallbacks( + @Nullable final Context context) + { + if (application != null) { + logMessageList.add("Cannot register activity lifecycle callbacks more than once"); + return; + } + + if (context == null) { + logMessageList.add("Cannot register activity lifecycle callbacks without context"); + return; + } + + @Nullable final Context applicationContext = context.getApplicationContext(); + if (! (applicationContext instanceof Application)) { + logMessageList.add( + "Cannot register activity lifecycle callbacks without application context as Application"); + return; + } + + logMessageList.add("Registering activity lifecycle callbacks"); + + application = (Application) applicationContext; + application.registerActivityLifecycleCallbacks(this); + } + + public void overwriteCallback( + @NonNull final SystemLifecycleCallback systemLifecycleCallback) + { + this.callback = systemLifecycleCallback; + } + + @Nullable + public Boolean foregroundOrElseBackgroundCached() { + return callbackCache.foregroundOrElseBackgroundCache; + } + // endregion +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycleContentProvider.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycleContentProvider.java new file mode 100644 index 000000000..8b2169715 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/SystemLifecycleContentProvider.java @@ -0,0 +1,53 @@ +package com.adjust.sdk; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class SystemLifecycleContentProvider extends ContentProvider { + // region ContentProvider + @Override public boolean onCreate() { + SystemLifecycle.getSingletonInstance(). + registerActivityLifecycleCallbacks(getContext()); + + return false; + } + + @Nullable @Override public Cursor query(@NonNull final Uri uri, + @Nullable final String[] projection, + @Nullable final String selection, + @Nullable final String[] selectionArgs, + @Nullable final String sortOrder) + { + return null; + } + + @Nullable @Override public String getType(@NonNull final Uri uri) { + return null; + } + + @Nullable @Override + public Uri insert(@NonNull final Uri uri, @Nullable final ContentValues values) { + return null; + } + + @Override public int delete(@NonNull final Uri uri, + @Nullable final String selection, + @Nullable final String[] selectionArgs) + { + return 0; + } + + @Override public int update(@NonNull final Uri uri, + @Nullable final ContentValues values, + @Nullable final String selection, + @Nullable final String[] selectionArgs) + { + return 0; + } + // endregion +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/ThirdPartySharingResponseData.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ThirdPartySharingResponseData.java new file mode 100644 index 000000000..00196a280 --- /dev/null +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/ThirdPartySharingResponseData.java @@ -0,0 +1,4 @@ +package com.adjust.sdk; + +public class ThirdPartySharingResponseData extends ResponseData { +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java index 89e828867..491eddedb 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/Util.java @@ -10,7 +10,6 @@ package com.adjust.sdk; import static com.adjust.sdk.Constants.ENCODING; -import static com.adjust.sdk.Constants.SHA256; import android.content.Context; import android.content.pm.PackageManager; @@ -22,12 +21,15 @@ import com.adjust.sdk.scheduler.AsyncTaskExecutor; import com.adjust.sdk.scheduler.SingleThreadFutureScheduler; +import org.json.JSONObject; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.InvalidClassException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -62,7 +64,7 @@ public class Util { public static final SimpleDateFormat dateFormatter = new SimpleDateFormat(DATE_FORMAT, Locale.US); // https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html - private static volatile SingleThreadFutureScheduler playAdIdScheduler = null; + private static volatile SingleThreadFutureScheduler googleAdIdScheduler = null; private static ILogger getLogger() { return AdjustFactory.getLogger(); @@ -92,7 +94,7 @@ public static String quote(String string) { } public static Object getAdvertisingInfoObject(final Context context, long timeoutMilli) { - return runSyncInPlayAdIdSchedulerWithTimeout(context, new Callable() { + return runSyncInGoogleAdIdSchedulerWithTimeout(context, new Callable() { @Override public Object call() { try { @@ -104,46 +106,46 @@ public Object call() { }, timeoutMilli); } - public static String getPlayAdId(final Context context, - final Object advertisingInfoObject, - long timeoutMilli) + public static String getGoogleAdId(final Context context, + final Object advertisingInfoObject, + long timeoutMilli) { - return runSyncInPlayAdIdSchedulerWithTimeout(context, new Callable() { + return runSyncInGoogleAdIdSchedulerWithTimeout(context, new Callable() { @Override public String call() { - return Reflection.getPlayAdId(context, advertisingInfoObject); + return Reflection.getGoogleAdId(context, advertisingInfoObject); } }, timeoutMilli); } - public static Boolean isPlayTrackingEnabled(final Context context, - final Object advertisingInfoObject, - long timeoutMilli) + public static Boolean isGoogleAdIdTrackingEnabled(final Context context, + final Object advertisingInfoObject, + long timeoutMilli) { - return runSyncInPlayAdIdSchedulerWithTimeout(context, new Callable() { + return runSyncInGoogleAdIdSchedulerWithTimeout(context, new Callable() { @Override public Boolean call() { - return Reflection.isPlayTrackingEnabled(context, advertisingInfoObject); + return Reflection.isGoogleAdIdTrackingEnabled(context, advertisingInfoObject); } }, timeoutMilli); } - private static R runSyncInPlayAdIdSchedulerWithTimeout(final Context context, - Callable callable, - long timeoutMilli) + private static R runSyncInGoogleAdIdSchedulerWithTimeout(final Context context, + Callable callable, + long timeoutMilli) { - if (playAdIdScheduler == null) { + if (googleAdIdScheduler == null) { synchronized (Util.class) { - if (playAdIdScheduler == null) { - playAdIdScheduler = new SingleThreadFutureScheduler("PlayAdIdLibrary", true); + if (googleAdIdScheduler == null) { + googleAdIdScheduler = new SingleThreadFutureScheduler("PlayAdIdLibrary", true); } } } - ScheduledFuture playAdIdFuture = playAdIdScheduler.scheduleFutureWithReturn(callable, 0); + ScheduledFuture googleAdIdFuture = googleAdIdScheduler.scheduleFutureWithReturn(callable, 0); try { - return playAdIdFuture.get(timeoutMilli, TimeUnit.MILLISECONDS); + return googleAdIdFuture.get(timeoutMilli, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { } catch (InterruptedException e) { } catch (TimeoutException e) { @@ -152,7 +154,13 @@ private static R runSyncInPlayAdIdSchedulerWithTimeout(final Context context return null; } - public static void getGoogleAdId(Context context, final OnDeviceIdsRead onDeviceIdRead) { + /** + * Called to get value of Google Play Advertising Identifier. + * + * @param context Application context + * @param onGoogleAdIdReadListener Callback to get triggered once identifier is obtained + */ + public static void getGoogleAdId(final Context context, final OnGoogleAdIdReadListener onGoogleAdIdReadListener) { new AsyncTaskExecutor() { @Override protected String doInBackground(Context... params) { @@ -164,9 +172,9 @@ protected String doInBackground(Context... params) { } @Override - protected void onPostExecute(String playAdiId) { - if (onDeviceIdRead != null) { - onDeviceIdRead.onGoogleAdIdRead(playAdiId); + protected void onPostExecute(String googleAdiId) { + if (onGoogleAdIdReadListener != null) { + onGoogleAdIdReadListener.onGoogleAdIdRead(googleAdiId); } } }.execute(context); @@ -188,7 +196,7 @@ private static String getGoogleAdId(Context context) { context, Constants.ONE_SECOND * 11); if (advertisingInfoObject != null) { - googleAdId = Util.getPlayAdId(context, advertisingInfoObject, Constants.ONE_SECOND); + googleAdId = Util.getGoogleAdId(context, advertisingInfoObject, Constants.ONE_SECOND); } } @@ -209,7 +217,7 @@ public static T readObject(Context context, String filename, String objectNa BufferedInputStream bufferedStream = new BufferedInputStream(inputStream); closable = bufferedStream; - ObjectInputStream objectStream = new ObjectInputStream(bufferedStream); + ObjectInputStream objectStream = new ObjectInputFilterStream(bufferedStream); closable = objectStream; try { @@ -217,6 +225,8 @@ public static T readObject(Context context, String filename, String objectNa getLogger().debug("Read %s: %s", objectName, object); } catch (ClassNotFoundException e) { getLogger().error("Failed to find %s class (%s)", objectName, e.getMessage()); + } catch (InvalidClassException e) { + getLogger().error("Failed to validate %s class (%s)", objectName, e.getMessage()); } catch (ClassCastException e) { getLogger().error("Failed to cast %s object (%s)", objectName, e.getMessage()); } catch (Exception e) { @@ -405,10 +415,6 @@ public static int hashObject(Object value, int hashCode) { return 37 * hashCode + value.hashCode(); } - public static String sha256(final String text) { - return hash(text, SHA256); - } - public static String hash(final String text, final String method) { String hashString = null; try { @@ -620,6 +626,23 @@ public static boolean isUrlFilteredOut(Uri url) { return false; } + public static boolean isUrlWithTrackerQueryParam(Uri url) { + try { + String trackerParam = url.getQueryParameter("adj_t"); + if (trackerParam != null) { + return true; + } + + trackerParam = url.getQueryParameter("adjust_t"); + if (trackerParam != null) { + return true; + } + } catch (Exception e) { + } + + return false; + } + public static String getSdkVersion() { return Constants.CLIENT_SDK; } @@ -657,33 +680,53 @@ public static boolean isEqualReferrerDetails(final ReferrerDetails referrerDetai return false; } - public static boolean canReadPlayIds(final AdjustConfig adjustConfig) { - if (adjustConfig.playStoreKidsAppEnabled) { + public static boolean isGoogleAdIdReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { return false; } - if (adjustConfig.coppaCompliantEnabled) { + return adjustConfig.isGoogleAdIdReadingEnabled; + } + + public static boolean isAndroidIdReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { return false; } - return true; + return adjustConfig.isAndroidIdReadingEnabled; } - public static boolean canReadNonPlayIds(final AdjustConfig adjustConfig) { - if (adjustConfig.playStoreKidsAppEnabled) { + public static boolean isAppSetIdReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { return false; } - if (adjustConfig.coppaCompliantEnabled) { + return adjustConfig.isAppSetIdReadingEnabled; + } + + public static boolean isFbIdReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { return false; } - return true; + return adjustConfig.isFbIdReadingEnabled; } + public static boolean isFireAdIdReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { + return false; + } + return adjustConfig.isFireAdIdReadingEnabled; + } + public static boolean isDeviceIdsFromPluginsReadingEnabled(final AdjustConfig adjustConfig) { + if (adjustConfig.coppaComplianceEnabled || adjustConfig.playStoreKidsComplianceEnabled) { + return false; + } + return adjustConfig.isDeviceIdsFromPluginsReadingEnabled; + } public static boolean isGooglePlayGamesForPC(final Context context) { PackageManager pm = context.getPackageManager(); @@ -746,4 +789,79 @@ private static boolean isEqualMetaReferrerDetails(final ReferrerDetails referrer && Util.equalString(referrerDetails.installReferrer, activityState.installReferrerMeta) && Util.equalBoolean(referrerDetails.isClick, activityState.isClickMeta); } -} \ No newline at end of file + + public static boolean isEnabledFromActivityStateFile(final Context context) { + ActivityState activityState = Util.readObject( + context, + Constants.ACTIVITY_STATE_FILENAME, + "Activity state", + ActivityState.class); + if (activityState == null) { + return true; + } else { + return activityState.enabled; + } + } + + public static AdjustAttribution attributionFromJson(final JSONObject jsonObject, + final String sdkPlatform) { + if (jsonObject == null) { + return null; + } + + AdjustAttribution attribution = new AdjustAttribution(); + + attribution.jsonResponse = jsonObject.toString(); + + if ("unity".equals(sdkPlatform)) { + // Unity platform. + attribution.trackerToken = jsonObject.optString("tracker_token", ""); + attribution.trackerName = jsonObject.optString("tracker_name", ""); + attribution.network = jsonObject.optString("network", ""); + attribution.campaign = jsonObject.optString("campaign", ""); + attribution.adgroup = jsonObject.optString("adgroup", ""); + attribution.creative = jsonObject.optString("creative", ""); + attribution.clickLabel = jsonObject.optString("click_label", ""); + attribution.costType = jsonObject.optString("cost_type", ""); + attribution.costAmount = jsonObject.optDouble("cost_amount", 0); + attribution.costCurrency = jsonObject.optString("cost_currency", ""); + attribution.fbInstallReferrer = jsonObject.optString("fb_install_referrer", ""); + } else { + // Rest of all platforms. + attribution.trackerToken = jsonObject.optString("tracker_token"); + attribution.trackerName = jsonObject.optString("tracker_name"); + attribution.network = jsonObject.optString("network"); + attribution.campaign = jsonObject.optString("campaign"); + attribution.adgroup = jsonObject.optString("adgroup"); + attribution.creative = jsonObject.optString("creative"); + attribution.clickLabel = jsonObject.optString("click_label"); + attribution.costType = jsonObject.optString("cost_type"); + attribution.costAmount = jsonObject.optDouble("cost_amount"); + attribution.costCurrency = jsonObject.optString("cost_currency"); + attribution.fbInstallReferrer = jsonObject.optString("fb_install_referrer"); + } + + return attribution; + } + + public static String getAdidFromActivityStateFile(final Context context) { + ActivityState activityState = Util.readObject( + context, + Constants.ACTIVITY_STATE_FILENAME, + "Activity state", + ActivityState.class); + if (activityState == null) { + return null; + } else { + return activityState.adid; + } + } + + public static AdjustAttribution getAttributionFromAttributionFile(final Context context) { + return Util.readObject( + context, + Constants.ATTRIBUTION_FILENAME, + "Attribution", + AdjustAttribution.class); + } +} diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/ActivityPackageSender.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/ActivityPackageSender.java index c7595eaad..2298c6914 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/ActivityPackageSender.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/ActivityPackageSender.java @@ -5,13 +5,13 @@ import com.adjust.sdk.ActivityKind; import com.adjust.sdk.ActivityPackage; -import com.adjust.sdk.AdjustAttribution; import com.adjust.sdk.AdjustFactory; import com.adjust.sdk.AdjustSigner; import com.adjust.sdk.Constants; import com.adjust.sdk.ILogger; import com.adjust.sdk.PackageBuilder; import com.adjust.sdk.ResponseData; +import com.adjust.sdk.SharedPreferencesManager; import com.adjust.sdk.TrackingState; import com.adjust.sdk.Util; import com.adjust.sdk.scheduler.SingleThreadCachedScheduler; @@ -34,6 +34,8 @@ import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; @@ -52,13 +54,16 @@ public class ActivityPackageSender implements IActivityPackageSender { private IHttpsURLConnectionProvider httpsURLConnectionProvider; private IConnectionOptions connectionOptions; private Context context; + private int connectionTimeout; - public ActivityPackageSender(final String adjustUrlStrategy, + public ActivityPackageSender(final List urlStrategyDomains, + final boolean useSubdomains, final String basePath, final String gdprPath, final String subscriptionPath, final String purchaseVerificationPath, final String clientSdk, + final int connectionTimeout, final Context context) { this.basePath = basePath; @@ -66,6 +71,7 @@ public ActivityPackageSender(final String adjustUrlStrategy, this.subscriptionPath = subscriptionPath; this.purchaseVerificationPath = purchaseVerificationPath; this.clientSdk = clientSdk; + this.connectionTimeout = connectionTimeout; this.context = context; logger = AdjustFactory.getLogger(); @@ -75,9 +81,11 @@ public ActivityPackageSender(final String adjustUrlStrategy, AdjustFactory.getGdprUrl(), AdjustFactory.getSubscriptionUrl(), AdjustFactory.getPurchaseVerificationUrl(), - adjustUrlStrategy); + urlStrategyDomains, + useSubdomains); httpsURLConnectionProvider = AdjustFactory.getHttpsURLConnectionProvider(); connectionOptions = AdjustFactory.getConnectionOptions(); + } @Override @@ -98,29 +106,72 @@ public void run() { public ResponseData sendActivityPackageSync(final ActivityPackage activityPackage, final Map sendingParameters) { - AdjustSigner.sign(activityPackage.getParameters(), - activityPackage.getActivityKind().toString(), - activityPackage.getClientSdk(), - context, - logger); - boolean retryToSend; ResponseData responseData; do { + Map updatedSendingParameters = updateSendingParameters(sendingParameters); + + Map signedParameters = signParameters(activityPackage, updatedSendingParameters); + responseData = - ResponseData.buildResponseData(activityPackage, sendingParameters); + ResponseData.buildResponseData(activityPackage, updatedSendingParameters, signedParameters); tryToGetResponse(responseData); - retryToSend = shouldRetryToSend(responseData); + retryToSend = shouldRetryToSendWithUrlStrategy(responseData); } while (retryToSend); return responseData; } - private boolean shouldRetryToSend(final ResponseData responseData) { - if (!responseData.willRetry) { - logger.debug("Will not retry with current url strategy"); + private Map updateSendingParameters(Map sendingParameters) { + Map updatedSendingParameters = sendingParameters; + if (updatedSendingParameters == null) { + updatedSendingParameters = new HashMap(); + } + long now = System.currentTimeMillis(); + String dateString = Util.dateFormatter.format(now); + PackageBuilder.addString(updatedSendingParameters, "sent_at", dateString); + return updatedSendingParameters; + } + + private Map signParameters(final ActivityPackage activityPackage, + final Map sendingParameters) { + Map packageParams = new HashMap<>(activityPackage.getParameters()); + if (sendingParameters != null) { + packageParams.putAll(sendingParameters); + } + + Map extraParams = new HashMap<>(); + + extraParams.put("client_sdk", activityPackage.getClientSdk()); + extraParams.put("activity_kind", activityPackage.getActivityKind().toString()); + + String endpoint = urlStrategy.targetUrlByActivityKind(activityPackage.getActivityKind()); + extraParams.put("endpoint", endpoint); + + JSONObject controlParams = SharedPreferencesManager.getDefaultInstance(context).getControlParamsJson(); + if (controlParams != null) { + Iterator keys = controlParams.keys(); + + while (keys.hasNext()) { + String key = keys.next(); + try { + if (controlParams.get(key) instanceof String) { + extraParams.put(key, (String) controlParams.get(key)); + } + } catch (JSONException e) { + logger.error("JSONException while iterating control params"); + } + } + } + + return AdjustSigner.sign(packageParams, extraParams, context, logger); + } + + private boolean shouldRetryToSendWithUrlStrategy(final ResponseData responseData) { + if (responseData.jsonResponse != null) { + logger.debug("Will not retry with current url strategy, already got a valid json response"); urlStrategy.resetAfterSuccess(); return false; } @@ -139,26 +190,22 @@ private void tryToGetResponse(final ResponseData responseData) { DataOutputStream dataOutputStream = null; try { - ActivityPackage activityPackage = responseData.activityPackage; - Map activityPackageParameters = - new HashMap<>(activityPackage.getParameters()); - Map sendingParameters = responseData.sendingParameters; - - String authorizationHeader = buildAndExtractAuthorizationHeader( - activityPackageParameters, - activityPackage.getActivityKind()); + String authorizationHeader = extractAuthorizationHeader(responseData.signedParameters); + logger.verbose("authorizationHeader: %s", authorizationHeader); boolean shouldUseGET = responseData.activityPackage.getActivityKind() == ActivityKind.ATTRIBUTION; final String urlString; if (shouldUseGET) { - urlString = generateUrlStringForGET(activityPackage.getActivityKind(), - activityPackage.getPath(), - activityPackageParameters, - sendingParameters); + urlString = generateUrlStringForGET(responseData.activityPackage.getActivityKind(), + responseData.activityPackage.getPath(), + responseData.activityPackage.getParameters(), + responseData.sendingParameters, + responseData.signedParameters); } else { - urlString = generateUrlStringForPOST(activityPackage.getActivityKind(), - activityPackage.getPath()); + urlString = generateUrlStringForPOST(responseData.activityPackage.getActivityKind(), + responseData.activityPackage.getPath(), + responseData.signedParameters); } final URL url = new URL(urlString); @@ -166,7 +213,7 @@ private void tryToGetResponse(final ResponseData responseData) { httpsURLConnectionProvider.generateHttpsURLConnection(url); // get and apply connection options (default or for tests) - connectionOptions.applyConnectionOptions(connection, activityPackage.getClientSdk()); + connectionOptions.applyConnectionOptions(connection, clientSdk, connectionTimeout); if (authorizationHeader != null) { connection.setRequestProperty("Authorization", authorizationHeader); @@ -176,8 +223,9 @@ private void tryToGetResponse(final ResponseData responseData) { dataOutputStream = configConnectionForGET(connection); } else { dataOutputStream = configConnectionForPOST(connection, - activityPackageParameters, - sendingParameters); + responseData.activityPackage.getParameters(), + responseData.sendingParameters, + responseData.signedParameters); } // read connection response @@ -281,10 +329,11 @@ private String errorMessage(final Throwable throwable, private String generateUrlStringForGET(final ActivityKind activityKind, final String activityPackagePath, final Map activityPackageParameters, - final Map sendingParameters) + final Map sendingParameters, + final Map signedParameters) throws MalformedURLException { - String targetUrl = urlStrategy.targetUrlByActivityKind(activityKind); + String targetUrl = extractTargetUrl(signedParameters, activityKind, urlStrategy); // extra path, if present, has the format '/X/Y' String urlWithPath = @@ -297,26 +346,34 @@ private String generateUrlStringForGET(final ActivityKind activityKind, uriBuilder.path(urlObject.getPath()); uriBuilder.appendPath(activityPackagePath); - for (final Map.Entry entry : activityPackageParameters.entrySet()) { - uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue()); - } + logger.debug("Making request to url: %s", uriBuilder.toString()); - if (sendingParameters != null) { - for (final Map.Entry entry: sendingParameters.entrySet()) { + if (signedParameters != null && !signedParameters.isEmpty()) { + for (final Map.Entry entry : signedParameters.entrySet()) { uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue()); } - } + } else { + if (activityPackageParameters != null) { + for (final Map.Entry entry : activityPackageParameters.entrySet()) { + uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue()); + } + } - logger.debug("Making request to url: %s", uriBuilder.toString()); + if (sendingParameters != null) { + for (final Map.Entry entry : sendingParameters.entrySet()) { + uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue()); + } + } + } return uriBuilder.build().toString(); } private String generateUrlStringForPOST(final ActivityKind activityKind, - final String activityPackagePath) + final String activityPackagePath, + final Map signedParameters) { - String targetUrl = - urlStrategy.targetUrlByActivityKind(activityKind); + String targetUrl = extractTargetUrl(signedParameters, activityKind, urlStrategy); // extra path, if present, has the format '/X/Y' String urlWithPath = @@ -357,7 +414,8 @@ private DataOutputStream configConnectionForGET(final HttpsURLConnection connect private DataOutputStream configConnectionForPOST(final HttpsURLConnection connection, final Map activityPackageParameters, - final Map sendingParameters) + final Map sendingParameters, + final Map signedParameters) throws ProtocolException, UnsupportedEncodingException, IOException @@ -374,9 +432,8 @@ private DataOutputStream configConnectionForPOST(final HttpsURLConnection connec // build POST body final String postBodyString = generatePOSTBodyString( activityPackageParameters, - sendingParameters); - - logger.debug("Post body: %s", postBodyString); + sendingParameters, + signedParameters); if (postBodyString == null) { return null; @@ -391,17 +448,23 @@ private DataOutputStream configConnectionForPOST(final HttpsURLConnection connec } private String generatePOSTBodyString(final Map parameters, - final Map sendingParameters) + final Map sendingParameters, + final Map signedParameters) throws UnsupportedEncodingException { - if (parameters.isEmpty()) { - return null; - } - final StringBuilder postStringBuilder = new StringBuilder(); - injectParametersToPOSTStringBuilder(parameters, postStringBuilder); - injectParametersToPOSTStringBuilder(sendingParameters, postStringBuilder); + if (signedParameters!= null && !signedParameters.isEmpty()) { + injectParametersToPOSTStringBuilder(signedParameters, postStringBuilder); + } else { + if (parameters != null && !parameters.isEmpty()){ + injectParametersToPOSTStringBuilder(parameters, postStringBuilder); + } + + if (sendingParameters != null && !sendingParameters.isEmpty()) { + injectParametersToPOSTStringBuilder(sendingParameters, postStringBuilder); + } + } // delete last added & if (postStringBuilder.length() > 0 @@ -486,6 +549,10 @@ Integer readConnectionResponse(final HttpsURLConnection connection, parseResponse(responseData, responseString); + if (responseData.controlParams != null) { + SharedPreferencesManager.getDefaultInstance(context).saveControlParams(responseData.controlParams); + } + final String responseMessage = responseData.message; if (responseMessage == null) { return responseCode; @@ -511,6 +578,7 @@ private void parseResponse(final ResponseData responseData, final String respons // convert string response to JSON object try { jsonResponse = new JSONObject(responseString); + } catch (final JSONException jsonException) { String errorMessage = errorMessage(jsonException, "Failed to parse JSON response", @@ -540,222 +608,26 @@ private void parseResponse(final ResponseData responseData, final String respons responseData.continueIn = UtilNetworking.extractJsonLong(jsonResponse, "continue_in"); JSONObject attributionJson = jsonResponse.optJSONObject("attribution"); - responseData.attribution = AdjustAttribution.fromJson( + responseData.attribution = Util.attributionFromJson( attributionJson, - responseData.adid, Util.getSdkPrefixPlatform(clientSdk)); responseData.resolvedDeeplink = UtilNetworking.extractJsonString(jsonResponse,"resolved_click_url"); + responseData.controlParams = jsonResponse.optJSONObject("control_params"); } - private String buildAndExtractAuthorizationHeader(final Map parameters, - final ActivityKind activityKind) { - String activityKindString = activityKind.toString(); - - String adjSigningId = extractAdjSigningId(parameters); - String secretId = extractSecretId(parameters); - String headersId = extractHeadersId(parameters); - String signature = extractSignature(parameters); - String algorithm = extractAlgorithm(parameters); - String nativeVersion = extractNativeVersion(parameters); - - String authorizationHeader = buildAuthorizationHeaderV2WithAdjSigningId(signature, adjSigningId, - headersId, algorithm, nativeVersion); - if (authorizationHeader != null) { - return authorizationHeader; - } - - authorizationHeader = buildAuthorizationHeaderV2WithSecretId(signature, secretId, headersId, - algorithm, nativeVersion); - if (authorizationHeader != null) { - return authorizationHeader; - } - - String appSecret = extractAppSecret(parameters); - return buildAuthorizationHeaderV1(parameters, appSecret, secretId, activityKindString); - } - - private String buildAuthorizationHeaderV1(final Map parameters, - final String appSecret, - final String secretId, - final String activityKindString) - { - // check if the secret exists and it's not empty - if (appSecret == null || appSecret.length() == 0) { - return null; - } - String appSecretName = "app_secret"; - - Map signatureDetails = getSignature(parameters, activityKindString, appSecret); - - String algorithm = "sha256"; - String signature = Util.sha256(signatureDetails.get("clear_signature")); - String fields = signatureDetails.get("fields"); - - String secretIdHeader = Util.formatString("secret_id=\"%s\"", secretId); - String signatureHeader = Util.formatString("signature=\"%s\"", signature); - String algorithmHeader = Util.formatString("algorithm=\"%s\"", algorithm); - String fieldsHeader = Util.formatString("headers=\"%s\"", fields); - - String authorizationHeader = Util.formatString("Signature %s,%s,%s,%s", - secretIdHeader, signatureHeader, algorithmHeader, fieldsHeader); - logger.verbose("authorizationHeader: %s", authorizationHeader); - - return authorizationHeader; - } - - private String buildAuthorizationHeaderV2WithAdjSigningId(final String signature, - final String adjSigningId, - final String headersId, - final String algorithm, - final String nativeVersion) - { - if (adjSigningId == null || signature == null || headersId == null) { - return null; - } - - String signatureHeader = Util.formatString("signature=\"%s\"", signature); - String adjSigningIdHeader = Util.formatString("adj_signing_id=\"%s\"", adjSigningId); - String idHeader = Util.formatString("headers_id=\"%s\"", headersId); - String algorithmHeader = Util.formatString("algorithm=\"%s\"", algorithm != null ? algorithm : "adj1"); - String nativeVersionHeader = Util.formatString("native_version=\"%s\"", nativeVersion != null ? nativeVersion : ""); - - String authorizationHeader = Util.formatString("Signature %s,%s,%s,%s,%s", - signatureHeader, adjSigningIdHeader, algorithmHeader, idHeader, nativeVersionHeader); - - logger.verbose("authorizationHeader: %s", authorizationHeader); - - return authorizationHeader; + private static String extractAuthorizationHeader(final Map parameters) { + return parameters.remove("authorization"); } - private String buildAuthorizationHeaderV2WithSecretId(final String signature, - final String secretId, - final String headersId, - final String algorithm, - final String nativeVersion) - { - if (secretId == null || signature == null || headersId == null) { - return null; + private static String extractTargetUrl(final Map parameters, + final ActivityKind activityKind, + final UrlStrategy urlStrategy) { + String targetUrl = parameters.remove("endpoint"); + if (targetUrl != null) { + return targetUrl; } - String signatureHeader = Util.formatString("signature=\"%s\"", signature); - String secretIdHeader = Util.formatString("secret_id=\"%s\"", secretId); - String idHeader = Util.formatString("headers_id=\"%s\"", headersId); - String algorithmHeader = Util.formatString("algorithm=\"%s\"", algorithm != null ? algorithm : "adj1"); - String nativeVersionHeader = Util.formatString("native_version=\"%s\"", nativeVersion != null ? nativeVersion : ""); - - String authorizationHeader = Util.formatString("Signature %s,%s,%s,%s,%s", - signatureHeader, secretIdHeader, algorithmHeader, idHeader, nativeVersionHeader); - - logger.verbose("authorizationHeader: %s", authorizationHeader); - - return authorizationHeader; + return urlStrategy.targetUrlByActivityKind(activityKind); } - - private Map getSignature(final Map parameters, - final String activityKindString, - final String appSecret) - { - String activityKindName = "activity_kind"; - String activityKindValue = activityKindString; - - String createdAtName = "created_at"; - String createdAt = parameters.get(createdAtName); - - String deviceIdentifierName = getValidIdentifier(parameters); - String deviceIdentifier = parameters.get(deviceIdentifierName); - - String sourceName = "source"; - String sourceValue = parameters.get(sourceName); - - String payloadName = "payload"; - String payloadValue = parameters.get(payloadName); - - Map signatureParams = new HashMap(); - - signatureParams.put("app_secret", appSecret); - signatureParams.put(createdAtName, createdAt); - signatureParams.put(activityKindName, activityKindValue); - signatureParams.put(deviceIdentifierName, deviceIdentifier); - - if (sourceValue != null) { - signatureParams.put(sourceName, sourceValue); - } - - if (payloadValue != null) { - signatureParams.put(payloadName, payloadValue); - } - - String fields = ""; - String clearSignature = ""; - - for (Map.Entry entry : signatureParams.entrySet()) { - if (entry.getValue() != null) { - fields += entry.getKey() + " "; - clearSignature += entry.getValue(); - } - } - - // Remove last empty space. - fields = fields.substring(0, fields.length() - 1); - - HashMap signature = new HashMap(); - - signature.put("clear_signature", clearSignature); - signature.put("fields", fields); - - return signature; - } - - private String getValidIdentifier(final Map parameters) { - String googleAdIdName = "gps_adid"; - String fireAdIdName = "fire_adid"; - String androidIdName = "android_id"; - String androidUUIDName= "android_uuid"; - - if (parameters.get(googleAdIdName) != null) { - return googleAdIdName; - } - if (parameters.get(fireAdIdName) != null) { - return fireAdIdName; - } - if (parameters.get(androidIdName) != null) { - return androidIdName; - } - if (parameters.get(androidUUIDName) != null) { - return androidUUIDName; - } - - return null; - } - - private static String extractAppSecret(final Map parameters) { - return parameters.remove("app_secret"); - } - - private static String extractSecretId(final Map parameters) { - return parameters.remove("secret_id"); - } - - private static String extractSignature(final Map parameters) { - return parameters.remove("signature"); - } - - private static String extractAlgorithm(final Map parameters) { - return parameters.remove("algorithm"); - } - - private static String extractNativeVersion(final Map parameters) { - return parameters.remove("native_version"); - } - - private static String extractHeadersId(final Map parameters) { - return parameters.remove("headers_id"); - } - - private static String extractAdjSigningId(final Map parameters) { - return parameters.remove("adj_signing_id"); - } - - } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UrlStrategy.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UrlStrategy.java index ae434da78..8a7652e0b 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UrlStrategy.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UrlStrategy.java @@ -1,50 +1,30 @@ package com.adjust.sdk.network; +import static com.adjust.sdk.Constants.BASE_URL; +import static com.adjust.sdk.Constants.BASE_URL_FORMAT; +import static com.adjust.sdk.Constants.BASE_URL_NO_SUB_DOMAIN_FORMAT; +import static com.adjust.sdk.Constants.GDPR_URL; +import static com.adjust.sdk.Constants.GDPR_URL_FORMAT; +import static com.adjust.sdk.Constants.PURCHASE_VERIFICATION_URL; +import static com.adjust.sdk.Constants.PURCHASE_VERIFICATION_URL_FORMAT; +import static com.adjust.sdk.Constants.SUBSCRIPTION_URL; +import static com.adjust.sdk.Constants.SUBSCRIPTION_URL_FORMAT; + import com.adjust.sdk.ActivityKind; -import com.adjust.sdk.Constants; +import com.adjust.sdk.AdjustFactory; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; -import static com.adjust.sdk.AdjustConfig.DATA_RESIDENCY_TR; -import static com.adjust.sdk.AdjustConfig.DATA_RESIDENCY_US; -import static com.adjust.sdk.AdjustConfig.URL_STRATEGY_CHINA; -import static com.adjust.sdk.AdjustConfig.URL_STRATEGY_CN; -import static com.adjust.sdk.AdjustConfig.URL_STRATEGY_CN_ONLY; -import static com.adjust.sdk.AdjustConfig.URL_STRATEGY_INDIA; -import static com.adjust.sdk.AdjustConfig.DATA_RESIDENCY_EU; - public class UrlStrategy { - private static final String BASE_URL_INDIA = "https://app.adjust.net.in"; - private static final String GDPR_URL_INDIA = "https://gdpr.adjust.net.in"; - private static final String SUBSCRIPTION_URL_INDIA = "https://subscription.adjust.net.in"; - private static final String PURCHASE_VERIFICATION_URL_INDIA = "https://ssrv.adjust.net.in"; - - private static final String BASE_URL_CHINA = "https://app.adjust.world"; - private static final String GDPR_URL_CHINA = "https://gdpr.adjust.world"; - private static final String SUBSCRIPTION_URL_CHINA = "https://subscription.adjust.world"; - private static final String PURCHASE_VERIFICATION_URL_CHINA = "https://ssrv.adjust.world"; - - private static final String BASE_URL_CN = "https://app.adjust.cn"; - private static final String GDPR_URL_CN = "https://gdpr.adjust.cn"; - private static final String SUBSCRIPTION_URL_CN = "https://subscription.adjust.cn"; - private static final String PURCHASE_VERIFICATION_URL_CN = "https://ssrv.adjust.cn"; - - private static final String BASE_URL_EU = "https://app.eu.adjust.com"; - private static final String GDPR_URL_EU = "https://gdpr.eu.adjust.com"; - private static final String SUBSCRIPTION_URL_EU = "https://subscription.eu.adjust.com"; - private static final String PURCHASE_VERIFICATION_URL_EU = "https://ssrv.eu.adjust.com"; - - private static final String BASE_URL_TR = "https://app.tr.adjust.com"; - private static final String GDPR_URL_TR = "https://gdpr.tr.adjust.com"; - private static final String SUBSCRIPTION_URL_TR = "https://subscription.tr.adjust.com"; - private static final String PURCHASE_VERIFICATION_URL_TR = "https://ssrv.tr.adjust.com"; - - private static final String BASE_URL_US = "https://app.us.adjust.com"; - private static final String GDPR_URL_US = "https://gdpr.us.adjust.com"; - private static final String SUBSCRIPTION_URL_US = "https://subscription.us.adjust.com"; - private static final String PURCHASE_VERIFICATION_URL_US = "https://ssrv.us.adjust.com"; + private static final String BASE_URL_IO = "https://app.adjust.io"; + private static final String GDPR_URL_IO = "https://gdpr.adjust.io"; + private static final String SUBSCRIPTION_URL_IO = "https://subscription.adjust.io"; + private static final String PURCHASE_VERIFICATION_URL_IO = "https://ssrv.adjust.io"; + + private final List urlStrategyDomains; + private final boolean useSubdomains; private final String baseUrlOverwrite; private final String gdprUrlOverwrite; @@ -64,17 +44,21 @@ public UrlStrategy(final String baseUrlOverwrite, final String gdprUrlOverwrite, final String subscriptionUrlOverwrite, final String purchaseVerificationUrlOverwrite, - final String adjustUrlStrategy) + final List urlStrategyDomains, + final boolean useSubdomains) { + this.urlStrategyDomains = urlStrategyDomains; + this.useSubdomains = useSubdomains; + this.baseUrlOverwrite = baseUrlOverwrite; this.gdprUrlOverwrite = gdprUrlOverwrite; this.subscriptionUrlOverwrite = subscriptionUrlOverwrite; this.purchaseVerificationUrlOverwrite = purchaseVerificationUrlOverwrite; - baseUrlChoicesList = baseUrlChoices(adjustUrlStrategy); - gdprUrlChoicesList = gdprUrlChoices(adjustUrlStrategy); - subscriptionUrlChoicesList = subscriptionUrlChoices(adjustUrlStrategy); - purchaseVerificationUrlChoicesList = purchaseVerificationUrlChoices(adjustUrlStrategy); + baseUrlChoicesList = baseUrlChoices(); + gdprUrlChoicesList = gdprUrlChoices(); + subscriptionUrlChoicesList = subscriptionUrlChoices(); + purchaseVerificationUrlChoicesList = purchaseVerificationUrlChoices(); wasLastAttemptSuccess = false; choiceIndex = 0; @@ -95,8 +79,10 @@ public boolean shouldRetryAfterFailure(final ActivityKind activityKind) { // since it will use the same overwritten url // might as well stop retrying in the same sending "session" // and let the backoff strategy pick it up - if (wasLastAttemptWithOverwrittenUrl) { - return false; + if (AdjustFactory.isAllowUrlStrategyFallback()) { + if (wasLastAttemptWithOverwrittenUrl) { + return false; + } } int choiceListSize; @@ -154,84 +140,71 @@ public String targetUrlByActivityKind(final ActivityKind activityKind) { } } - private static List baseUrlChoices(final String urlStrategy) { - if (URL_STRATEGY_INDIA.equals(urlStrategy)) { - return Arrays.asList(BASE_URL_INDIA, Constants.BASE_URL); - } else if (URL_STRATEGY_CHINA.equals(urlStrategy)) { - return Arrays.asList(BASE_URL_CHINA, Constants.BASE_URL); - } else if (URL_STRATEGY_CN.equals(urlStrategy)) { - return Arrays.asList(BASE_URL_CN, Constants.BASE_URL); - } else if (URL_STRATEGY_CN_ONLY.equals(urlStrategy)) { - return Arrays.asList(BASE_URL_CN); - } else if (DATA_RESIDENCY_EU.equals(urlStrategy)) { - return Collections.singletonList(BASE_URL_EU); - } else if (DATA_RESIDENCY_TR.equals(urlStrategy)) { - return Collections.singletonList(BASE_URL_TR); - } else if (DATA_RESIDENCY_US.equals(urlStrategy)) { - return Collections.singletonList(BASE_URL_US); - } else { - return Arrays.asList(Constants.BASE_URL, BASE_URL_INDIA, BASE_URL_CHINA); + private List baseUrlChoices() { + + if (urlStrategyDomains == null || urlStrategyDomains.isEmpty()) { + return Arrays.asList(BASE_URL, BASE_URL_IO); + } + if (useSubdomains) { + List baseUrls = new ArrayList<>(); + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(BASE_URL_FORMAT, url)); + } + return baseUrls; + }else { + List baseUrls = new ArrayList<>(); + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(BASE_URL_NO_SUB_DOMAIN_FORMAT, url)); + } + return baseUrls; } } - private static List gdprUrlChoices(final String urlStrategy) { - if (URL_STRATEGY_INDIA.equals(urlStrategy)) { - return Arrays.asList(GDPR_URL_INDIA, Constants.GDPR_URL); - } else if (URL_STRATEGY_CHINA.equals(urlStrategy)) { - return Arrays.asList(GDPR_URL_CHINA, Constants.GDPR_URL); - } else if (URL_STRATEGY_CN.equals(urlStrategy)) { - return Arrays.asList(GDPR_URL_CN, Constants.GDPR_URL); - } else if (URL_STRATEGY_CN_ONLY.equals(urlStrategy)) { - return Arrays.asList(GDPR_URL_CN); - } else if (DATA_RESIDENCY_EU.equals(urlStrategy)) { - return Collections.singletonList(GDPR_URL_EU); - } else if (DATA_RESIDENCY_TR.equals(urlStrategy)) { - return Collections.singletonList(GDPR_URL_TR); - } else if (DATA_RESIDENCY_US.equals(urlStrategy)) { - return Collections.singletonList(GDPR_URL_US); - } else { - return Arrays.asList(Constants.GDPR_URL, GDPR_URL_INDIA, GDPR_URL_CHINA); + private List gdprUrlChoices() { + if (urlStrategyDomains == null || urlStrategyDomains.isEmpty()) { + return Arrays.asList(GDPR_URL, GDPR_URL_IO); } + List baseUrls = new ArrayList<>(); + if (useSubdomains) { + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(GDPR_URL_FORMAT, url)); + } + }else { + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(BASE_URL_NO_SUB_DOMAIN_FORMAT, url)); + } + } + return baseUrls; } - private static List subscriptionUrlChoices(final String urlStrategy) { - if (URL_STRATEGY_INDIA.equals(urlStrategy)) { - return Arrays.asList(SUBSCRIPTION_URL_INDIA, Constants.SUBSCRIPTION_URL); - } else if (URL_STRATEGY_CHINA.equals(urlStrategy)) { - return Arrays.asList(SUBSCRIPTION_URL_CHINA, Constants.SUBSCRIPTION_URL); - } else if (URL_STRATEGY_CN.equals(urlStrategy)) { - return Arrays.asList(SUBSCRIPTION_URL_CN, Constants.SUBSCRIPTION_URL); - } else if (URL_STRATEGY_CN_ONLY.equals(urlStrategy)) { - return Arrays.asList(SUBSCRIPTION_URL_CN); - } else if (DATA_RESIDENCY_EU.equals(urlStrategy)) { - return Collections.singletonList(SUBSCRIPTION_URL_EU); - } else if (DATA_RESIDENCY_TR.equals(urlStrategy)) { - return Collections.singletonList(SUBSCRIPTION_URL_TR); - } else if (DATA_RESIDENCY_US.equals(urlStrategy)) { - return Collections.singletonList(SUBSCRIPTION_URL_US); - } else { - return Arrays.asList(Constants.SUBSCRIPTION_URL, - SUBSCRIPTION_URL_INDIA, - SUBSCRIPTION_URL_CHINA); + private List subscriptionUrlChoices() { + if (urlStrategyDomains == null || urlStrategyDomains.isEmpty()) { + return Arrays.asList(SUBSCRIPTION_URL, SUBSCRIPTION_URL_IO); } + List baseUrls = new ArrayList<>(); + if (useSubdomains) { + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(SUBSCRIPTION_URL_FORMAT, url)); + } + }else { + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(BASE_URL_NO_SUB_DOMAIN_FORMAT, url)); + } + } + return baseUrls; } - private static List purchaseVerificationUrlChoices(final String urlStrategy) { - if (URL_STRATEGY_INDIA.equals(urlStrategy)) { - return Arrays.asList(PURCHASE_VERIFICATION_URL_INDIA, Constants.PURCHASE_VERIFICATION_URL); - } else if (URL_STRATEGY_CHINA.equals(urlStrategy)) { - return Arrays.asList(PURCHASE_VERIFICATION_URL_CHINA, Constants.PURCHASE_VERIFICATION_URL); - } else if (URL_STRATEGY_CN.equals(urlStrategy)) { - return Arrays.asList(PURCHASE_VERIFICATION_URL_CN, Constants.PURCHASE_VERIFICATION_URL); - } else if (URL_STRATEGY_CN_ONLY.equals(urlStrategy)) { - return Arrays.asList(PURCHASE_VERIFICATION_URL_CN); - } else if (DATA_RESIDENCY_EU.equals(urlStrategy)) { - return Collections.singletonList(PURCHASE_VERIFICATION_URL_EU); - } else if (DATA_RESIDENCY_TR.equals(urlStrategy)) { - return Collections.singletonList(PURCHASE_VERIFICATION_URL_TR); - } else if (DATA_RESIDENCY_US.equals(urlStrategy)) { - return Collections.singletonList(PURCHASE_VERIFICATION_URL_US); - } else { - return Arrays.asList(Constants.PURCHASE_VERIFICATION_URL, - PURCHASE_VERIFICATION_URL_INDIA, - PURCHASE_VERIFICATION_URL_CHINA); + private List purchaseVerificationUrlChoices() { + if (urlStrategyDomains == null || urlStrategyDomains.isEmpty()) { + return Arrays.asList(PURCHASE_VERIFICATION_URL, PURCHASE_VERIFICATION_URL_IO); + } + List baseUrls = new ArrayList<>(); + if (useSubdomains){ + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(PURCHASE_VERIFICATION_URL_FORMAT, url)); + } + }else { + for (String url : urlStrategyDomains) { + baseUrls.add(String.format(BASE_URL_NO_SUB_DOMAIN_FORMAT, url)); + } } + return baseUrls; } } diff --git a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UtilNetworking.java b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UtilNetworking.java index d0d36a2cf..1114c4ae2 100644 --- a/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UtilNetworking.java +++ b/Adjust/sdk-core/src/main/java/com/adjust/sdk/network/UtilNetworking.java @@ -16,34 +16,27 @@ */ public class UtilNetworking { - private static String userAgent; private static ILogger getLogger() { return AdjustFactory.getLogger(); } - public static void setUserAgent(String userAgent) { - UtilNetworking.userAgent = userAgent; - } - public interface IConnectionOptions { - void applyConnectionOptions(HttpsURLConnection connection, String clientSdk); + void applyConnectionOptions(HttpsURLConnection connection, String clientSdk, int connectionTimeout); } public static IConnectionOptions createDefaultConnectionOptions() { return new IConnectionOptions() { @Override public void applyConnectionOptions(final HttpsURLConnection connection, - final String clientSdk) + final String clientSdk, + final int timeout) { connection.setRequestProperty("Client-SDK", clientSdk); - connection.setConnectTimeout(Constants.ONE_MINUTE); - connection.setReadTimeout(Constants.ONE_MINUTE); - - if (userAgent != null) { - connection.setRequestProperty("User-Agent", userAgent); - } - + // in case of beta release, specify beta version here + // connection.setRequestProperty("Beta-Version", "2"); + connection.setConnectTimeout(timeout); + connection.setReadTimeout(timeout); } }; } diff --git a/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamPersistedTest.java b/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamPersistedTest.java new file mode 100644 index 000000000..0a20c27f1 --- /dev/null +++ b/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamPersistedTest.java @@ -0,0 +1,366 @@ +package com.adjust.sdk; + +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +public class ObjectInputFilterStreamPersistedTest { + @Test + public void roundTrip_activityState() throws Exception { + ActivityState original = new ActivityState(); + original.uuid = "uuid-1"; + original.enabled = false; + original.isGdprForgotten = true; + original.askingAttribution = true; + original.eventCount = 12; + original.sessionCount = 34; + original.subsessionCount = 56; + original.sessionLength = 1001L; + original.timeSpent = 1002L; + original.lastActivity = 1003L; + original.lastInterval = 1004L; + original.orderIds = new LinkedList<>(); + original.orderIds.add("order-1"); + original.orderIds.add("order-2"); + original.pushToken = "push-token"; + original.adid = "adid-1"; + original.clickTime = 2001L; + original.installBegin = 2002L; + original.installReferrer = "install-ref"; + original.googlePlayInstant = Boolean.TRUE; + original.clickTimeServer = 2003L; + original.installBeginServer = 2004L; + original.installVersion = "1.2.3"; + original.clickTimeHuawei = 3001L; + original.installBeginHuawei = 3002L; + original.installReferrerHuawei = "hua-ref"; + original.installReferrerHuaweiAppGallery = "hua-app-gallery-ref"; + original.isThirdPartySharingDisabledForCoppa = true; + original.clickTimeXiaomi = 4001L; + original.installBeginXiaomi = 4002L; + original.installReferrerXiaomi = "xiaomi-ref"; + original.clickTimeServerXiaomi = 4003L; + original.installBeginServerXiaomi = 4004L; + original.installVersionXiaomi = "x-1.0"; + original.clickTimeSamsung = 5001L; + original.installBeginSamsung = 5002L; + original.installReferrerSamsung = "samsung-ref"; + original.clickTimeVivo = 6001L; + original.installBeginVivo = 6002L; + original.installReferrerVivo = "vivo-ref"; + original.installVersionVivo = "v-1.0"; + original.installReferrerMeta = "meta-ref"; + original.clickTimeMeta = 7001L; + original.isClickMeta = Boolean.FALSE; + + ActivityState restored = (ActivityState) deserialize(serialize(original)); + + assertEquals(original.uuid, restored.uuid); + assertEquals(original.enabled, restored.enabled); + assertEquals(original.isGdprForgotten, restored.isGdprForgotten); + assertEquals(original.askingAttribution, restored.askingAttribution); + assertEquals(original.eventCount, restored.eventCount); + assertEquals(original.sessionCount, restored.sessionCount); + assertEquals(original.subsessionCount, restored.subsessionCount); + assertEquals(original.sessionLength, restored.sessionLength); + assertEquals(original.timeSpent, restored.timeSpent); + assertEquals(original.lastActivity, restored.lastActivity); + assertEquals(original.lastInterval, restored.lastInterval); + assertEquals(original.orderIds, restored.orderIds); + assertEquals(original.pushToken, restored.pushToken); + assertEquals(original.adid, restored.adid); + assertEquals(original.clickTime, restored.clickTime); + assertEquals(original.installBegin, restored.installBegin); + assertEquals(original.installReferrer, restored.installReferrer); + assertEquals(original.googlePlayInstant, restored.googlePlayInstant); + assertEquals(original.clickTimeServer, restored.clickTimeServer); + assertEquals(original.installBeginServer, restored.installBeginServer); + assertEquals(original.installVersion, restored.installVersion); + assertEquals(original.clickTimeHuawei, restored.clickTimeHuawei); + assertEquals(original.installBeginHuawei, restored.installBeginHuawei); + assertEquals(original.installReferrerHuawei, restored.installReferrerHuawei); + assertEquals(original.installReferrerHuaweiAppGallery, restored.installReferrerHuaweiAppGallery); + assertEquals(original.isThirdPartySharingDisabledForCoppa, restored.isThirdPartySharingDisabledForCoppa); + assertEquals(original.clickTimeXiaomi, restored.clickTimeXiaomi); + assertEquals(original.installBeginXiaomi, restored.installBeginXiaomi); + assertEquals(original.installReferrerXiaomi, restored.installReferrerXiaomi); + assertEquals(original.clickTimeServerXiaomi, restored.clickTimeServerXiaomi); + assertEquals(original.installBeginServerXiaomi, restored.installBeginServerXiaomi); + assertEquals(original.installVersionXiaomi, restored.installVersionXiaomi); + assertEquals(original.clickTimeSamsung, restored.clickTimeSamsung); + assertEquals(original.installBeginSamsung, restored.installBeginSamsung); + assertEquals(original.installReferrerSamsung, restored.installReferrerSamsung); + assertEquals(original.clickTimeVivo, restored.clickTimeVivo); + assertEquals(original.installBeginVivo, restored.installBeginVivo); + assertEquals(original.installReferrerVivo, restored.installReferrerVivo); + assertEquals(original.installVersionVivo, restored.installVersionVivo); + assertEquals(original.installReferrerMeta, restored.installReferrerMeta); + assertEquals(original.clickTimeMeta, restored.clickTimeMeta); + assertEquals(original.isClickMeta, restored.isClickMeta); + } + + @Test + public void roundTrip_adjustAttribution() throws Exception { + AdjustAttribution original = new AdjustAttribution(); + original.trackerToken = "token"; + original.trackerName = "name"; + original.network = "network"; + original.campaign = "campaign"; + original.adgroup = "adgroup"; + original.creative = "creative"; + original.clickLabel = "label"; + original.costType = "cpi"; + original.costAmount = 123.45d; + original.costCurrency = "USD"; + original.fbInstallReferrer = "fb-ref"; + original.jsonResponse = "{\"a\":1}"; + + AdjustAttribution restored = (AdjustAttribution) deserialize(serialize(original)); + + assertEquals(original.trackerToken, restored.trackerToken); + assertEquals(original.trackerName, restored.trackerName); + assertEquals(original.network, restored.network); + assertEquals(original.campaign, restored.campaign); + assertEquals(original.adgroup, restored.adgroup); + assertEquals(original.creative, restored.creative); + assertEquals(original.clickLabel, restored.clickLabel); + assertEquals(original.costType, restored.costType); + assertEquals(original.costAmount, restored.costAmount); + assertEquals(original.costCurrency, restored.costCurrency); + assertEquals(original.fbInstallReferrer, restored.fbInstallReferrer); + assertEquals(original.jsonResponse, restored.jsonResponse); + } + + @Test + public void roundTrip_eventMetadata() throws Exception { + EventMetadata original = new EventMetadata(); + original.incrementSequenceForEvent("evt-a"); + original.incrementSequenceForEvent("evt-b"); + original.incrementSequenceForEvent("evt-b"); + + EventMetadata restored = (EventMetadata) deserialize(serialize(original)); + + assertEquals(original, restored); + } + + @Test + public void roundTrip_activityPackage() throws Exception { + ActivityPackage original = new ActivityPackage(ActivityKind.EVENT); + original.setPath("/event"); + original.setClientSdk("android5.5.1"); + Map parameters = new LinkedHashMap<>(); + parameters.put("k1", "v1"); + parameters.put("k2", "v2"); + original.setParameters(parameters); + original.setSuffix("_suffix"); + Map callbackParameters = new LinkedHashMap<>(); + callbackParameters.put("cb1", "cv1"); + original.setCallbackParameters(callbackParameters); + Map partnerParameters = new LinkedHashMap<>(); + partnerParameters.put("pp1", "pv1"); + original.setPartnerParameters(partnerParameters); + original.addError(400); + original.addError(401); + original.setWaitBeforeSendTimeSeconds(3.5d); + + ActivityPackage restored = (ActivityPackage) deserialize(serialize(original)); + + assertEquals(original.getPath(), restored.getPath()); + assertEquals(original.getClientSdk(), restored.getClientSdk()); + assertEquals(original.getParameters(), restored.getParameters()); + assertEquals(original.getActivityKind(), restored.getActivityKind()); + assertEquals(original.getSuffix(), restored.getSuffix()); + assertEquals(original.getCallbackParameters(), restored.getCallbackParameters()); + assertEquals(original.getPartnerParameters(), restored.getPartnerParameters()); + // current ActivityPackage.readObject reads "retryCount" and drops legacy "errorCount" + assertEquals(original.getRetryCount(), restored.getRetryCount()); + assertEquals(original.getFirstErrorCode(), restored.getFirstErrorCode()); + assertEquals(original.getLastErrorCode(), restored.getLastErrorCode()); + assertEquals(original.getWaitBeforeSendTimeSeconds(), restored.getWaitBeforeSendTimeSeconds(), 0.0d); + } + + @Test + public void roundTrip_packageQueue() throws Exception { + ActivityPackage first = new ActivityPackage(ActivityKind.SESSION); + first.setPath("/session"); + first.setClientSdk("android5.5.1"); + Map firstParams = new LinkedHashMap<>(); + firstParams.put("k1", "v1"); + firstParams.put("k2", "v2"); + first.setParameters(firstParams); + first.setSuffix("_first"); + Map firstCallbackParams = new LinkedHashMap<>(); + firstCallbackParams.put("fcb1", "fcv1"); + first.setCallbackParameters(firstCallbackParams); + Map firstPartnerParams = new LinkedHashMap<>(); + firstPartnerParams.put("fpp1", "fpv1"); + first.setPartnerParameters(firstPartnerParams); + first.addError(400); + first.addError(401); + first.setWaitBeforeSendTimeSeconds(1.5d); + + ActivityPackage second = new ActivityPackage(ActivityKind.EVENT); + second.setPath("/event"); + second.setClientSdk("android5.5.1"); + Map secondParams = new LinkedHashMap<>(); + secondParams.put("k2", "v2"); + secondParams.put("k3", "v3"); + second.setParameters(secondParams); + second.setSuffix("_second"); + Map secondCallbackParams = new LinkedHashMap<>(); + secondCallbackParams.put("scb1", "scv1"); + second.setCallbackParameters(secondCallbackParams); + Map secondPartnerParams = new LinkedHashMap<>(); + secondPartnerParams.put("spp1", "spv1"); + second.setPartnerParameters(secondPartnerParams); + second.addError(402); + second.addError(403); + second.setWaitBeforeSendTimeSeconds(2.5d); + + List original = new ArrayList<>(); + original.add(first); + original.add(second); + + @SuppressWarnings("unchecked") + List restored = (List) deserialize(serialize(original)); + + assertEquals(2, restored.size()); + assertEquals(first.getPath(), restored.get(0).getPath()); + assertEquals(first.getClientSdk(), restored.get(0).getClientSdk()); + assertEquals(first.getParameters(), restored.get(0).getParameters()); + assertEquals(first.getActivityKind(), restored.get(0).getActivityKind()); + assertEquals(first.getSuffix(), restored.get(0).getSuffix()); + assertEquals(first.getCallbackParameters(), restored.get(0).getCallbackParameters()); + assertEquals(first.getPartnerParameters(), restored.get(0).getPartnerParameters()); + assertEquals(first.getRetryCount(), restored.get(0).getRetryCount()); + assertEquals(first.getFirstErrorCode(), restored.get(0).getFirstErrorCode()); + assertEquals(first.getLastErrorCode(), restored.get(0).getLastErrorCode()); + assertEquals(first.getWaitBeforeSendTimeSeconds(), restored.get(0).getWaitBeforeSendTimeSeconds(), 0.0d); + + assertEquals(second.getPath(), restored.get(1).getPath()); + assertEquals(second.getClientSdk(), restored.get(1).getClientSdk()); + assertEquals(second.getParameters(), restored.get(1).getParameters()); + assertEquals(second.getActivityKind(), restored.get(1).getActivityKind()); + assertEquals(second.getSuffix(), restored.get(1).getSuffix()); + assertEquals(second.getCallbackParameters(), restored.get(1).getCallbackParameters()); + assertEquals(second.getPartnerParameters(), restored.get(1).getPartnerParameters()); + assertEquals(second.getRetryCount(), restored.get(1).getRetryCount()); + assertEquals(second.getFirstErrorCode(), restored.get(1).getFirstErrorCode()); + assertEquals(second.getLastErrorCode(), restored.get(1).getLastErrorCode()); + assertEquals(second.getWaitBeforeSendTimeSeconds(), restored.get(1).getWaitBeforeSendTimeSeconds(), 0.0d); + } + + @Test + public void roundTrip_globalParametersMap() throws Exception { + Map original = new LinkedHashMap<>(); + original.put("k1", "v1"); + original.put("k2", "v2"); + + @SuppressWarnings("unchecked") + Map restored = (Map) deserialize(serialize(original)); + + assertEquals(original, restored); + } + + @Test + public void blocks_activityState_withBoobytrappedOrderIds() throws Exception { + ActivityState boobytrapped = new ActivityState(); + LinkedList orderIds = new LinkedList<>(); + orderIds.add("safe"); + orderIds.add(new UnfilteredClass()); + @SuppressWarnings("unchecked") + LinkedList raw = (LinkedList) (LinkedList) orderIds; + boobytrapped.orderIds = raw; + + assertThrows(InvalidClassException.class, () -> deserialize(serialize(boobytrapped))); + } + + @Test + public void blocks_eventMetadata_withBoobytrappedEventSequence() throws Exception { + EventMetadata boobytrapped = new EventMetadata(); + Map eventSequence = new HashMap<>(); + eventSequence.put("safe", 1); + eventSequence.put("bad", new UnfilteredClass()); + Field field = EventMetadata.class.getDeclaredField("eventSequence"); + field.setAccessible(true); + field.set(boobytrapped, eventSequence); + + assertThrows(InvalidClassException.class, () -> deserialize(serialize(boobytrapped))); + } + + @Test + public void blocks_activityPackage_withBoobytrappedParameters() throws Exception { + ActivityPackage boobytrapped = new ActivityPackage(ActivityKind.EVENT); + Map parameters = new LinkedHashMap<>(); + parameters.put("safe", "value"); + parameters.put("bad", new UnfilteredClass()); + @SuppressWarnings("unchecked") + Map raw = (Map) (Map) parameters; + boobytrapped.setParameters(raw); + + assertThrows(InvalidClassException.class, () -> deserialize(serialize(boobytrapped))); + } + + @Test + public void blocks_packageQueue_withBoobytrappedElement() throws Exception { + ActivityPackage safePackage = new ActivityPackage(ActivityKind.SESSION); + safePackage.setPath("/safe"); + Map safeParameters = new LinkedHashMap<>(); + safeParameters.put("safe_k", "safe_v"); + safePackage.setParameters(safeParameters); + + ActivityPackage boobytrappedPackage = new ActivityPackage(ActivityKind.EVENT); + boobytrappedPackage.setPath("/boobytrapped"); + Map boobytrappedParameters = new LinkedHashMap<>(); + boobytrappedParameters.put("safe_k", "safe_v"); + boobytrappedParameters.put("bad_k", new UnfilteredClass()); + @SuppressWarnings("unchecked") + Map rawBoobytrappedParameters = + (Map) (Map) boobytrappedParameters; + boobytrappedPackage.setParameters(rawBoobytrappedParameters); + + List boobytrappedQueue = new ArrayList<>(); + boobytrappedQueue.add(safePackage); + boobytrappedQueue.add(boobytrappedPackage); + + assertThrows(InvalidClassException.class, () -> deserialize(serialize(boobytrappedQueue))); + } + + @Test + public void blocks_globalParametersMap_withBoobytrappedValue() throws Exception { + Map boobytrapped = new LinkedHashMap<>(); + boobytrapped.put("safe", "value"); + boobytrapped.put("bad", new UnfilteredClass()); + + assertThrows(InvalidClassException.class, () -> deserialize(serialize(boobytrapped))); + } + + private static Object deserialize(byte[] data) throws Exception { + ByteArrayInputStream input = new ByteArrayInputStream(data); + try (ObjectInputStream objectInputStream = new ObjectInputFilterStream(input)) { + return objectInputStream.readObject(); + } + } + + private static byte[] serialize(Object obj) throws Exception { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(output)) { + objectOutputStream.writeObject(obj); + } + return output.toByteArray(); + } +} diff --git a/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamTest.java b/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamTest.java new file mode 100644 index 000000000..4d2998518 --- /dev/null +++ b/Adjust/sdk-core/src/test/java/com/adjust/sdk/ObjectInputFilterStreamTest.java @@ -0,0 +1,120 @@ +package com.adjust.sdk; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class ObjectInputFilterStreamTest { + + @Test + public void allowedClasses_shouldDeserialize() throws Exception { + String input = "hello"; + + byte[] data = serialize(input); + Object result = deserialize(data); + + assertEquals("hello", result); + } + + @Test + public void disallowedClasses_shouldBeBlocked() throws Exception { + UnfilteredClass.DESERIALIZED = false; + + byte[] data = serialize(new UnfilteredClass()); + + assertThrows(InvalidClassException.class, () -> { + deserialize(data); + }); + + assertFalse(UnfilteredClass.DESERIALIZED); + } + + @Test + public void nestedUnfilteredObject_shouldBeBlocked() throws Exception { + UnfilteredClass.DESERIALIZED = false; + + ArrayList list = new ArrayList<>(); + list.add(new UnfilteredClass()); + + byte[] data = serialize(list); + + assertThrows(InvalidClassException.class, () -> { + deserialize(data); + }); + + assertFalse(UnfilteredClass.DESERIALIZED); + } + + @Test + public void nestedSerializableFieldsMustBeWhitelisted() { + Set missing = new HashSet<>(); + + for (String allowed : ObjectInputFilterStream.ALLOWED_CLASSES) { + try { + Class cls = Class.forName(allowed); + checkSerializableFields(cls, missing); + } catch (ClassNotFoundException e) { + fail("Whitelisted class not found: " + allowed); + } + } + + assertTrue( + "Found serializable types in allowed classes that are missing from whitelist: " + missing, + missing.isEmpty() + ); + } + + private void checkSerializableFields(Class cls, Set missing) { + for (Field field : cls.getDeclaredFields()) { + + int mods = field.getModifiers(); + + // skip static fields + if (Modifier.isStatic(mods)) continue; + + // skip synthetic fields + if (field.isSynthetic()) continue; + + Class type = field.getType(); + + // skip primitives + if (type.isPrimitive()) continue; + + // skip arrays for simplicity (or handle arrays separately) + if (type.isArray()) type = type.getComponentType(); + + // check if Serializable + if (Serializable.class.isAssignableFrom(type)) { + String typeName = type.getName(); + if (!ObjectInputFilterStream.ALLOWED_CLASSES.contains(typeName)) { + missing.add(cls.getName() + "." + field.getName() + " -> " + typeName); + } + } + } + } + + byte[] serialize(Object obj) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(obj); + oos.close(); + return bos.toByteArray(); + } + + Object deserialize(byte[] data) throws Exception { + ByteArrayInputStream bis = new ByteArrayInputStream(data); + ObjectInputStream ois = new ObjectInputFilterStream(bis); + return ois.readObject(); + } +} diff --git a/Adjust/sdk-core/src/test/java/com/adjust/sdk/UnfilteredClass.java b/Adjust/sdk-core/src/test/java/com/adjust/sdk/UnfilteredClass.java new file mode 100644 index 000000000..ac887338e --- /dev/null +++ b/Adjust/sdk-core/src/test/java/com/adjust/sdk/UnfilteredClass.java @@ -0,0 +1,19 @@ +package com.adjust.sdk; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +public class UnfilteredClass implements Serializable { + + public static boolean DESERIALIZED = false; + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException { + + in.defaultReadObject(); + + // If this runs, indicates filter has FAILED with no exception thrown + DESERIALIZED = true; + } +} diff --git a/Adjust/sdk-plugin-criteo/build.gradle b/Adjust/sdk-plugin-criteo/build.gradle deleted file mode 100644 index 96e65fca8..000000000 --- a/Adjust/sdk-plugin-criteo/build.gradle +++ /dev/null @@ -1,216 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' -apply plugin: 'signing' - -repositories { - maven { - url "https://oss.sonatype.org/content/repositories/staging/" - } -} - -android { - compileSdk rootProject.ext.coreCompileSdkVersion - - publishing { - multipleVariants { - allVariants() - withJavadocJar() - } - } - defaultConfig { - minSdkVersion rootProject.ext.coreMinSdkVersion - targetSdkVersion rootProject.ext.coreTargetSdkVersion - } - namespace 'com.adjust.sdk.criteo' -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - - // Add SDK via module. - compileOnly project(':sdk-core') - // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' -} - -// read local properties -File localPropsFile = project.rootProject.file('local.properties') -if (localPropsFile.exists()) { - Properties p = new Properties() - new FileInputStream(localPropsFile).withCloseable { is -> - p.load(is) - } - p.each { name, value -> - ext[name] = value - } -} - -task adjustCriteoAndroidAar(type: Copy) { - dependsOn 'assembleRelease' - - from('build/outputs/aar/') - include 'sdk-plugin-criteo-release.aar' - destinationDir file('build/libs/') - rename 'sdk-plugin-criteo-release.aar', "${project.name}.aar" - -} - -task adjustCriteoAndroidJar(type: Jar) { - dependsOn 'compileReleaseJavaWithJavac' - from('build/intermediates/javac/release/classes/') - archiveFileName = project.provider { "${project.name}.jar" } -} - -task adjustCriteoAndroidSourcesJar(type: Jar) { - setArchiveClassifier('sources') - from android.sourceSets.main.java.srcDirs -} - -artifacts { - archives adjustCriteoAndroidJar - archives adjustCriteoAndroidSourcesJar -} - -afterEvaluate { - publishing { - publications { -/* - mavenAndroidCriteoJar(MavenPublication) { - customizePomForJar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-criteo' - version rootProject.ext.coreVersionName - - artifact adjustCriteoAndroidJar - artifact adjustCriteoAndroidSourcesJar - } -*/ - mavenAndroidCriteoAar(MavenPublication) { - customizePomForAar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-criteo' - version rootProject.ext.coreVersionName - - artifact("$buildDir/outputs/aar/sdk-plugin-criteo-release.aar") { - builtBy tasks.getByPath("adjustCriteoAndroidAar") - } - artifact adjustCriteoAndroidSourcesJar - } - } - - repositories { - maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" - if (project.hasProperty("sonatypeUsername")) { - credentials { - username sonatypeUsername - password sonatypePassword - } - } - } - } - } - signing { -// sign publishing.publications.mavenAndroidCriteoJar - sign publishing.publications.mavenAndroidCriteoAar - } -} - -def customizePomForJar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Criteo plugin for Adjust SDK for Android' - name 'Adjust Android SDK Criteo plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -def customizePomForAar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Criteo plugin for Adjust SDK for Android' - name 'Adjust Android SDK Criteo plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -model { -// tasks.generatePomFileForMavenAndroidCriteoJarPublication { -// destination = file("${project.buildDir}/generated-pom.xml") -// } - /* TODO check if/how to replace this tasks - tasks.publishMavenAndroidCriteoPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenAndroidCriteoPublicationToMavenRepository { - dependsOn project.tasks.signArchives - } - */ - tasks.generatePomFileForMavenAndroidCriteoAarPublication { - destination = file("${project.buildDir}/generated-pom.xml") - } -} - - diff --git a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java deleted file mode 100644 index 03b8f7fa1..000000000 --- a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/AdjustCriteo.java +++ /dev/null @@ -1,236 +0,0 @@ -package com.adjust.sdk.criteo; - -import android.net.Uri; - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -/** - * Created by pfms on 24/02/15. - */ -public class AdjustCriteo { - private static ILogger logger = AdjustFactory.getLogger(); - private static int MAX_VIEW_LISTING_PRODUCTS = 3; - private static String hashEmailInternal; - private static String checkInDateInternal; - private static String checkOutDateInternal; - private static String partnerIdInternal; - private static String userSegmentInternal; - private static String customerIdInternal; - - public static void injectViewListingIntoEvent(AdjustEvent event, List productIds) { - String jsonProducts = createCriteoVLFromProducts(productIds); - event.addPartnerParameter("criteo_p", jsonProducts); - - injectOptionalParams(event); - } - - public static void injectViewProductIntoEvent(AdjustEvent event, String productId) { - event.addPartnerParameter("criteo_p", productId); - - injectOptionalParams(event); - } - - public static void injectCartIntoEvent(AdjustEvent event, List products) { - String jsonProducts = createCriteoVBFromProducts(products); - - event.addPartnerParameter("criteo_p", jsonProducts); - - injectOptionalParams(event); - } - - public static void injectTransactionConfirmedIntoEvent(AdjustEvent event, List products, String transactionId, String newCustomer) { - String jsonProducts = createCriteoVBFromProducts(products); - - event.addPartnerParameter("transaction_id", transactionId); - event.addPartnerParameter("criteo_p", jsonProducts); - event.addPartnerParameter("new_customer", newCustomer); - - injectOptionalParams(event); - } - - public static void injectUserLevelIntoEvent(AdjustEvent event, long uiLevel) { - event.addPartnerParameter("ui_level", String.valueOf(uiLevel)); - - injectOptionalParams(event); - } - - public static void injectUserStatusIntoEvent(AdjustEvent event, String uiStatus) { - event.addPartnerParameter("ui_status", uiStatus); - - injectOptionalParams(event); - } - - public static void injectAchievementUnlockedIntoEvent(AdjustEvent event, String uiAchievement) { - event.addPartnerParameter("ui_achievmnt", uiAchievement); - - injectOptionalParams(event); - } - - public static void injectCustomEventIntoEvent(AdjustEvent event, String uiData) { - event.addPartnerParameter("ui_data", uiData); - - injectOptionalParams(event); - } - - public static void injectCustomEvent2IntoEvent(AdjustEvent event, String uiData2, long uiData3) { - event.addPartnerParameter("ui_data2", uiData2); - event.addPartnerParameter("ui_data3", String.valueOf(uiData3)); - - injectOptionalParams(event); - } - - public static void injectHashedEmailIntoCriteoEvents(String hashEmail) { - hashEmailInternal = hashEmail; - } - - public static void injectViewSearchDatesIntoCriteoEvents(String checkInDate, String checkOutDate) { - checkInDateInternal = checkInDate; - checkOutDateInternal = checkOutDate; - } - - public static void injectPartnerIdIntoCriteoEvents(String partnerId) { - partnerIdInternal = partnerId; - } - - public static void injectUserSegmentIntoCriteoEvents(String userSegment) { - userSegmentInternal = userSegment; - } - - public static void injectCustomerIdIntoCriteoEvents(String customerId) { - customerIdInternal = customerId; - } - - public static void injectDeeplinkIntoEvent(AdjustEvent event, Uri url) { - if (url == null) { - return; - } - - event.addPartnerParameter("criteo_deeplink", url.toString()); - - injectOptionalParams(event); - } - - private static void injectOptionalParams(AdjustEvent event) { - injectHashEmail(event); - injectSearchDates(event); - injectPartnerId(event); - injectUserSegment(event); - injectCustomerId(event); - } - - private static void injectHashEmail(AdjustEvent event) { - if (hashEmailInternal == null || hashEmailInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("criteo_email_hash", hashEmailInternal); - } - - private static void injectSearchDates(AdjustEvent event) { - if (checkInDateInternal == null || checkInDateInternal.isEmpty() || - checkOutDateInternal == null || checkOutDateInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("din", checkInDateInternal); - event.addPartnerParameter("dout", checkOutDateInternal); - } - - private static void injectPartnerId(AdjustEvent event) { - if (partnerIdInternal == null || partnerIdInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("criteo_partner_id", partnerIdInternal); - } - - private static void injectUserSegment(AdjustEvent event) { - if (userSegmentInternal == null || userSegmentInternal.isEmpty()) { - return; - } - - event.addPartnerParameter("user_segment", userSegmentInternal); - } - - private static void injectCustomerId(AdjustEvent event) { - if (customerIdInternal == null || customerIdInternal.isEmpty()) { - return; - } - event.addPartnerParameter("customer_id", customerIdInternal); - } - - private static String createCriteoVLFromProducts(List productIds) { - if (productIds == null) { - logger.warn("Criteo View Listing product ids list is null. It will sent as empty."); - productIds = new ArrayList(); - } - StringBuffer criteoVLValue = new StringBuffer("["); - int productIdsSize = productIds.size(); - - if (productIdsSize > MAX_VIEW_LISTING_PRODUCTS) { - logger.warn("Criteo View Listing should only have at most 3 product ids. The rest will be discarded."); - } - for (int i = 0; i < productIdsSize; ) { - String productID = productIds.get(i); - String productString = String.format(Locale.US, "\"%s\"", productID); - criteoVLValue.append(productString); - - i++; - - if (i == productIdsSize || i >= MAX_VIEW_LISTING_PRODUCTS) { - break; - } - - criteoVLValue.append(","); - } - criteoVLValue.append("]"); - String result = null; - try { - result = URLEncoder.encode(criteoVLValue.toString(),"UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.error("error converting criteo product ids (%s)", e.getMessage()); - } - return result; - } - - private static String createCriteoVBFromProducts(List products) { - if (products == null) { - logger.warn("Criteo Event product list is empty. It will sent as empty."); - products = new ArrayList(); - } - StringBuffer criteoVBValue = new StringBuffer("["); - int productsSize = products.size(); - for (int i = 0; i < productsSize; ) { - CriteoProduct criteoProduct = products.get(i); - String productString = String.format(Locale.US, "{\"i\":\"%s\",\"pr\":%f,\"q\":%d}", - criteoProduct.productID, - criteoProduct.price, - criteoProduct.quantity); - criteoVBValue.append(productString); - - i++; - - if (i == productsSize) { - break; - } - - criteoVBValue.append(","); - } - criteoVBValue.append("]"); - String result = null; - try { - result = URLEncoder.encode(criteoVBValue.toString(),"UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.error("error converting criteo products (%s)", e.getMessage()); - } - return result; - } -} diff --git a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java b/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java deleted file mode 100644 index 519cc6826..000000000 --- a/Adjust/sdk-plugin-criteo/src/main/java/com/adjust/sdk/criteo/CriteoProduct.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.criteo; - -/** - * Created by pfms on 24/02/15. - */ -public class CriteoProduct { - float price; - int quantity; - String productID; - - public CriteoProduct(float price, int quantity, String productID) { - this.price = price; - this.quantity = quantity; - this.productID = productID; - } -} diff --git a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java b/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java deleted file mode 100644 index a06aef0cb..000000000 --- a/Adjust/sdk-plugin-oaid/src/main/java/com/adjust/sdk/oaid/AdjustOaid.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.adjust.sdk.oaid; - -import android.content.Context; -import android.util.Log; - -import com.bun.miitmdid.core.MdidSdkHelper; - -public class AdjustOaid { - static boolean isOaidToBeRead = false; - static boolean isMsaSdkAvailable = false; - - public static void readOaid() { - isOaidToBeRead = true; - } - - public static void readOaid(Context context) { - readOaid(); - - try { - System.loadLibrary("msaoaidsec"); - String certificate = Util.readCertFromAssetFile(context); - isMsaSdkAvailable = MdidSdkHelper.InitCert(context, certificate); - } catch (Throwable t) { - isMsaSdkAvailable = false; - Log.d("Adjust", "Error during msa sdk initialization " + t.getMessage()); - } - } - - public static void doNotReadOaid() { - isOaidToBeRead = false; - } -} diff --git a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java b/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java deleted file mode 100644 index bbd8b0d07..000000000 --- a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/AdjustSamsungReferrer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.samsung; - -import android.content.Context; - -public class AdjustSamsungReferrer { - - static boolean shouldReadSamsungReferrer = true; - - public static void readSamsungReferrer(Context context) { - shouldReadSamsungReferrer = true; - } - - public static void doNotReadSamsungReferrer() { - shouldReadSamsungReferrer = false; - } -} diff --git a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java b/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java deleted file mode 100644 index 3036df7b5..000000000 --- a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/SamsungReferrerClient.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.adjust.sdk.samsung; - -import android.content.Context; - -import com.adjust.sdk.ILogger; -import com.samsung.android.sdk.sinstallreferrer.api.InstallReferrerClient; -import com.samsung.android.sdk.sinstallreferrer.api.InstallReferrerStateListener; -import com.samsung.android.sdk.sinstallreferrer.api.ReferrerDetails; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -public class SamsungReferrerClient { - - public static ReferrerDetails getReferrer(Context context, final ILogger logger, long maxWaitTimeInMilli) { - try { - final InstallReferrerClient referrerClient = InstallReferrerClient.newBuilder(context).build(); - final BlockingQueue referrerDetailsHolder = new LinkedBlockingQueue(1); - referrerClient.startConnection(new InstallReferrerStateListener() { - @Override - public void onInstallReferrerSetupFinished(int responseCode) { - try { - switch (responseCode) { - case InstallReferrerClient.InstallReferrerResponse.OK: - try { - ReferrerDetails details = referrerClient.getInstallReferrer(); - referrerDetailsHolder.offer(details); - } catch (Exception e) { - logger.error("SamsungReferrer getInstallReferrer: " + e.getMessage()); - } finally { - referrerClient.endConnection(); - } - break; - case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED: - logger.info("SamsungReferrer onInstallReferrerSetupFinished: FEATURE_NOT_SUPPORTED"); - break; - case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE: - logger.info("SamsungReferrer onInstallReferrerSetupFinished: SERVICE_UNAVAILABLE"); - break; - } - } catch (Exception e) { - logger.error("SamsungReferrer onInstallReferrerSetupFinished: " + e.getMessage()); - } - } - - @Override - public void onInstallReferrerServiceDisconnected() { - referrerClient.endConnection(); - } - }); - - return referrerDetailsHolder.poll(maxWaitTimeInMilli, TimeUnit.MILLISECONDS); - - } catch (Exception e) { - logger.error("Exception while getting referrer: ", e.getMessage()); - } - - return null; - } -} diff --git a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java b/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java deleted file mode 100644 index 28d292a9c..000000000 --- a/Adjust/sdk-plugin-samsung-referrer/src/main/java/com/adjust/sdk/samsung/Util.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.adjust.sdk.samsung; - -import android.content.Context; - -import com.adjust.sdk.ILogger; -import com.adjust.sdk.ReferrerDetails; - -public class Util { - public synchronized static ReferrerDetails getSamsungInstallReferrerDetails(Context context, ILogger logger) { - if (!AdjustSamsungReferrer.shouldReadSamsungReferrer) { - return null; - } - - com.samsung.android.sdk.sinstallreferrer.api.ReferrerDetails referrerDetails = - SamsungReferrerClient.getReferrer(context, logger, 3000); - if (referrerDetails == null) { - return null; - } - - return new ReferrerDetails(referrerDetails.getInstallReferrer(), - referrerDetails.getReferrerClickTimestampSeconds(), - referrerDetails.getInstallBeginTimestampSeconds()); - } -} diff --git a/Adjust/sdk-plugin-sociomantic/build.gradle b/Adjust/sdk-plugin-sociomantic/build.gradle deleted file mode 100644 index e7ed6a45b..000000000 --- a/Adjust/sdk-plugin-sociomantic/build.gradle +++ /dev/null @@ -1,216 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' -apply plugin: 'signing' - -repositories { - maven { - url "https://oss.sonatype.org/content/repositories/staging/" - } -} - -android { - compileSdk rootProject.ext.coreCompileSdkVersion - publishing { - multipleVariants { - allVariants() - withJavadocJar() - } - } - defaultConfig { - minSdkVersion rootProject.ext.coreMinSdkVersion - targetSdkVersion rootProject.ext.coreTargetSdkVersion - } - namespace 'com.adjust.sdk.sociomantic' -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - // Add SDK via module. - compileOnly project(':sdk-core') - // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' -} - -// read local properties -File localPropsFile = project.rootProject.file('local.properties') -if (localPropsFile.exists()) { - Properties p = new Properties() - new FileInputStream(localPropsFile).withCloseable { is -> - p.load(is) - } - p.each { name, value -> - ext[name] = value - } -} - -task adjustSociomanticAndroidAar(type: Copy) { - dependsOn 'assembleRelease' - - from('build/outputs/aar/') - include 'sdk-plugin-sociomantic-release.aar' - destinationDir file('build/libs/') - rename 'sdk-plugin-sociomantic-release.aar', "${project.name}.aar" - -} - -task adjustSociomanticAndroidJar(type: Jar) { - dependsOn 'compileReleaseJavaWithJavac' - from('build/intermediates/javac/release/classes/') - archiveFileName = project.provider { "${project.name}.jar" } -} - -task adjustSociomanticAndroidSourcesJar(type: Jar) { - setArchiveClassifier('sources') - from android.sourceSets.main.java.srcDirs -} - -artifacts { - archives adjustSociomanticAndroidJar - archives adjustSociomanticAndroidSourcesJar -} - -afterEvaluate { - publishing { - publications { -/* - mavenAndroidSociomanticJar(MavenPublication) { - customizePomForJar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-sociomantic' - version rootProject.ext.coreVersionName - - artifact adjustSociomanticAndroidJar - artifact adjustSociomanticAndroidSourcesJar - } -*/ - mavenAndroidSociomanticAar(MavenPublication) { - customizePomForAar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-sociomantic' - version rootProject.ext.coreVersionName - - artifact("$buildDir/outputs/aar/sdk-plugin-sociomantic-release.aar") { - builtBy tasks.getByPath("adjustSociomanticAndroidAar") - } - artifact adjustSociomanticAndroidSourcesJar - } - } - - repositories { - maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" - if (project.hasProperty("sonatypeUsername")) { - credentials { - username sonatypeUsername - password sonatypePassword - } - } - } - } - } - signing { -// sign publishing.publications.mavenAndroidSociomanticJar - sign publishing.publications.mavenAndroidSociomanticAar - } -} - -def customizePomForJar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Sociomantic plugin for Adjust SDK for Android' - name 'Adjust Android SDK Sociomantic plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -def customizePomForAar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Sociomantic plugin for Adjust SDK for Android' - name 'Adjust Android SDK Sociomantic plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -model { -// tasks.generatePomFileForMavenAndroidSociomanticJarPublication { -// destination = file("${project.buildDir}/generated-pom.xml") -// } - /* TODO check if/how to replace this tasks - tasks.publishMavenAndroidSociomanticPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenAndroidSociomanticPublicationToMavenRepository { - dependsOn project.tasks.signArchives - } - */ - tasks.generatePomFileForMavenAndroidSociomanticAarPublication { - destination = file("${project.buildDir}/generated-pom.xml") - } -} - - diff --git a/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java b/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java deleted file mode 100644 index 0141861d6..000000000 --- a/Adjust/sdk-plugin-sociomantic/src/main/java/com/adjust/sdk/sociomantic/AdjustSociomantic.java +++ /dev/null @@ -1,425 +0,0 @@ -package com.adjust.sdk.sociomantic; - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * AdjustSociomantic Class - * Created by Nicolas Brugneaux nicolas.brugneaux@sociomantic.com on 01/04/15. - */ -public abstract class AdjustSociomantic { - - public final static String SCMCategory = "category"; - public final static String SCMProducts = "products"; - public final static String SCMProductName = "fn"; - public final static String SCMSalePrice = "price"; - public final static String SCMAmount = "amount"; - public final static String SCMCurrency = "currency"; - public final static String SCMProductURL = "url"; - public final static String SCMProductImageURL = "photo"; - public final static String SCMBrand = "brand"; - public final static String SCMDescription = "description"; - public final static String SCMTimestamp = "date"; - public final static String SCMValidityTimestamp = "valid"; - public final static String SCMQuantity = "quantity"; - public final static String SCMScore = "score"; - public final static String SCMProductID = "identifier"; - public final static String SCMActionConfirmed = "confirmed"; - public final static String SCMCustomerAgeGroup = "agegroup"; - public final static String SCMCustomerEducation = "education"; - public final static String SCMCustomerGender = "gender"; - public final static String SCMCustomerID = "identifier"; - public final static String SCMCustomerMHash = "mhash"; - public final static String SCMCustomerSegment = "segment"; - public final static String SCMCustomerTargeting = "targeting"; - public final static String SCMTransaction = "transaction"; - - private final static List productAliases = Arrays.asList( - SCMCategory, - SCMProductName, - SCMSalePrice, - SCMAmount, - SCMCurrency, - SCMProductURL, - SCMProductImageURL, - SCMBrand, - SCMDescription, - SCMTimestamp, - SCMValidityTimestamp, - SCMQuantity, - SCMScore - ); - - private final static List basketAliases = Arrays.asList( - SCMProductID, - SCMAmount, - SCMCurrency, - SCMQuantity - ); - - private final static List saleAliases = Arrays.asList( - SCMAmount, - SCMCurrency - ); - - private final static List customerAliases = Arrays.asList( - SCMCustomerAgeGroup, - SCMCustomerEducation, - SCMCustomerGender, - SCMCustomerID, - SCMCustomerMHash, - SCMCustomerSegment, - SCMCustomerTargeting - ); - - private static String adpanId; - - private static ILogger logger = AdjustFactory.getLogger(); - - public static void injectPartnerIdInSociomanticEvents(String newAdpanId) { - adpanId = newAdpanId; - } - - public static void injectCustomerDataIntoEvent(AdjustEvent event, Map customerData) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == customerData) { - logger.error("Customer data is required."); - return; - } - - Map data = new HashMap(); - - for (Entry entry: customerData.entrySet()) { - if (!customerAliases.contains(entry.getKey())) { - logger.warn("Key must belong to the customer Aliases, entry: %s was discarded", entry.getKey()); - } - else { - data.put(entry.getKey(), entry.getValue()); - } - } - - String dob = stringify(data); - - addPartnerParameter(event, "socio_dob", dob); - } - - public static void injectHomePageIntoEvent(AdjustEvent event) { - if (null == event) { - logger.error("Event object is required."); - } - addPartnerParameter(event); - } - - public static void injectViewListingIntoEvent(AdjustEvent event, List categories) { - injectViewListingIntoEvent(event, categories, null); - } - public static void injectViewListingIntoEvent(AdjustEvent event, List categories, String date) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == categories) { - logger.error("Categories list is required."); - return; - } - - Map co = new HashMap(); - - if (null != date) { - co.put(SCMTimestamp, date); - } - - co.put(SCMCategory, categories); - - addPartnerParameter(event, "socio_co", stringify(co)); - } - - public static void injectProductIntoEvent(AdjustEvent event, String productId) { - injectProductIntoEvent(event, productId, null); - } - public static void injectProductIntoEvent(AdjustEvent event, String productId, Map parameters) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == productId || "".equals(productId)) { - logger.error("Product ID is required."); - return; - } - - Map>> po = new HashMap>>(1); - List> productList; - Map product; - - if (null != parameters) { - product = filter(parameters, productAliases); - } - else { - product = new HashMap(); - } - - product.put(SCMProductID, productId); - productList = Arrays.asList(product); - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - - public static void injectCartIntoEvent(AdjustEvent event, List products) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == products) { - logger.error("Products list is required."); - return; - } - - Map>> po = new HashMap>>(1); - List> productList = new ArrayList>(); - - for (Object product: products) { - Map _product = new HashMap(); - - if (product instanceof String) { - _product.put(SCMProductID, product); - } - else if (product instanceof Map) { - _product = filter((Map) product, basketAliases); - } - - if (!_product.isEmpty()) { - productList.add(_product); - } - } - - if (!productList.isEmpty()) { - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - } - - public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { - injectTransactionIntoEvent(event, transactionID, products, null, Boolean.TRUE); - } - public static void injectConfirmedTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { - injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.TRUE); - } - - public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products) { - injectTransactionIntoEvent(event, transactionID, products, null, Boolean.FALSE); - } - public static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters) { - injectTransactionIntoEvent(event, transactionID, products, parameters, Boolean.FALSE); - } - private static void injectTransactionIntoEvent(AdjustEvent event, String transactionID, List products, Map parameters, Boolean confirmed) { - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == transactionID || "".equals(transactionID)) { - logger.error("Transaction ID is required."); - return; - } - if (null == products) { - logger.error("Products list is required."); - return; - } - - Map> to = new HashMap>(1); - Map>> po = new HashMap>>(1); - List> productList = new ArrayList>(); - - for (Object product: products) { - Map _product = new HashMap(); - - if (product instanceof String) { - _product.put(SCMProductID, product); - } - else if (product instanceof Map) { - _product = filter((Map) product, basketAliases); - } - - if (!_product.isEmpty()) { - productList.add(_product); - } - } - - if (!productList.isEmpty()) { - po.put(SCMProducts, productList); - addPartnerParameter(event, "socio_po", stringify(po)); - } - - if (null != parameters) { - to.put(SCMTransaction, filter(parameters, saleAliases)); - } - else { - to.put(SCMTransaction, new HashMap()); - } - - if (confirmed) { - to.get(SCMTransaction).put(SCMActionConfirmed, "true"); - } - - to.get(SCMTransaction).put(SCMTransaction, transactionID); - - addPartnerParameter(event, "socio_to", stringify(to)); - } - - public static void injectLeadIntoEvent(AdjustEvent event, String leadID) { - injectLeadIntoEvent(event, leadID, Boolean.FALSE); - } - public static void injectLeadIntoEvent(AdjustEvent event, String leadID, Boolean confirmed) { - - if (null == event) { - logger.error("Event object is required."); - return; - } - if (null == leadID || "".equals(leadID)) { - logger.error("Lead ID is required."); - return; - } - - Map> to = new HashMap>(1); - to.put(SCMTransaction, new HashMap()); - - if (confirmed) { - to.get(SCMTransaction).put(SCMActionConfirmed, "true"); - } - - to.get(SCMTransaction).put(SCMTransaction, leadID); - - addPartnerParameter(event, "socio_to", stringify(to)); - } - - //////////////////////////////////////////////////////////////////////////////////////////////// - // private methods used internally - //////////////////////////////////////////////////////////////////////////////////////////////// - - private static void addPartnerParameter(AdjustEvent event) { - addPartnerParameter(event, null, null); - } - private static void addPartnerParameter(AdjustEvent event, String parameter, String json) { - if (null == adpanId) { - logger.error("The adpanId must be set before sending any sociomantic event. No parameter has been added."); - return; - } - - if (null != parameter && null != json) - { - event.addPartnerParameter(parameter, json); - } - - event.addPartnerParameter("socio_aid", adpanId); - } - - private static Map filter(Map parameters, List aliases) { - - Map filtered = new HashMap(); - - for(Entry entry: parameters.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (!aliases.contains(key)) { - logger.error("Key must correspond to as Sociomantic alias => ".concat(key)); - } - else { - if (key.equals(SCMCategory)) { - if (value instanceof String || value instanceof String[]) { - filtered.put(key, Arrays.asList(value)); - } else if (value instanceof List) { - filtered.put(key, filterStringArray((List) value)); - } - } - else { - filtered.put(key, value); - } - } - } - return filtered; - } - - private static List filterStringArray(List list) { - - List filtered = new ArrayList(); - for (Object item: list) { - if (item instanceof String) { - filtered.add((String) item); - } - else { - logger.error("All values should be strings"); - } - } - return filtered; - } - - private static String stringify(Object o) { - if (o == null) { - return "null"; - } - - if (o instanceof String) { - return "\"".concat((String) o).concat("\""); - } - - if (o instanceof Integer || o instanceof Long || o instanceof Double) { - return o.toString(); - } - - if (o instanceof Boolean) { - return (Boolean) o ? "true" : "false"; - } - - if (o instanceof List) { - String res = "["; - List list = (List) o; - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - Object item = iterator.next(); - res = res.concat(stringify(item)); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("]"); - } - - if (o instanceof Map) { - String res = "{"; - Map map = (Map) o; - Iterator> iterator = map.entrySet().iterator(); - - while(iterator.hasNext()) { - Entry entry = iterator.next(); - - res = res.concat(stringify(entry.getKey())) - .concat(":") - .concat(stringify(entry.getValue())); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("}"); - } - - logger.error("Could not parse the object ".concat(o.toString().concat(" into a JSON string, returned empty string."))); - return ""; - - } -} diff --git a/Adjust/sdk-plugin-trademob/build.gradle b/Adjust/sdk-plugin-trademob/build.gradle deleted file mode 100644 index e8b223ec2..000000000 --- a/Adjust/sdk-plugin-trademob/build.gradle +++ /dev/null @@ -1,214 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'maven-publish' -apply plugin: 'signing' - -repositories { - maven { - url "https://oss.sonatype.org/content/repositories/staging/" - } -} - -android { - compileSdk rootProject.ext.coreCompileSdkVersion - publishing { - multipleVariants { - allVariants() - withJavadocJar() - } - } - defaultConfig { - minSdkVersion rootProject.ext.coreMinSdkVersion - targetSdkVersion rootProject.ext.coreTargetSdkVersion - } - namespace 'com.adjust.sdk.trademob' -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - // Add SDK via module. - compileOnly project(':sdk-core') - // Add SDK via Maven. - // implementation 'com.adjust.sdk:adjust-android:4.38.5' -} - -// read local properties -File localPropsFile = project.rootProject.file('local.properties') -if (localPropsFile.exists()) { - Properties p = new Properties() - new FileInputStream(localPropsFile).withCloseable { is -> - p.load(is) - } - p.each { name, value -> - ext[name] = value - } -} - -task adjustTrademobAndroidAar(type: Copy) { - dependsOn 'assembleRelease' - - from('build/outputs/aar/') - include 'sdk-plugin-trademob-release.aar' - destinationDir file('build/libs/') - rename 'sdk-plugin-trademob-release.aar', "${project.name}.aar" - -} - -task adjustTrademobAndroidJar(type: Jar) { - dependsOn 'compileReleaseJavaWithJavac' - - from('build/intermediates/javac/release/classes/') - archiveFileName = project.provider { "${project.name}.jar" } -} - - -task adjustTrademobAndroidSourcesJar(type: Jar) { - setArchiveClassifier('sources') - from android.sourceSets.main.java.srcDirs -} - -artifacts { - archives adjustTrademobAndroidJar - archives adjustTrademobAndroidSourcesJar -} - -afterEvaluate { - publishing { - publications { -/* - mavenAndroidTrademobJar(MavenPublication) { - customizePomForJar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-trademob' - version rootProject.ext.coreVersionName - - artifact adjustTrademobAndroidJar - artifact adjustTrademobAndroidSourcesJar - } -*/ - mavenAndroidTrademobAar(MavenPublication) { - customizePomForAar(pom) - groupId rootProject.ext.adjustGroupId - artifactId 'adjust-android-trademob' - version rootProject.ext.coreVersionName - - artifact("$buildDir/outputs/aar/sdk-plugin-trademob-release.aar") { - builtBy tasks.getByPath("adjustTrademobAndroidAar") - } - artifact adjustTrademobAndroidSourcesJar - } - } - - repositories { - maven { - url "https://oss.sonatype.org/service/local/staging/deploy/maven2" - if (project.hasProperty("sonatypeUsername")) { - credentials { - username sonatypeUsername - password sonatypePassword - } - } - } - } - } - signing { -// sign publishing.publications.mavenAndroidTrademobJar - sign publishing.publications.mavenAndroidTrademobAar - } -} - -def customizePomForJar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication. - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Trademob plugin for Adjust SDK for Android' - name 'Adjust Android SDK Trademob plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -def customizePomForAar(pom) { - pom.withXml { - def root = asNode() - - // Add all items necessary for maven central publication. - root.children().last() + { - resolveStrategy = Closure.DELEGATE_FIRST - description 'The Trademob plugin for Adjust SDK for Android' - name 'Adjust Android SDK Trademob plugin' - url 'https://github.com/adjust/android_sdk' - - organization { - name 'adjust GmbH' - url 'http://www.adjust.com' - } - licenses { - license { - name 'MIT License' - url 'http://www.opensource.org/licenses/mit-license.php' - } - } - scm { - url 'git@github.com:adjust/android_sdk.git' - connection 'scm:git:git@github.com:adjust/android_sdk.git' - developerConnection 'scm:git:git@github.com:adjust/android_sdk.git' - } - developers { - developer { - name 'Pedro Silva' - email 'pedro@adjust.com' - } - developer { - name 'Ugljesa Erceg' - email 'ugljesa@adjust.com' - } - } - } - } -} - -model { -// tasks.generatePomFileForMavenAndroidTrademobJarPublication { -// destination = file("${project.buildDir}/generated-pom.xml") -// } - /* TODO check if/how to replace this tasks - tasks.publishMavenAndroidTrademobPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenAndroidTrademobPublicationToMavenRepository { - dependsOn project.tasks.signArchives - } - */ - tasks.generatePomFileForMavenAndroidTrademobAarPublication { - destination = file("${project.buildDir}/generated-pom.xml") - } -} diff --git a/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml deleted file mode 100644 index 94cbbcfc3..000000000 --- a/Adjust/sdk-plugin-trademob/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java deleted file mode 100644 index 26867ca88..000000000 --- a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/AdjustTrademob.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.adjust.sdk.trademob; - -import com.adjust.sdk.AdjustEvent; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.ILogger; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - - -public class AdjustTrademob { - - private static int MAX_LISTING_ITEMS_COUNT = 5; - - private static ILogger logger = AdjustFactory.getLogger(); - - public static void injectViewItemIntoEvent(AdjustEvent event, String itemId, Map metadata) { - event.addPartnerParameter("tm_item", itemId); - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - } - - public static void injectViewListingIntoEvent(AdjustEvent event, List itemIds, Map metadata) { - String jsonItems = stringifyItemIds(itemIds); - event.addPartnerParameter("tm_item", jsonItems); - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - } - - public static void injectAddToBasketIntoEvent(AdjustEvent event, List items, Map metadata) { - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - String jsonItems = stringifyItems(items); - event.addPartnerParameter("tm_item", jsonItems); - } - - public static void injectCheckoutIntoEvent(AdjustEvent event, List items, Map metadata) { - String jsonMetadata = stringifyMetadata(metadata); - event.addPartnerParameter("tm_md", jsonMetadata); - String jsonItems = stringifyItems(items); - event.addPartnerParameter("tm_item", jsonItems); - } - - private static String stringifyItemIds(List itemIds) { - if (itemIds == null) { - logger.warn("TM View Listing item ids list is null. Empty ids array will be sent."); - itemIds = new ArrayList(); - } - StringBuffer tmViewList = new StringBuffer("["); - int itemsSize = itemIds.size(); - int i = 0; - - while (i < itemsSize) { - String itemId = itemIds.get(i); - String itemString = String.format(Locale.US, "\"%s\"", itemId); - tmViewList.append(itemString); - - i++; - - if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { - break; - } - - tmViewList.append(","); - } - - tmViewList.append("]"); - - return tmViewList.toString(); - } - - private static String stringifyItems(List items) { - if (items == null) { - logger.warn("TM View Listing item ids list is empty. Empty items will be sent."); - items = new ArrayList(); - } - - StringBuffer itemsStrBuffer = new StringBuffer("["); - int itemsSize = items.size(); - - for (int i = 0; i < itemsSize; ) { - TrademobItem item = items.get(i); - String itemString = String.format(Locale.US, "{\"id\":\"%s\",\"price\":%f,\"quantity\":%d}", - item.itemId, - item.price, - item.quantity); - itemsStrBuffer.append(itemString); - - i++; - - if (i == itemsSize || i >= MAX_LISTING_ITEMS_COUNT) { - break; - } - - itemsStrBuffer.append(","); - } - - itemsStrBuffer.append("]"); - - return itemsStrBuffer.toString(); - } - - private static String stringifyMetadata(Map metadata) { - - if(null == metadata) { - return "{}"; - } - String res = "{"; - - Iterator> iterator = metadata.entrySet().iterator(); - - while(iterator.hasNext()) { - Map.Entry entry = iterator.next(); - String key = "\"".concat(entry.getKey()).concat("\""); - String value = "\"".concat(entry.getValue()).concat("\""); - res = res.concat(key).concat(":").concat(value); - - if (iterator.hasNext()) { - res = res.concat(","); - } - } - - return res.concat("}"); - } -} diff --git a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java b/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java deleted file mode 100644 index 483c1a334..000000000 --- a/Adjust/sdk-plugin-trademob/src/main/java/com/adjust/sdk/trademob/TrademobItem.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adjust.sdk.trademob; - -public class TrademobItem { - float price; - int quantity; - String itemId; - - public TrademobItem(String itemId, int quantity, float price) { - this.price = price; - this.quantity = quantity; - this.itemId = itemId; - } -} diff --git a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java b/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java deleted file mode 100644 index 583652ceb..000000000 --- a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/AdjustVivoReferrer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.vivo; - -import android.content.Context; - -public class AdjustVivoReferrer { - - static boolean shouldReadVivoReferrer = true; - - public static void readVivoReferrer(Context context) { - shouldReadVivoReferrer = true; - } - - public static void doNotReadVivoReferrer() { - shouldReadVivoReferrer = false; - } -} diff --git a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java b/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java deleted file mode 100644 index 38dc9cf15..000000000 --- a/Adjust/sdk-plugin-vivo-referrer/src/main/java/com/adjust/sdk/vivo/Util.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.vivo; - -import android.content.Context; - -import com.adjust.sdk.ILogger; -import com.adjust.sdk.ReferrerDetails; - -public class Util { - public synchronized static ReferrerDetails getVivoInstallReferrerDetails(Context context, ILogger logger) { - if (!AdjustVivoReferrer.shouldReadVivoReferrer) { - return null; - } - - return VivoReferrerClient.getReferrer(context, logger); - } -} diff --git a/Adjust/sdk-plugin-webbridge/src/main/AndroidManifest.xml b/Adjust/sdk-plugin-webbridge/src/main/AndroidManifest.xml deleted file mode 100644 index 94cbbcfc3..000000000 --- a/Adjust/sdk-plugin-webbridge/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust.js b/Adjust/sdk-plugin-webbridge/src/main/assets/adjust.js deleted file mode 100644 index ca9c7ae4d..000000000 --- a/Adjust/sdk-plugin-webbridge/src/main/assets/adjust.js +++ /dev/null @@ -1,228 +0,0 @@ -var Adjust = { - onCreate: function (adjustConfig) { - if (adjustConfig && !adjustConfig.getSdkPrefix()) { - adjustConfig.setSdkPrefix(this.getSdkPrefix()); - } - this.adjustConfig = adjustConfig; - if (AdjustBridge) { - AdjustBridge.onCreate(JSON.stringify(adjustConfig)); - } - }, - - getConfig: function () { - return this.adjustConfig; - }, - - trackEvent: function (adjustEvent) { - if (AdjustBridge) { - AdjustBridge.trackEvent(JSON.stringify(adjustEvent)); - } - }, - - trackAdRevenue: function(source, payload) { - if (AdjustBridge) { - AdjustBridge.trackAdRevenue(source, payload); - } - }, - - onResume: function () { - if (AdjustBridge) { - AdjustBridge.onResume(); - } - }, - - onPause: function () { - if (AdjustBridge) { - AdjustBridge.onPause(); - } - }, - - setEnabled: function (enabled) { - if (AdjustBridge) { - AdjustBridge.setEnabled(enabled); - } - }, - - isEnabled: function (callback) { - if (!AdjustBridge) { - return undefined; - } - // supports legacy return with callback - if (arguments.length === 1) { - // with manual string call - if (typeof callback === 'string' || callback instanceof String) { - this.isEnabledCallbackName = callback; - } else { - // or save callback and call later - this.isEnabledCallbackName = 'Adjust.adjust_isEnabledCallback'; - this.isEnabledCallbackFunction = callback; - } - AdjustBridge.isEnabled(this.isEnabledCallbackName); - } else { - return AdjustBridge.isEnabled(); - } - }, - - adjust_isEnabledCallback: function (isEnabled) { - if (AdjustBridge && this.isEnabledCallbackFunction) { - this.isEnabledCallbackFunction(isEnabled); - } - }, - - appWillOpenUrl: function (url) { - if (AdjustBridge) { - AdjustBridge.appWillOpenUrl(url); - } - }, - - setReferrer: function (referrer) { - if (AdjustBridge) { - AdjustBridge.setReferrer(referrer); - } - }, - - setOfflineMode: function(isOffline) { - if (AdjustBridge) { - AdjustBridge.setOfflineMode(isOffline); - } - }, - - sendFirstPackages: function() { - if (AdjustBridge) { - AdjustBridge.sendFirstPackages(); - } - }, - - addSessionCallbackParameter: function(key, value) { - if (AdjustBridge) { - AdjustBridge.addSessionCallbackParameter(key, value); - } - }, - - addSessionPartnerParameter: function(key, value) { - if (AdjustBridge) { - AdjustBridge.addSessionPartnerParameter(key, value); - } - }, - - removeSessionCallbackParameter: function(key) { - if (AdjustBridge) { - AdjustBridge.removeSessionCallbackParameter(key); - } - }, - - removeSessionPartnerParameter: function(key) { - if (AdjustBridge) { - AdjustBridge.removeSessionPartnerParameter(key); - } - }, - - resetSessionCallbackParameters: function() { - if (AdjustBridge) { - AdjustBridge.resetSessionCallbackParameters(); - } - }, - - resetSessionPartnerParameters: function() { - if (AdjustBridge) { - AdjustBridge.resetSessionPartnerParameters(); - } - }, - - setPushToken: function(token) { - if (AdjustBridge) { - AdjustBridge.setPushToken(token); - } - }, - - gdprForgetMe: function() { - if (AdjustBridge) { - AdjustBridge.gdprForgetMe(); - } - }, - - disableThirdPartySharing: function() { - if (AdjustBridge) { - AdjustBridge.disableThirdPartySharing(); - } - }, - - trackThirdPartySharing: function(adjustThirdPartySharing) { - if (AdjustBridge) { - AdjustBridge.trackThirdPartySharing(JSON.stringify(adjustThirdPartySharing)); - } - }, - - trackMeasurementConsent: function(consentMeasurement) { - if (AdjustBridge) { - AdjustBridge.trackMeasurementConsent(consentMeasurement); - } - }, - - getGoogleAdId: function (callback) { - if (AdjustBridge) { - if (typeof callback === 'string' || callback instanceof String) { - this.getGoogleAdIdCallbackName = callback; - } else { - this.getGoogleAdIdCallbackName = 'Adjust.adjust_getGoogleAdIdCallback'; - this.getGoogleAdIdCallbackFunction = callback; - } - AdjustBridge.getGoogleAdId(this.getGoogleAdIdCallbackName); - } - }, - - adjust_getGoogleAdIdCallback: function (googleAdId) { - if (AdjustBridge && this.getGoogleAdIdCallbackFunction) { - this.getGoogleAdIdCallbackFunction(googleAdId); - } - }, - - getAmazonAdId: function (callback) { - if (AdjustBridge) { - return AdjustBridge.getAmazonAdId(); - } else { - return undefined; - } - }, - - getAdid: function () { - if (AdjustBridge) { - return AdjustBridge.getAdid(); - } else { - return undefined; - } - }, - - getAttribution: function (callback) { - if (AdjustBridge) { - AdjustBridge.getAttribution(callback); - } - }, - - getSdkVersion: function () { - if (AdjustBridge) { - return this.getSdkPrefix() + '@' + AdjustBridge.getSdkVersion(); - } else { - return undefined; - } - }, - - getSdkPrefix: function () { - if (this.adjustConfig) { - return this.adjustConfig.getSdkPrefix(); - } else { - return 'web-bridge4.38.5'; - } - }, - - teardown: function() { - if (AdjustBridge) { - AdjustBridge.teardown(); - } - this.adjustConfig = undefined; - this.isEnabledCallbackName = undefined; - this.isEnabledCallbackFunction = undefined; - this.getGoogleAdIdCallbackName = undefined; - this.getGoogleAdIdCallbackFunction = undefined; - }, -}; diff --git a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java b/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java deleted file mode 100644 index 4b26d0dfe..000000000 --- a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeInstance.java +++ /dev/null @@ -1,845 +0,0 @@ -package com.adjust.sdk.webbridge; - -import android.annotation.TargetApi; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.app.Activity; -import android.webkit.JavascriptInterface; -import android.webkit.WebView; -import android.app.Application; - -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.AdjustFactory; -import com.adjust.sdk.AdjustSessionFailure; -import com.adjust.sdk.AdjustSessionSuccess; -import com.adjust.sdk.AdjustTestOptions; -import com.adjust.sdk.AdjustThirdPartySharing; -import com.adjust.sdk.LogLevel; -import com.adjust.sdk.OnAttributionChangedListener; -import com.adjust.sdk.OnDeeplinkResponseListener; -import com.adjust.sdk.OnDeviceIdsRead; -import com.adjust.sdk.OnEventTrackingFailedListener; -import com.adjust.sdk.OnEventTrackingSucceededListener; -import com.adjust.sdk.OnSessionTrackingFailedListener; -import com.adjust.sdk.OnSessionTrackingSucceededListener; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; - -/** - * Created by uerceg on 22/07/16. - */ -public class AdjustBridgeInstance { - private static final String LOG_LEVEL_VERBOSE = "VERBOSE"; - private static final String LOG_LEVEL_DEBUG = "DEBUG"; - private static final String LOG_LEVEL_INFO = "INFO"; - private static final String LOG_LEVEL_WARN = "WARN"; - private static final String LOG_LEVEL_ERROR = "ERROR"; - private static final String LOG_LEVEL_ASSERT = "ASSERT"; - private static final String LOG_LEVEL_SUPPRESS = "SUPPRESS"; - - private static final String JAVASCRIPT_INTERFACE_NAME = "AdjustBridge"; - private static final String FB_JAVASCRIPT_INTERFACE_NAME_PREFIX = "fbmq_"; - - private WebView webView; - private Application application; - private boolean isInitialized = false; - private boolean shouldDeferredDeeplinkBeLaunched = true; - private FacebookSDKJSInterface facebookSDKJSInterface = null; - - AdjustBridgeInstance() {} - - AdjustBridgeInstance(Application application, WebView webView) { - this.application = application; - setWebView(webView); - } - - // Automatically subscribe to Android lifecycle callbacks to properly handle session tracking. - // This requires user to have minimal supported API level set to 14. - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private static final class AdjustLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { - @Override - public void onActivityResumed(Activity activity) { - Adjust.onResume(); - } - - @Override - public void onActivityPaused(Activity activity) { - Adjust.onPause(); - } - - @Override - public void onActivityStopped(Activity activity) {} - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} - - @Override - public void onActivityDestroyed(Activity activity) {} - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) {} - - @Override - public void onActivityStarted(Activity activity) {} - } - - private boolean isInitialized() { - if (webView == null) { - AdjustBridgeUtil.getLogger().error("Webview missing. Call AdjustBridge.setWebView before"); - return false; - } - if (application == null) { - AdjustBridgeUtil.getLogger().error("Application context missing. Call AdjustBridge.setApplicationContext before"); - return false; - } - return true; - } - - public void registerFacebookSDKJSInterface() { - // Configure the web view to add fb pixel interface - String fbApplicationId = FacebookSDKJSInterface.getApplicationId(application.getApplicationContext()); - AdjustFactory.getLogger().info("AdjustBridgeInstance fbApplicationId: %s", fbApplicationId); - - if (fbApplicationId == null) { - return; - } - - this.facebookSDKJSInterface = new FacebookSDKJSInterface(); - - // Add FB pixel to JS interface. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - this.webView.addJavascriptInterface(facebookSDKJSInterface, - FB_JAVASCRIPT_INTERFACE_NAME_PREFIX - + fbApplicationId - ); - } - } - - @JavascriptInterface - public void onCreate(String adjustConfigString) { - // Initialise SDK only if it's not already initialised. - if (isInitialized) { - AdjustBridgeUtil.getLogger().warn("Adjust bridge is already initialized. Ignoring further attempts"); - return; - } - if (!isInitialized()) { - return; - } - - try { - AdjustBridgeUtil.getLogger().verbose("Web bridge onCreate adjustConfigString: " + adjustConfigString); - - JSONObject jsonAdjustConfig = new JSONObject(adjustConfigString); - Object appTokenField = jsonAdjustConfig.get("appToken"); - Object environmentField = jsonAdjustConfig.get("environment"); - Object allowSuppressLogLevelField = jsonAdjustConfig.get("allowSuppressLogLevel"); - Object eventBufferingEnabledField = jsonAdjustConfig.get("eventBufferingEnabled"); - Object sendInBackgroundField = jsonAdjustConfig.get("sendInBackground"); - Object logLevelField = jsonAdjustConfig.get("logLevel"); - Object sdkPrefixField = jsonAdjustConfig.get("sdkPrefix"); - Object processNameField = jsonAdjustConfig.get("processName"); - Object defaultTrackerField = jsonAdjustConfig.get("defaultTracker"); - Object externalDeviceIdField = jsonAdjustConfig.get("externalDeviceId"); - Object attributionCallbackNameField = jsonAdjustConfig.get("attributionCallbackName"); - Object deviceKnownField = jsonAdjustConfig.get("deviceKnown"); - Object needsCostField = jsonAdjustConfig.get("needsCost"); - Object eventSuccessCallbackNameField = jsonAdjustConfig.get("eventSuccessCallbackName"); - Object eventFailureCallbackNameField = jsonAdjustConfig.get("eventFailureCallbackName"); - Object sessionSuccessCallbackNameField = jsonAdjustConfig.get("sessionSuccessCallbackName"); - Object sessionFailureCallbackNameField = jsonAdjustConfig.get("sessionFailureCallbackName"); - Object openDeferredDeeplinkField = jsonAdjustConfig.get("openDeferredDeeplink"); - Object deferredDeeplinkCallbackNameField = jsonAdjustConfig.get("deferredDeeplinkCallbackName"); - Object delayStartField = jsonAdjustConfig.get("delayStart"); - Object userAgentField = jsonAdjustConfig.get("userAgent"); - Object secretIdField = jsonAdjustConfig.get("secretId"); - Object info1Field = jsonAdjustConfig.get("info1"); - Object info2Field = jsonAdjustConfig.get("info2"); - Object info3Field = jsonAdjustConfig.get("info3"); - Object info4Field = jsonAdjustConfig.get("info4"); - Object fbPixelDefaultEventTokenField = jsonAdjustConfig.get("fbPixelDefaultEventToken"); - Object fbPixelMappingField = jsonAdjustConfig.get("fbPixelMapping"); - Object urlStrategyField = jsonAdjustConfig.get("urlStrategy"); - Object preinstallTrackingEnabledField = jsonAdjustConfig.get("preinstallTrackingEnabled"); - Object preinstallFilePathField = jsonAdjustConfig.get("preinstallFilePath"); - Object playStoreKidsAppEnabledField = jsonAdjustConfig.get("playStoreKidsAppEnabled"); - Object coppaCompliantEnabledField = jsonAdjustConfig.get("coppaCompliantEnabled"); - Object finalAttributionEnabledField = jsonAdjustConfig.get("finalAttributionEnabled"); - Object fbAppIdField = jsonAdjustConfig.get("fbAppId"); - Object readDeviceInfoOnceEnabledField = jsonAdjustConfig.get("readDeviceInfoOnceEnabled"); - - String appToken = AdjustBridgeUtil.fieldToString(appTokenField); - String environment = AdjustBridgeUtil.fieldToString(environmentField); - Boolean allowSuppressLogLevel = AdjustBridgeUtil.fieldToBoolean(allowSuppressLogLevelField); - - AdjustConfig adjustConfig; - if (allowSuppressLogLevel == null) { - adjustConfig = new AdjustConfig(application.getApplicationContext(), appToken, environment); - } else { - adjustConfig = new AdjustConfig(application.getApplicationContext(), appToken, environment, allowSuppressLogLevel.booleanValue()); - } - - if (!adjustConfig.isValid()) { - return; - } - - // Event buffering - Boolean eventBufferingEnabled = AdjustBridgeUtil.fieldToBoolean(eventBufferingEnabledField); - if (eventBufferingEnabled != null) { - adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); - } - - // Send in the background - Boolean sendInBackground = AdjustBridgeUtil.fieldToBoolean(sendInBackgroundField); - if (sendInBackground != null) { - adjustConfig.setSendInBackground(sendInBackground); - } - - // Log level - String logLevelString = AdjustBridgeUtil.fieldToString(logLevelField); - if (logLevelString != null) { - if (logLevelString.equalsIgnoreCase(LOG_LEVEL_VERBOSE)) { - adjustConfig.setLogLevel(LogLevel.VERBOSE); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_DEBUG)) { - adjustConfig.setLogLevel(LogLevel.DEBUG); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_INFO)) { - adjustConfig.setLogLevel(LogLevel.INFO); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_WARN)) { - adjustConfig.setLogLevel(LogLevel.WARN); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_ERROR)) { - adjustConfig.setLogLevel(LogLevel.ERROR); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_ASSERT)) { - adjustConfig.setLogLevel(LogLevel.ASSERT); - } else if (logLevelString.equalsIgnoreCase(LOG_LEVEL_SUPPRESS)) { - adjustConfig.setLogLevel(LogLevel.SUPRESS); - } - } - - // SDK prefix - String sdkPrefix = AdjustBridgeUtil.fieldToString(sdkPrefixField); - if (sdkPrefix != null) { - adjustConfig.setSdkPrefix(sdkPrefix); - } - - // Main process name - String processName = AdjustBridgeUtil.fieldToString(processNameField); - if (processName != null) { - adjustConfig.setProcessName(processName); - } - - // Default tracker - String defaultTracker = AdjustBridgeUtil.fieldToString(defaultTrackerField); - if (defaultTracker != null) { - adjustConfig.setDefaultTracker(defaultTracker); - } - - // External device ID - String externalDeviceId = AdjustBridgeUtil.fieldToString(externalDeviceIdField); - if (externalDeviceId != null) { - adjustConfig.setExternalDeviceId(externalDeviceId); - } - - // Attribution callback name - final String attributionCallbackName = AdjustBridgeUtil.fieldToString(attributionCallbackNameField); - if (attributionCallbackName != null) { - adjustConfig.setOnAttributionChangedListener(new OnAttributionChangedListener() { - @Override - public void onAttributionChanged(AdjustAttribution attribution) { - AdjustBridgeUtil.execAttributionCallbackCommand(webView, attributionCallbackName, attribution); - } - }); - } - - // Is device known - Boolean deviceKnown = AdjustBridgeUtil.fieldToBoolean(deviceKnownField); - if (deviceKnown != null) { - adjustConfig.setDeviceKnown(deviceKnown); - } - - // Needs cost - Boolean needsCost = AdjustBridgeUtil.fieldToBoolean(needsCostField); - if (needsCost != null) { - adjustConfig.setNeedsCost(needsCost); - } - - // Event success callback - final String eventSuccessCallbackName = AdjustBridgeUtil.fieldToString(eventSuccessCallbackNameField); - if (eventSuccessCallbackName != null) { - adjustConfig.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { - public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { - AdjustBridgeUtil.execEventSuccessCallbackCommand(webView, eventSuccessCallbackName, eventSuccessResponseData); - } - }); - } - - // Event failure callback - final String eventFailureCallbackName = AdjustBridgeUtil.fieldToString(eventFailureCallbackNameField); - if (eventFailureCallbackName != null) { - adjustConfig.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { - public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { - AdjustBridgeUtil.execEventFailureCallbackCommand(webView, eventFailureCallbackName, eventFailureResponseData); - } - }); - } - - // Session success callback - final String sessionSuccessCallbackName = AdjustBridgeUtil.fieldToString(sessionSuccessCallbackNameField); - if (sessionSuccessCallbackName != null) { - adjustConfig.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { - @Override - public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { - AdjustBridgeUtil.execSessionSuccessCallbackCommand(webView, sessionSuccessCallbackName, sessionSuccessResponseData); - } - }); - } - - // Session failure callback - final String sessionFailureCallbackName = AdjustBridgeUtil.fieldToString(sessionFailureCallbackNameField); - if (sessionFailureCallbackName != null) { - adjustConfig.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { - @Override - public void onFinishedSessionTrackingFailed(AdjustSessionFailure failureResponseData) { - AdjustBridgeUtil.execSessionFailureCallbackCommand(webView, sessionFailureCallbackName, failureResponseData); - } - }); - } - - // Should deferred deep link be opened? - Boolean openDeferredDeeplink = AdjustBridgeUtil.fieldToBoolean(openDeferredDeeplinkField); - if (openDeferredDeeplink != null) { - shouldDeferredDeeplinkBeLaunched = openDeferredDeeplink; - } - - // Deferred deeplink callback - final String deferredDeeplinkCallbackName = AdjustBridgeUtil.fieldToString(deferredDeeplinkCallbackNameField); - if (deferredDeeplinkCallbackName != null) { - adjustConfig.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { - @Override - public boolean launchReceivedDeeplink(Uri deeplink) { - AdjustBridgeUtil.execSingleValueCallback(webView, deferredDeeplinkCallbackName, deeplink.toString()); - return shouldDeferredDeeplinkBeLaunched; - } - }); - } - - // Delay start - Double delayStart = AdjustBridgeUtil.fieldToDouble(delayStartField); - if (delayStart != null) { - adjustConfig.setDelayStart(delayStart); - } - - // User agent - String userAgent = AdjustBridgeUtil.fieldToString(userAgentField); - if (userAgent != null) { - adjustConfig.setUserAgent(userAgent); - } - - // App secret - Long secretId = AdjustBridgeUtil.fieldToLong(secretIdField); - Long info1 = AdjustBridgeUtil.fieldToLong(info1Field); - Long info2 = AdjustBridgeUtil.fieldToLong(info2Field); - Long info3 = AdjustBridgeUtil.fieldToLong(info3Field); - Long info4 = AdjustBridgeUtil.fieldToLong(info4Field); - if (secretId != null && info1 != null && info2 != null && info3 != null && info4 != null) { - adjustConfig.setAppSecret(secretId, info1, info2, info3, info4); - } - - // Check Pixel Default Event Token - String fbPixelDefaultEventToken = AdjustBridgeUtil.fieldToString(fbPixelDefaultEventTokenField); - if (fbPixelDefaultEventToken != null && this.facebookSDKJSInterface != null) { - this.facebookSDKJSInterface.setDefaultEventToken(fbPixelDefaultEventToken); - } - - // Add Pixel mappings - try { - String[] fbPixelMapping = AdjustBridgeUtil.jsonArrayToArray((JSONArray)fbPixelMappingField); - if (fbPixelMapping != null && this.facebookSDKJSInterface != null) { - for (int i = 0; i < fbPixelMapping.length; i += 2) { - String key = fbPixelMapping[i]; - String value = fbPixelMapping[i+1]; - this.facebookSDKJSInterface.addFbPixelEventTokenMapping(key, value); - } - } - } catch (Exception e) { - AdjustFactory.getLogger().error("AdjustBridgeInstance.configureFbPixel: %s", e.getMessage()); - } - - // Set url strategy - String urlStrategy = AdjustBridgeUtil.fieldToString(urlStrategyField); - if (urlStrategy != null) { - adjustConfig.setUrlStrategy(urlStrategy); - } - - // Preinstall tracking - Boolean preinstallTrackingEnabled = AdjustBridgeUtil.fieldToBoolean(preinstallTrackingEnabledField); - if (preinstallTrackingEnabled != null) { - adjustConfig.setPreinstallTrackingEnabled(preinstallTrackingEnabled); - } - - // Preinstall secondary file path - String preinstallFilePath = AdjustBridgeUtil.fieldToString(preinstallFilePathField); - if (preinstallFilePath != null) { - adjustConfig.setPreinstallFilePath(preinstallFilePath); - } - - // PlayStore Kids app - Boolean playStoreKidsAppEnabled = AdjustBridgeUtil.fieldToBoolean(playStoreKidsAppEnabledField); - if (playStoreKidsAppEnabled != null) { - adjustConfig.setPlayStoreKidsAppEnabled(playStoreKidsAppEnabled); - } - - // Coppa compliant - Boolean coppaCompliantEnabled = AdjustBridgeUtil.fieldToBoolean(coppaCompliantEnabledField); - if (coppaCompliantEnabled != null) { - adjustConfig.setCoppaCompliantEnabled(coppaCompliantEnabled); - } - - // Final attribution config - Boolean finalAttributionEnabled = AdjustBridgeUtil.fieldToBoolean(finalAttributionEnabledField); - if (finalAttributionEnabled != null) { - adjustConfig.setFinalAttributionEnabled(finalAttributionEnabled); - } - - // FB App ID - String fbAppId = AdjustBridgeUtil.fieldToString(fbAppIdField); - if (fbAppId != null) { - adjustConfig.setFbAppId(fbAppId); - } - - // read device info once - Boolean readDeviceInfoOnceEnabled = AdjustBridgeUtil.fieldToBoolean(readDeviceInfoOnceEnabledField); - if (readDeviceInfoOnceEnabled != null) { - adjustConfig.setReadDeviceInfoOnceEnabled(readDeviceInfoOnceEnabled); - } - - // Manually call onResume() because web view initialisation will happen a bit delayed. - // With this delay, it will miss lifecycle callback onResume() initial firing. - Adjust.onCreate(adjustConfig); - Adjust.onResume(); - - isInitialized = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - application.registerActivityLifecycleCallbacks(new AdjustLifecycleCallbacks()); - } - } catch (Exception e) { - AdjustFactory.getLogger().error("AdjustBridgeInstance onCreate: %s", e.getMessage()); - } - } - - @JavascriptInterface - public void trackEvent(String adjustEventString) { - if (!isInitialized()) { - return; - } - - try { - JSONObject jsonAdjustEvent = new JSONObject(adjustEventString); - - Object eventTokenField = jsonAdjustEvent.get("eventToken"); - Object revenueField = jsonAdjustEvent.get("revenue"); - Object currencyField = jsonAdjustEvent.get("currency"); - Object callbackParametersField = jsonAdjustEvent.get("callbackParameters"); - Object partnerParametersField = jsonAdjustEvent.get("partnerParameters"); - Object orderIdField = jsonAdjustEvent.get("orderId"); - Object callbackIdField = jsonAdjustEvent.get("callbackId"); - - String eventToken = AdjustBridgeUtil.fieldToString(eventTokenField); - AdjustEvent adjustEvent = new AdjustEvent(eventToken); - - if (!adjustEvent.isValid()) { - return; - } - - // Revenue - Double revenue = AdjustBridgeUtil.fieldToDouble(revenueField); - String currency = AdjustBridgeUtil.fieldToString(currencyField); - if (revenue != null && currency != null) { - adjustEvent.setRevenue(revenue, currency); - } - - // Callback parameters - String[] callbackParameters = AdjustBridgeUtil.jsonArrayToArray((JSONArray)callbackParametersField); - if (callbackParameters != null) { - for (int i = 0; i < callbackParameters.length; i += 2) { - String key = callbackParameters[i]; - String value = callbackParameters[i+1]; - adjustEvent.addCallbackParameter(key, value); - } - } - - // Partner parameters - String[] partnerParameters = AdjustBridgeUtil.jsonArrayToArray((JSONArray)partnerParametersField); - if (partnerParameters != null) { - for (int i = 0; i < partnerParameters.length; i += 2) { - String key = partnerParameters[i]; - String value = partnerParameters[i+1]; - adjustEvent.addPartnerParameter(key, value); - } - } - - // Revenue deduplication - String orderId = AdjustBridgeUtil.fieldToString(orderIdField); - if (orderId != null) { - adjustEvent.setOrderId(orderId); - } - - // Callback id - String callbackId = AdjustBridgeUtil.fieldToString(callbackIdField); - if (callbackId != null) { - adjustEvent.setCallbackId(callbackId); - } - - // Track event - Adjust.trackEvent(adjustEvent); - } catch (Exception e) { - AdjustFactory.getLogger().error("AdjustBridgeInstance trackEvent: %s", e.getMessage()); - } - } - - @JavascriptInterface - public void trackAdRevenue(final String source, final String payload) { - try { - // payload JSON string is URL encoded - String decodedPayload = URLDecoder.decode(payload, "UTF-8"); - JSONObject jsonPayload = new JSONObject(decodedPayload); - Adjust.trackAdRevenue(source, jsonPayload); - } catch (JSONException je) { - AdjustFactory.getLogger().debug("Ad revenue payload does not seem to be a valid JSON string"); - } catch (UnsupportedEncodingException ue) { - AdjustFactory.getLogger().debug("Unable to URL decode given JSON string"); - } - } - - @JavascriptInterface - public void onResume() { - if (!isInitialized()) { - return; - } - Adjust.onResume(); - } - - @JavascriptInterface - public void onPause() { - if (!isInitialized()) { - return; - } - Adjust.onPause(); - } - - @JavascriptInterface - public void setEnabled(String isEnabledString) { - if (!isInitialized()) { - return; - } - Boolean isEnabled = AdjustBridgeUtil.fieldToBoolean(isEnabledString); - if (isEnabled != null) { - Adjust.setEnabled(isEnabled); - } - } - - @JavascriptInterface - public void isEnabled(String callback) { - if (!isInitialized()) { - return; - } - boolean isEnabled = Adjust.isEnabled(); - AdjustBridgeUtil.execSingleValueCallback(webView, callback, String.valueOf(isEnabled)); - } - - @JavascriptInterface - public boolean isEnabled() { - if (!isInitialized()) { - return false; - } - return Adjust.isEnabled(); - } - - @JavascriptInterface - public void appWillOpenUrl(String deeplinkString) { - if (!isInitialized()) { - return; - } - Uri deeplink = null; - if (deeplinkString != null) { - deeplink = Uri.parse(deeplinkString); - } - Adjust.appWillOpenUrl(deeplink, application.getApplicationContext()); - } - - @JavascriptInterface - public void setReferrer(String referrer) { - if (!isInitialized()) { - return; - } - Adjust.setReferrer(referrer, application.getApplicationContext()); - } - - @JavascriptInterface - public void setOfflineMode(String isOfflineString) { - if (!isInitialized()) { - return; - } - Boolean isOffline = AdjustBridgeUtil.fieldToBoolean(isOfflineString); - if (isOffline != null) { - Adjust.setOfflineMode(isOffline); - } - } - - @JavascriptInterface - public void sendFirstPackages() { - if (!isInitialized()) { - return; - } - Adjust.sendFirstPackages(); - } - - @JavascriptInterface - public void addSessionCallbackParameter(String key, String value) { - if (!isInitialized()) { - return; - } - Adjust.addSessionCallbackParameter(key, value); - } - - @JavascriptInterface - public void addSessionPartnerParameter(String key, String value) { - if (!isInitialized()) { - return; - } - Adjust.addSessionPartnerParameter(key, value); - } - - @JavascriptInterface - public void removeSessionCallbackParameter(String key) { - if (!isInitialized()) { - return; - } - Adjust.removeSessionCallbackParameter(key); - } - - @JavascriptInterface - public void removeSessionPartnerParameter(String key) { - if (!isInitialized()) { - return; - } - Adjust.removeSessionPartnerParameter(key); - } - - @JavascriptInterface - public void resetSessionCallbackParameters() { - if (!isInitialized()) { - return; - } - Adjust.resetSessionCallbackParameters(); - } - - @JavascriptInterface - public void resetSessionPartnerParameters() { - if (!isInitialized()) { - return; - } - Adjust.resetSessionPartnerParameters(); - } - - @JavascriptInterface - public void setPushToken(String pushToken) { - if (!isInitialized()) { - return; - } - - Adjust.setPushToken(pushToken, application.getApplicationContext()); - } - - @JavascriptInterface - public void gdprForgetMe() { - if (!isInitialized()) { - return; - } - Adjust.gdprForgetMe(application.getApplicationContext()); - } - - @JavascriptInterface - public void disableThirdPartySharing() { - if (!isInitialized()) { - return; - } - Adjust.disableThirdPartySharing(application.getApplicationContext()); - } - - @JavascriptInterface - public void trackThirdPartySharing(String adjustThirdPartySharingString) { - if (!isInitialized()) { - return; - } - - try { - JSONObject jsonAdjustThirdPartySharing = new JSONObject(adjustThirdPartySharingString); - - Object isEnabledField = - jsonAdjustThirdPartySharing.get("isEnabled"); - Object granularOptionsField = jsonAdjustThirdPartySharing.get("granularOptions"); - Object partnerSharingSettingsField = jsonAdjustThirdPartySharing.get("partnerSharingSettings"); - - Boolean isEnabled = AdjustBridgeUtil.fieldToBoolean(isEnabledField); - - AdjustThirdPartySharing adjustThirdPartySharing = - new AdjustThirdPartySharing(isEnabled); - - // Granular options - String[] granularOptions = - AdjustBridgeUtil.jsonArrayToArray((JSONArray)granularOptionsField); - if (granularOptions != null) { - for (int i = 0; i < granularOptions.length; i += 3) { - String partnerName = granularOptions[i]; - String key = granularOptions[i + 1]; - String value = granularOptions[i + 2]; - adjustThirdPartySharing.addGranularOption(partnerName, key, value); - } - } - - // Partner sharing settings - String[] partnerSharingSettings = - AdjustBridgeUtil.jsonArrayToArray((JSONArray)partnerSharingSettingsField); - if (partnerSharingSettings != null) { - for (int i = 0; i < partnerSharingSettings.length; i += 3) { - String partnerName = partnerSharingSettings[i]; - String key = partnerSharingSettings[i + 1]; - Boolean value = AdjustBridgeUtil.fieldToBoolean(partnerSharingSettings[i + 2]); - if (value != null) { - adjustThirdPartySharing.addPartnerSharingSetting(partnerName, key, value); - } else { - AdjustFactory.getLogger().error("Cannot add partner sharing setting with non boolean value"); - } - } - } - - // Track ThirdPartySharing - Adjust.trackThirdPartySharing(adjustThirdPartySharing); - } catch (Exception e) { - AdjustFactory.getLogger().error( - "AdjustBridgeInstance trackThirdPartySharing: %s", e.getMessage()); - } - } - - @JavascriptInterface - public void trackMeasurementConsent(String consentMeasurementString) { - if (!isInitialized()) { - return; - } - Boolean consentMeasurement = AdjustBridgeUtil.fieldToBoolean(consentMeasurementString); - if (consentMeasurement != null) { - Adjust.trackMeasurementConsent(consentMeasurement); - } - } - - @JavascriptInterface - public void getGoogleAdId(final String callback) { - if (!isInitialized()) { - return; - } - Adjust.getGoogleAdId(application.getApplicationContext(), new OnDeviceIdsRead() { - @Override - public void onGoogleAdIdRead(String googleAdId) { - AdjustBridgeUtil.execSingleValueCallback(webView, callback, googleAdId); - } - }); - } - - @JavascriptInterface - public String getAmazonAdId() { - if (!isInitialized()) { - return null; - } - return Adjust.getAmazonAdId(application.getApplicationContext()); - } - - @JavascriptInterface - public String getAdid() { - if (!isInitialized()) { - return null; - } - return Adjust.getAdid(); - } - - @JavascriptInterface - public void getAttribution(final String callback) { - if (!isInitialized()) { - return; - } - AdjustAttribution attribution = Adjust.getAttribution(); - AdjustBridgeUtil.execAttributionCallbackCommand(webView, callback, attribution); - } - - @JavascriptInterface - public String getSdkVersion() { - return Adjust.getSdkVersion(); - } - - @JavascriptInterface - public void fbPixelEvent(String pixelId, String event_name, String jsonString) { - this.facebookSDKJSInterface.sendEvent(pixelId, event_name, jsonString); - } - - @JavascriptInterface - public void teardown() { - isInitialized = false; - shouldDeferredDeeplinkBeLaunched = true; - } - - public void setWebView(WebView webView) { - this.webView = webView; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - webView.addJavascriptInterface(this, JAVASCRIPT_INTERFACE_NAME); - } - } - - public void setApplicationContext(Application application) { - this.application = application; - } - - public void unregister() { - if (!isInitialized()) { - return; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - this.webView.removeJavascriptInterface(JAVASCRIPT_INTERFACE_NAME); - } - - unregisterFacebookSDKJSInterface(); - - application = null; - webView = null; - isInitialized = false; - } - - public void unregisterFacebookSDKJSInterface() { - if (!isInitialized()) { - return; - } - - if (this.facebookSDKJSInterface == null) { - return; - } - - String fbApplicationId = FacebookSDKJSInterface.getApplicationId(application.getApplicationContext()); - if (fbApplicationId == null) { - return; - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - this.webView.removeJavascriptInterface(FB_JAVASCRIPT_INTERFACE_NAME_PREFIX + fbApplicationId); - } - - this.facebookSDKJSInterface = null; - } -} diff --git a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java b/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java deleted file mode 100644 index da9a6a653..000000000 --- a/Adjust/sdk-plugin-webbridge/src/main/java/com/adjust/sdk/webbridge/AdjustBridgeUtil.java +++ /dev/null @@ -1,284 +0,0 @@ -package com.adjust.sdk.webbridge; - -import android.net.Uri; -import android.util.Log; -import android.webkit.WebView; - -import com.adjust.sdk.AdjustAttribution; -import com.adjust.sdk.AdjustEventFailure; -import com.adjust.sdk.AdjustEventSuccess; -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.AdjustSessionFailure; -import com.adjust.sdk.AdjustSessionSuccess; -import com.adjust.sdk.ILogger; -import com.adjust.sdk.network.UtilNetworking; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -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; - -/** - * Created by uerceg on 22/07/16. - */ -public class AdjustBridgeUtil { - public static void sendDeeplinkToWebView(final WebView webView, final Uri deeplink) { - // If web view is initialised, trigger adjust_deeplink method which user should override. - // In this method, the content of the deeplink will be delivered. - if (webView != null) { - webView.post(new Runnable() { - @Override - public void run() { - String command = "javascript:adjust_deeplink('" + deeplink.toString() + "');"; - webView.loadUrl(command); - } - }); - } - } - - public static String fieldToString(Object field) { - if (field == null) { - return null; - } - - String fieldString = field.toString(); - if (fieldString.equals("null")) { - return null; - } - - return fieldString; - } - - public static Boolean fieldToBoolean(Object field) { - if (field == null) { - return null; - } - - String fieldString = field.toString(); - if (fieldString.equalsIgnoreCase("true")) { - return true; - } - if (fieldString.equalsIgnoreCase("false")) { - return false; - } - - return null; - } - - public static Double fieldToDouble(Object field) { - if (field == null) { - return null; - } - - String fieldString = field.toString(); - try { - return Double.parseDouble(fieldString); - } catch (Exception e) { - return null; - } - } - - public static Long fieldToLong(Object field) { - if (field == null) { - return null; - } - - String fieldString = field.toString(); - try { - return Long.parseLong(fieldString); - } catch (Exception e) { - return null; - } - } - - - public static void execAttributionCallbackCommand(final WebView webView, final String commandName, final AdjustAttribution attribution) { - if (webView == null) { - return; - } - if (attribution == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - JSONObject jsonAttribution = new JSONObject(); - try { - jsonAttribution.put("trackerName", attribution.trackerName == null ? JSONObject.NULL : attribution.trackerName); - jsonAttribution.put("trackerToken", attribution.trackerToken == null ? JSONObject.NULL : attribution.trackerToken); - jsonAttribution.put("campaign", attribution.campaign == null ? JSONObject.NULL : attribution.campaign); - jsonAttribution.put("network", attribution.network == null ? JSONObject.NULL : attribution.network); - jsonAttribution.put("creative", attribution.creative == null ? JSONObject.NULL : attribution.creative); - jsonAttribution.put("adgroup", attribution.adgroup == null ? JSONObject.NULL : attribution.adgroup); - jsonAttribution.put("clickLabel", attribution.clickLabel == null ? JSONObject.NULL : attribution.clickLabel); - jsonAttribution.put("adid", attribution.adid == null ? JSONObject.NULL : attribution.adid); - jsonAttribution.put("costType", attribution.costType == null ? JSONObject.NULL : attribution.costType); - jsonAttribution.put("costAmount", attribution.costAmount == null || attribution.costAmount.isNaN() ? 0 : attribution.costAmount); - jsonAttribution.put("costCurrency", attribution.costCurrency == null ? JSONObject.NULL : attribution.costCurrency); - jsonAttribution.put("fbInstallReferrer", attribution.fbInstallReferrer == null ? JSONObject.NULL : attribution.fbInstallReferrer); - - String command = "javascript:" + commandName + "(" + jsonAttribution.toString() + ");"; - webView.loadUrl(command); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public static void execSessionSuccessCallbackCommand(final WebView webView, final String commandName, final AdjustSessionSuccess sessionSuccess) { - if (webView == null) { - return; - } - if (sessionSuccess == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - JSONObject jsonSessionSuccess = new JSONObject(); - try { - jsonSessionSuccess.put("message", sessionSuccess.message == null ? JSONObject.NULL : sessionSuccess.message); - jsonSessionSuccess.put("adid", sessionSuccess.adid == null ? JSONObject.NULL : sessionSuccess.adid); - jsonSessionSuccess.put("timestamp", sessionSuccess.timestamp == null ? JSONObject.NULL : sessionSuccess.timestamp); - jsonSessionSuccess.put("jsonResponse", sessionSuccess.jsonResponse == null ? JSONObject.NULL : sessionSuccess.jsonResponse); - - String command = "javascript:" + commandName + "(" + jsonSessionSuccess.toString() + ");"; - webView.loadUrl(command); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public static void execSessionFailureCallbackCommand(final WebView webView, final String commandName, final AdjustSessionFailure sessionFailure) { - if (webView == null) { - return; - } - if (sessionFailure == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - JSONObject jsonSessionFailure = new JSONObject(); - try { - jsonSessionFailure.put("message", sessionFailure.message == null ? JSONObject.NULL : sessionFailure.message); - jsonSessionFailure.put("adid", sessionFailure.adid == null ? JSONObject.NULL : sessionFailure.adid); - jsonSessionFailure.put("timestamp", sessionFailure.timestamp == null ? JSONObject.NULL : sessionFailure.timestamp); - jsonSessionFailure.put("willRetry", sessionFailure.willRetry ? String.valueOf(true) : String.valueOf(false)); - jsonSessionFailure.put("jsonResponse", sessionFailure.jsonResponse == null ? JSONObject.NULL : sessionFailure.jsonResponse); - - String command = "javascript:" + commandName + "(" + jsonSessionFailure.toString() + ");"; - webView.loadUrl(command); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public static void execEventSuccessCallbackCommand(final WebView webView, final String commandName, final AdjustEventSuccess eventSuccess) { - if (webView == null) { - return; - } - if (eventSuccess == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - JSONObject jsonEventSuccess = new JSONObject(); - try { - jsonEventSuccess.put("eventToken", eventSuccess.eventToken == null ? JSONObject.NULL : eventSuccess.eventToken); - jsonEventSuccess.put("message", eventSuccess.message == null ? JSONObject.NULL : eventSuccess.message); - jsonEventSuccess.put("adid", eventSuccess.adid == null ? JSONObject.NULL : eventSuccess.adid); - jsonEventSuccess.put("timestamp", eventSuccess.timestamp == null ? JSONObject.NULL : eventSuccess.timestamp); - jsonEventSuccess.put("callbackId", eventSuccess.callbackId == null ? JSONObject.NULL : eventSuccess.callbackId); - jsonEventSuccess.put("jsonResponse", eventSuccess.jsonResponse == null ? JSONObject.NULL : eventSuccess.jsonResponse); - - String command = "javascript:" + commandName + "(" + jsonEventSuccess.toString() + ");"; - webView.loadUrl(command); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public static void execEventFailureCallbackCommand(final WebView webView, final String commandName, final AdjustEventFailure eventFailure) { - if (webView == null) { - return; - } - if (eventFailure == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - JSONObject jsonEventFailure = new JSONObject(); - try { - jsonEventFailure.put("eventToken", eventFailure.eventToken == null ? JSONObject.NULL : eventFailure.eventToken); - jsonEventFailure.put("message", eventFailure.message == null ? JSONObject.NULL : eventFailure.message); - jsonEventFailure.put("adid", eventFailure.adid == null ? JSONObject.NULL : eventFailure.adid); - jsonEventFailure.put("timestamp", eventFailure.timestamp == null ? JSONObject.NULL : eventFailure.timestamp); - jsonEventFailure.put("willRetry", eventFailure.willRetry ? String.valueOf(true) : String.valueOf(false)); - jsonEventFailure.put("callbackId", eventFailure.callbackId == null ? JSONObject.NULL : eventFailure.callbackId); - jsonEventFailure.put("jsonResponse", eventFailure.jsonResponse == null ? JSONObject.NULL : eventFailure.jsonResponse); - - String command = "javascript:" + commandName + "(" + jsonEventFailure.toString() + ");"; - webView.loadUrl(command); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - public static void execSingleValueCallback(final WebView webView, final String commandName, final String value) { - if (webView == null) { - return; - } - - webView.post(new Runnable() { - @Override - public void run() { - String command = "javascript:" + commandName + "('" + value + "');"; - webView.loadUrl(command); - } - }); - } - - public static String[] jsonArrayToArray(JSONArray jsonArray) throws JSONException { - if (jsonArray != null) { - String[] array = new String[jsonArray.length()]; - for (int i = 0; i < jsonArray.length(); i++) { - array[i] = jsonArray.get(i).toString(); - } - return array; - } - return null; - } - - public static ILogger getLogger() { - return AdjustFactory.getLogger(); - } -} diff --git a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java b/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java deleted file mode 100644 index 1690a1983..000000000 --- a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/AdjustXiaomiReferrer.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.adjust.sdk.xiaomi; - -import android.content.Context; - -public class AdjustXiaomiReferrer { - - static boolean shouldReadXiaomiReferrer = true; - - public static void readXiaomiReferrer(Context context) { - shouldReadXiaomiReferrer = true; - } - - public static void doNotReadXiaomiReferrer() { - shouldReadXiaomiReferrer = false; - } -} diff --git a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java b/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java deleted file mode 100644 index 35f071b6f..000000000 --- a/Adjust/sdk-plugin-xiaomi-referrer/src/main/java/com/adjust/sdk/xiaomi/Util.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.adjust.sdk.xiaomi; - -import android.content.Context; - -import com.adjust.sdk.ILogger; -import com.adjust.sdk.ReferrerDetails; -import com.miui.referrer.api.GetAppsReferrerDetails; - -public class Util { - public synchronized static ReferrerDetails getXiaomiInstallReferrerDetails(Context context, ILogger logger) { - if (!AdjustXiaomiReferrer.shouldReadXiaomiReferrer) { - return null; - } - - GetAppsReferrerDetails getAppsReferrerDetails = XiaomiReferrerClient.getReferrer(context, logger, 3000); - if (getAppsReferrerDetails == null) { - return null; - } - - return new ReferrerDetails(getAppsReferrerDetails.getInstallReferrer(), - getAppsReferrerDetails.getReferrerClickTimestampSeconds(), - getAppsReferrerDetails.getInstallBeginTimestampSeconds(), - getAppsReferrerDetails.getReferrerClickTimestampServerSeconds(), - getAppsReferrerDetails.getInstallBeginTimestampServerSeconds(), - getAppsReferrerDetails.getInstallVersion(), null, null); - } -} diff --git a/Adjust/settings.gradle b/Adjust/settings.gradle index cbec02925..9fc1cffee 100644 --- a/Adjust/settings.gradle +++ b/Adjust/settings.gradle @@ -1,3 +1,25 @@ -include ':sdk-core', ':sdk-plugin-webbridge', ':sdk-plugin-oaid', ':sdk-plugin-sociomantic', ':sdk-plugin-trademob', ':sdk-plugin-imei', ':sdk-plugin-criteo', ':sdk-plugin-xiaomi-referrer', ':sdk-plugin-samsung-referrer', ':sdk-plugin-vivo-referrer', ':sdk-plugin-samsung-clouddev' -include ':test-options', ':test-unit', ':test-library', ':test-app-core', ':test-kotlin', ':test-app-webbridge' -include ':example-app-java', ':example-app-kotlin', ':example-app-tv', ':example-app-webbridge', ':example-app-fbpixel', ':example-app-keyboard' +include ':sdk-core' + +include ':plugins:sdk-plugin-webbridge' +include ':plugins:sdk-plugin-oaid' +include ':plugins:sdk-plugin-imei' +include ':plugins:sdk-plugin-xiaomi-referrer' +include ':plugins:sdk-plugin-samsung-referrer' +include ':plugins:sdk-plugin-vivo-referrer' +include ':plugins:sdk-plugin-samsung-clouddev' +include ':plugins:sdk-plugin-huawei-referrer' +include ':plugins:sdk-plugin-meta-referrer' +include ':plugins:sdk-plugin-google-lvl' + +include ':tests:test-options' +include ':tests:test-library' +include ':tests:test-app-core' +include ':tests:test-app-webbridge' + +include ':examples:example-app-java' +include ':examples:example-app-kotlin' +include ':examples:example-app-tv' +include ':examples:example-app-webbridge' +include ':examples:example-app-fbpixel' +include ':examples:example-app-keyboard' + diff --git a/Adjust/test-app-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java b/Adjust/test-app-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java deleted file mode 100644 index 020b2e22e..000000000 --- a/Adjust/test-app-webbridge/src/test/java/com/example/testappwebbridge/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.testappwebbridge; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/Adjust/test-kotlin/.gitignore b/Adjust/test-kotlin/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/Adjust/test-kotlin/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/Adjust/test-kotlin/build.gradle b/Adjust/test-kotlin/build.gradle deleted file mode 100644 index eee979035..000000000 --- a/Adjust/test-kotlin/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -android { - compileSdk 34 - - defaultConfig { - applicationId "com.adjust.sdk.test" - targetSdkVersion 34 - minSdkVersion 9 - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - namespace 'com.adjust.sdk.test' -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - - testImplementation project(path: ':sdk-core') -} diff --git a/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt b/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt deleted file mode 100644 index 835fa8f15..000000000 --- a/Adjust/test-kotlin/src/androidTest/java/com/adjust/sdk/test/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.adjust.sdk.test - -import android.support.test.InstrumentationRegistry -import android.support.test.runner.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getTargetContext() - assertEquals("com.adjust.sdk.test", appContext.packageName) - } -} diff --git a/Adjust/test-kotlin/src/main/AndroidManifest.xml b/Adjust/test-kotlin/src/main/AndroidManifest.xml deleted file mode 100644 index bdb1e58ce..000000000 --- a/Adjust/test-kotlin/src/main/AndroidManifest.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt b/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt deleted file mode 100644 index 74176cd4b..000000000 --- a/Adjust/test-kotlin/src/main/java/com/adjust/sdk/test/MainActivity.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.adjust.sdk.test - -import android.app.Activity -import android.os.Bundle - -class MainActivity : Activity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } -} diff --git a/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 1f6bb2906..000000000 --- a/Adjust/test-kotlin/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml b/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 0d025f9bf..000000000 --- a/Adjust/test-kotlin/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index eca70cfe5..000000000 --- a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index eca70cfe5..000000000 --- a/Adjust/test-kotlin/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 898f3ed59..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index dffca3601..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 64ba76f75..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index dae5e0823..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index e5ed46597..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 14ed0af35..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index b0907cac3..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index d8ae03154..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 2c18de9e6..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index beed3cdd2..000000000 Binary files a/Adjust/test-kotlin/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/Adjust/test-kotlin/src/main/res/values/colors.xml b/Adjust/test-kotlin/src/main/res/values/colors.xml deleted file mode 100644 index 69b22338c..000000000 --- a/Adjust/test-kotlin/src/main/res/values/colors.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - #008577 - #00574B - #D81B60 - diff --git a/Adjust/test-kotlin/src/main/res/values/strings.xml b/Adjust/test-kotlin/src/main/res/values/strings.xml deleted file mode 100644 index 7a6b55c64..000000000 --- a/Adjust/test-kotlin/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - test-unit-kotlin - diff --git a/Adjust/test-kotlin/src/main/res/values/styles.xml b/Adjust/test-kotlin/src/main/res/values/styles.xml deleted file mode 100644 index e84bc5ec1..000000000 --- a/Adjust/test-kotlin/src/main/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt b/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt deleted file mode 100644 index 20d6d63c9..000000000 --- a/Adjust/test-kotlin/src/test/java/com/adjust/sdk/test/SchedulerTest.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.adjust.sdk.test - -import com.adjust.sdk.scheduler.* -import org.junit.Assert -import org.junit.Test -import java.util.concurrent.TimeUnit - -class SchedulerTest { - @Test - fun threadExecutor_submitsVarious_executesInOrder() { - val threadExecutor: ThreadExecutor = SingleThreadCachedScheduler("s") - var s = ""; - threadExecutor.submit { s += "a" } - threadExecutor.submit { s += "b" } - threadExecutor.submit { s += "c" } - Thread.sleep(1000) - Assert.assertEquals("abc", s) - } - - @Test - fun threadScheduler_schedulesVariousDelayed_executesInDelayedOrder() { - val threadScheduler: ThreadScheduler = SingleThreadCachedScheduler("s") - var s = ""; - threadScheduler.submit { s += "a" } - threadScheduler.schedule ({ s += "e"}, 500) - threadScheduler.submit { s += "b" } - threadScheduler.schedule ({ s += "d"}, 250) - threadScheduler.submit { s += "c" } - Thread.sleep(1000) - Assert.assertEquals("abcde", s) - } - - @Test - fun futureScheduler_ScheduleAndWaitWithKeepAlive() { - // arrange - val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) - - // act - var s = ""; - val scheduledFuture = futureScheduler.scheduleFuture({ s += "a" }, 500) - - val withDelay = scheduledFuture.getDelay(TimeUnit.MILLISECONDS) - val isNotDone = scheduledFuture.isDone - val isNotCanceledBefore = scheduledFuture.isCancelled - // wait for finish - scheduledFuture.get() - - val noDelay = scheduledFuture.getDelay(TimeUnit.MILLISECONDS) - val isDone = scheduledFuture.isDone - val isNotCanceledBeforeAfter = scheduledFuture.isCancelled - - // assert - // before finish - Assert.assertTrue(withDelay > 0L) - Assert.assertTrue(withDelay < 500L) - Assert.assertTrue(noDelay <= 0L) - Assert.assertFalse(isNotDone) - - // after finish - Assert.assertEquals("a", s) - Assert.assertTrue(isDone) - Assert.assertFalse(isNotCanceledBefore) - Assert.assertFalse(isNotCanceledBeforeAfter) - } - - @Test - fun futureScheduler_ScheduleAndCancelWithKeepAlive() { - // arrange - val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) - - // act - var s = ""; - val scheduledFuture = futureScheduler.scheduleFuture({ s += "a" }, 500) - - // cancel - scheduledFuture.cancel(false) - - val isDone = scheduledFuture.isDone - val isCancelled = scheduledFuture.isCancelled - - // assert - Assert.assertEquals("", s) - Assert.assertTrue(isDone) - Assert.assertTrue(isCancelled) - } - - @Test - fun futureScheduler_ScheduleWithFixedDelayWithKeepAlive() { - // arrange - val futureScheduler: FutureScheduler = SingleThreadFutureScheduler("s", true) - - // act - var s = ""; - val scheduledFuture = futureScheduler.scheduleFutureWithFixedDelay({ s += "a" }, 500, 500) - - Thread.sleep(650) - val s1 = s - Thread.sleep(650) - - // assert - Assert.assertEquals("a", s1) - Assert.assertEquals("aa", s) - } - -} \ No newline at end of file diff --git a/Adjust/test-library/.gitignore b/Adjust/test-library/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/Adjust/test-library/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/Adjust/test-library/src/main/AndroidManifest.xml b/Adjust/test-library/src/main/AndroidManifest.xml deleted file mode 100644 index 94cbbcfc3..000000000 --- a/Adjust/test-library/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java b/Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java deleted file mode 100644 index ab622f9b9..000000000 --- a/Adjust/test-library/src/main/java/com/adjust/test/UtilsNetworking.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.adjust.test; - -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.test.Constants.ONE_MINUTE; -import static com.adjust.test.Utils.debug; -import static com.adjust.test.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/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java b/Adjust/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java deleted file mode 100644 index ab4d13ced..000000000 --- a/Adjust/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.adjust.test_options; - -import android.util.Log; - -import com.adjust.sdk.AdjustFactory; -import com.adjust.sdk.network.UtilNetworking; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -public class TestConnectionOptions { - public static void setTestConnectionOptions() { - AdjustFactory.setConnectionOptions(new UtilNetworking.IConnectionOptions() { - @Override - public void applyConnectionOptions(HttpsURLConnection connection, String clientSdk) { - UtilNetworking.IConnectionOptions defaultConnectionOption = - UtilNetworking.createDefaultConnectionOptions(); - defaultConnectionOption.applyConnectionOptions(connection, clientSdk); - - try { - TLSSocketFactory tlsSocketFactory = - new TLSSocketFactory( - TestConnectionOptions.generateTrustAllCerts(), - new java.security.SecureRandom()); - connection.setSSLSocketFactory(tlsSocketFactory); - connection.setHostnameVerifier( - TestConnectionOptions.generateHostnameVerifier()); - } catch (Exception e) { - Log.e("TestOptions","connectionOptions error " + e.getMessage()); - } - } - }); - } - - private static TrustManager[] generateTrustAllCerts() { - return new TrustManager[]{ - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - Log.d("TestApp", "getAcceptedIssuers"); - return null; - } - - public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, - final String authType) - { - Log.d("TestApp", "checkClientTrusted"); - } - - public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, - final String authType) - { - Log.d("TestApp", "checkServerTrusted"); - } - } - }; - } - - private static HostnameVerifier generateHostnameVerifier() { - return new HostnameVerifier() { - @Override - public boolean verify(final String hostname, final SSLSession session) { - Log.d("TestApp", "HostnameVerifier verify"); - return true; - } - }; - } - -} diff --git a/Adjust/test-unit/build.gradle b/Adjust/test-unit/build.gradle deleted file mode 100644 index c784750b6..000000000 --- a/Adjust/test-unit/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdk 34 - - defaultConfig { - minSdkVersion 9 - targetSdkVersion 34 - } - defaultConfig { - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - namespace 'com.adjust.sdk.test' -} - -repositories { - mavenCentral() -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31' - androidTestImplementation 'androidx.test:runner:1.4.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' - - testImplementation project(path: ':sdk-core') -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ApplicationTest.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ApplicationTest.java deleted file mode 100644 index 77072ab2c..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adjust.sdk; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - * Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/AssertUtil.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/AssertUtil.java deleted file mode 100644 index b3a637dcf..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/AssertUtil.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.adjust.sdk; - -import android.net.Uri; - -import junit.framework.Assert; - -import java.util.Locale; - -import static com.adjust.sdk.LogLevel.ASSERT; -import static com.adjust.sdk.LogLevel.DEBUG; -import static com.adjust.sdk.LogLevel.ERROR; -import static com.adjust.sdk.LogLevel.INFO; -import static com.adjust.sdk.LogLevel.VERBOSE; -import static com.adjust.sdk.LogLevel.WARN; - -/** - * Created by pfms on 09/01/15. - */ -public class AssertUtil { - private MockLogger mockLogger; - - public AssertUtil(MockLogger mockLogger) { - this.mockLogger = mockLogger; - } - - public String test(String message, Object... parameters) { - MockLogger.ContainsReturn containsTestMessage = mockLogger.containsTestMessage(String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsTestMessage.containsMessage); - return containsTestMessage.matchMessage; - } - - public String verbose(String message, Object... parameters) { - MockLogger.ContainsReturn containsVerboseMessage = mockLogger.containsMessage(VERBOSE, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsVerboseMessage.containsMessage); - return containsVerboseMessage.matchMessage; - } - - public String debug(String message, Object... parameters) { - MockLogger.ContainsReturn containsDebugMessage = mockLogger.containsMessage(DEBUG, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsDebugMessage.containsMessage); - return containsDebugMessage.matchMessage; - } - - public String info(String message, Object... parameters) { - MockLogger.ContainsReturn containsInfoMessage = mockLogger.containsMessage(INFO, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsInfoMessage.containsMessage); - return containsInfoMessage.matchMessage; - } - - public String warn(String message, Object... parameters) { - MockLogger.ContainsReturn containsWarnMessage = mockLogger.containsMessage(WARN, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsWarnMessage.containsMessage); - return containsWarnMessage.matchMessage; - } - - public String error(String message, Object... parameters) { - MockLogger.ContainsReturn containsErrorMessage = mockLogger.containsMessage(ERROR, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsErrorMessage.containsMessage); - return containsErrorMessage.matchMessage; - } - - public String Assert(String message, Object... parameters) { - MockLogger.ContainsReturn containsAssertMessage = mockLogger.containsMessage(ASSERT, String.format(Locale.US, message, parameters)); - Assert.assertTrue(mockLogger.toString(), containsAssertMessage.containsMessage); - return containsAssertMessage.matchMessage; - } - - public void notInTest(String message, Object... parameters) { - MockLogger.ContainsReturn containsTestMessage = mockLogger.containsTestMessage(String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsTestMessage.containsMessage); - } - - public void notInVerbose(String message, Object... parameters) { - MockLogger.ContainsReturn containsVerboseMessage = mockLogger.containsMessage(VERBOSE, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsVerboseMessage.containsMessage); - } - - public void notInDebug(String message, Object... parameters) { - MockLogger.ContainsReturn containsDebugMessage = mockLogger.containsMessage(DEBUG, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsDebugMessage.containsMessage); - } - - public void notInInfo(String message, Object... parameters) { - MockLogger.ContainsReturn containsInfoMessage = mockLogger.containsMessage(INFO, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsInfoMessage.containsMessage); - } - - public void notInWarn(String message, Object... parameters) { - MockLogger.ContainsReturn containsWarnMessage = mockLogger.containsMessage(WARN, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsWarnMessage.containsMessage); - } - - public void notInError(String message, Object... parameters) { - MockLogger.ContainsReturn containsErrorMessage = mockLogger.containsMessage(ERROR, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsErrorMessage.containsMessage); - } - - public void notInAssert(String message, Object... parameters) { - MockLogger.ContainsReturn containsAssertMessage = mockLogger.containsMessage(ASSERT, String.format(Locale.US, message, parameters)); - Assert.assertFalse(mockLogger.toString(), containsAssertMessage.containsMessage); - } - - public void isNull(Object object) { - Assert.assertNull(mockLogger.toString(), object); - } - - public void isNotNull(Object object) { - Assert.assertNotNull(mockLogger.toString(), object); - } - - public void isTrue(boolean value) { - Assert.assertTrue(mockLogger.toString(), value); - } - - public void isFalse(boolean value) { - Assert.assertFalse(mockLogger.toString(), value); - } - - public void isEqual(String expected, String actual) { - Assert.assertEquals(mockLogger.toString(), expected, actual); - } - - public void isEqual(boolean expected, boolean actual) { - Assert.assertEquals(mockLogger.toString(), expected, actual); - } - - public void isEqual(int expected, int actual) { - Assert.assertEquals(mockLogger.toString(), expected, actual); - } - - public void isEqual(Uri expected, Uri actual) { - Assert.assertEquals(mockLogger.toString(), expected, actual); - } - - public void fail() { - Assert.fail(mockLogger.toString()); - } - - public void fail(String extraMessage) { - Assert.fail(extraMessage + "\n" + mockLogger.toString()); - } - -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java deleted file mode 100644 index 84662e9ef..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockActivityHandler.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.adjust.sdk; - -import android.net.Uri; - - -/** - * Created by pfms on 09/01/15. - */ -public class MockActivityHandler implements IActivityHandler { - private MockLogger testLogger; - private String prefix = "ActivityHandler "; - private AdjustConfig config; - private ResponseData lastResponseData; - - public MockActivityHandler(MockLogger testLogger) { - this.testLogger = testLogger; - } - - @Override - public void init(AdjustConfig config) { - testLogger.test(prefix + "init"); - this.config = config; - } - - @Override - public void onResume() { - testLogger.test(prefix + "onResume"); - } - - @Override - public void onPause() { - testLogger.test(prefix + "onPause"); - } - - @Override - public void trackEvent(AdjustEvent event) { - testLogger.test(prefix + "trackEvent, " + event); - } - - @Override - public void finishedTrackingActivity(ResponseData responseData) { - testLogger.test(prefix + "finishedTrackingActivity, " + responseData); - this.lastResponseData = responseData; - } - - @Override - public void setEnabled(boolean enabled) { - testLogger.test(prefix + "setEnabled, " + enabled); - } - - @Override - public boolean isEnabled() { - testLogger.test(prefix + "isEnabled"); - return false; - } - - @Override - public void readOpenUrl(Uri url, long clickTime) { - testLogger.test(prefix + "readOpenUrl, " + url + ". ClickTime, " + clickTime); - } - - @Override - public boolean updateAttributionI(AdjustAttribution attribution) { - testLogger.test(prefix + "updateAttributionI, " + attribution); - return false; - } - - @Override - public void launchEventResponseTasks(EventResponseData eventResponseData) { - testLogger.test(prefix + "launchEventResponseTasks, " + eventResponseData); - this.lastResponseData = eventResponseData; - } - - @Override - public void launchSessionResponseTasks(SessionResponseData sessionResponseData) { - testLogger.test(prefix + "launchSessionResponseTasks, " + sessionResponseData); - this.lastResponseData = sessionResponseData; - } - - @Override - public void launchSdkClickResponseTasks(SdkClickResponseData sdkClickResponseData) { - testLogger.test(prefix + "launchSdkClickResponseTasks, " + sdkClickResponseData); - this.lastResponseData = sdkClickResponseData; - } - - @Override - public void launchAttributionResponseTasks(AttributionResponseData attributionResponseData) { - testLogger.test(prefix + "launchAttributionResponseTasks, " + attributionResponseData); - this.lastResponseData = attributionResponseData; - } - - @Override - public void sendReferrer(String referrer, long clickTime) { - testLogger.test(prefix + "sendReferrer, " + referrer + ". ClickTime, " + clickTime); - } - - @Override - public void setOfflineMode(boolean enabled) { - testLogger.test(prefix + "setOfflineMode, " + enabled); - } - - @Override - public void setAskingAttribution(boolean askingAttribution) { - testLogger.test(prefix + "setAskingAttribution, " + askingAttribution); - } - - @Override - public void sendFirstPackages() { - testLogger.test(prefix + "sendFirstPackages"); - } - - @Override - public void addSessionCallbackParameter(String key, String value) { - testLogger.test(prefix + "addSessionCallbackParameter key, " + key + ", value, " + value); - } - - @Override - public void addSessionPartnerParameter(String key, String value) { - testLogger.test(prefix + "addSessionPartnerParameter key, " + key + ", value, " + value); - } - - @Override - public void removeSessionCallbackParameter(String key) { - testLogger.test(prefix + "removeSessionCallbackParameter, " + key); - } - - @Override - public void removeSessionPartnerParameter(String key) { - testLogger.test(prefix + "removeSessionPartnerParameter, " + key); - } - - @Override - public void resetSessionCallbackParameters() { - testLogger.test(prefix + "resetSessionCallbackParameters"); - } - - @Override - public void resetSessionPartnerParameters() { - testLogger.test(prefix + "resetSessionPartnerParameters"); - } - - @Override - public void teardown(boolean deleteState) { - testLogger.test(prefix + "teardown deleteState, " + deleteState); - } - - @Override - public void setPushToken(String token) { - testLogger.test(prefix + "setPushToken token, " + token); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java deleted file mode 100644 index cc4e23c44..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockAttributionHandler.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 09/01/15. - */ -public class MockAttributionHandler implements IAttributionHandler { - private MockLogger testLogger; - private String prefix = "AttributionHandler "; - IActivityHandler activityHandler; - ActivityPackage attributionPackage; - SessionResponseData lastSessionResponseData; - SdkClickResponseData lastSdkClickResponseData; - - public MockAttributionHandler(MockLogger testLogger) { - this.testLogger = testLogger; - } - - @Override - public void init(IActivityHandler activityHandler, - ActivityPackage attributionPackage, - boolean startsSending) { - testLogger.test(prefix + "init, startsSending: " + startsSending); - this.activityHandler = activityHandler; - this.attributionPackage = attributionPackage; - } - - @Override - public void getAttribution() { - testLogger.test(prefix + "getAttribution"); - } - - @Override - public void checkSessionResponse(SessionResponseData sessionResponseData) { - testLogger.test(prefix + "checkSessionResponse"); - - this.lastSessionResponseData = sessionResponseData; - } - - @Override - public void checkSdkClickResponse(SdkClickResponseData sdkClickResponseData) { - testLogger.test(prefix + "checkSdkClickResponse"); - - this.lastSdkClickResponseData = sdkClickResponseData; - } - - @Override - public void pauseSending() { - testLogger.test(prefix + "pauseSending"); - } - - @Override - public void resumeSending() { - testLogger.test(prefix + "resumeSending"); - } - - @Override - public void teardown() { - testLogger.test(prefix + "teardown"); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java deleted file mode 100644 index bcd512adc..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockHttpsURLConnection.java +++ /dev/null @@ -1,366 +0,0 @@ -package com.adjust.sdk; - -import android.os.SystemClock; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.ProtocolException; -import java.net.URL; -import java.nio.charset.Charset; -import java.security.Permission; -import java.security.cert.Certificate; -import java.util.List; -import java.util.Map; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLPeerUnverifiedException; - -/** - * Created by pfms on 20/08/15. - */ -public class MockHttpsURLConnection extends HttpsURLConnection { - - private MockLogger testLogger; - private String prefix = "MockHttpsURLConnection "; - private ByteArrayOutputStream outputStream; - public ResponseType responseType; - public boolean timeout; - public Long waitingTime; - - protected MockHttpsURLConnection(URL url) { - super(url); - } - - public MockHttpsURLConnection(URL url, MockLogger mockLogger) { - this(url); - this.testLogger = mockLogger; - } - - public InputStream getInputStream() throws IOException { - testLogger.test(prefix + "getInputStream, responseType: " + responseType); - - if (timeout) { - SystemClock.sleep(10000); - } - - if (waitingTime != null) { - SystemClock.sleep(waitingTime); - } - - if (responseType == ResponseType.CLIENT_PROTOCOL_EXCEPTION) { - throw new IOException ("testResponseError"); - } else if (responseType == ResponseType.WRONG_JSON) { - return getMockResponse("not a json response"); - } else if (responseType == ResponseType.EMPTY_JSON) { - return getMockResponse("{ }"); - } else if (responseType == ResponseType.MESSAGE) { - return getMockResponse("{ \"message\" : \"response OK\"}"); - } - return null; - } - - public InputStream getErrorStream() { - testLogger.test(prefix + "getErrorStream, responseType: " + responseType); - try { - if (responseType == ResponseType.INTERNAL_SERVER_ERROR) { - return getMockResponse("{ \"message\": \"testResponseError\"}"); - } - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - private InputStream getMockResponse(String response) - throws IOException { - - InputStream stream = new ByteArrayInputStream(response.getBytes(Charset.forName("UTF-8"))); - - return stream; - } - - - public String readRequest() { - String out = null; - try { - out = new String(outputStream.toByteArray(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - testLogger.test("readRequest, UnsupportedEncodingException " + e.getMessage()); - } - return out; - } - - @Override - public void disconnect() { - testLogger.test(prefix + "disconnect"); - } - - @Override - public boolean usingProxy() { - testLogger.test(prefix + "usingProxy"); - return false; - } - - @Override - public void connect() throws IOException { - testLogger.test(prefix + "connect"); - } - - public Permission getPermission() throws IOException { - testLogger.test(prefix + "getPermission"); - return null; - } - - public String getRequestMethod() { - testLogger.test(prefix + "getRequestMethod"); - return null; - } - - public int getResponseCode() throws IOException { - testLogger.test(prefix + "getResponseCode"); - if (responseType == ResponseType.INTERNAL_SERVER_ERROR) { - return HttpsURLConnection.HTTP_INTERNAL_ERROR; - } else { - return HttpsURLConnection.HTTP_OK; - } - } - - public String getResponseMessage() throws IOException { - testLogger.test(prefix + "getResponseMessage"); - return null; - } - - public void setRequestMethod(String method) throws ProtocolException { - testLogger.test(prefix + "setRequestMethod, method " + method); - super.setRequestMethod(method); - } - - public String getContentEncoding() { - testLogger.test(prefix + "getContentEncoding"); - return null; - } - - public boolean getInstanceFollowRedirects() { - testLogger.test(prefix + "getInstanceFollowRedirects"); - return false; - } - - public void setInstanceFollowRedirects(boolean followRedirects) { - testLogger.test(prefix + "setInstanceFollowRedirects, followRedirects " + followRedirects); - } - - public long getHeaderFieldDate(String field, long defaultValue) { - testLogger.test(prefix + "getHeaderFieldDate, field " + field + ", defaultValue " + defaultValue); - return 0; - } - - public void setFixedLengthStreamingMode(long contentLength) { - testLogger.test(prefix + "setFixedLengthStreamingMode, contentLength " + contentLength); - } - - public void setFixedLengthStreamingMode(int contentLength) { - testLogger.test(prefix + "setFixedLengthStreamingMode, contentLength " + contentLength); - } - - public void setChunkedStreamingMode(int chunkLength) { - testLogger.test(prefix + "setChunkedStreamingMode, chunkLength " + chunkLength); - } - - public boolean getAllowUserInteraction() { - testLogger.test(prefix + "getAllowUserInteraction"); - return false; - } - - public Object getContent() throws IOException { - testLogger.test(prefix + "getReferrer"); - return null; - } - - public Object getContent(Class[] types) throws IOException { - testLogger.test(prefix + "getReferrer, types " + types); - return null; - } - - public int getContentLength() { - testLogger.test(prefix + "getContentLength"); - return 0; - } - - public String getContentType() { - testLogger.test(prefix + "getContentLength"); - return null; - } - - public long getDate() { - testLogger.test(prefix + "getDate"); - return 0; - } - - public boolean getDefaultUseCaches() { - testLogger.test(prefix + "getDefaultUseCaches"); - return false; - } - - public boolean getDoInput() { - testLogger.test(prefix + "getDoInput"); - return false; - } - - public boolean getDoOutput() { - testLogger.test(prefix + "getDoOutput"); - return false; - } - - public long getExpiration() { - testLogger.test(prefix + "getExpiration"); - return 0; - } - - public String getHeaderField(int pos) { - testLogger.test(prefix + "getHeaderField, pos " + pos); - return null; - } - - public Map> getHeaderFields() { - testLogger.test(prefix + "getHeaderFields"); - return null; - } - - public Map> getRequestProperties() { - testLogger.test(prefix + "getRequestProperties"); - return null; - } - - public void addRequestProperty(String field, String newValue) { - testLogger.test(prefix + "addRequestProperty, field " + field + ", newValue " + newValue); - } - - public String getHeaderField(String key) { - testLogger.test(prefix + "getHeaderField, key " + key); - return null; - } - - public int getHeaderFieldInt(String field, int defaultValue) { - testLogger.test(prefix + "getHeaderFieldInt, field " + field + ", defaultValue " + defaultValue); - return 0; - } - - public String getHeaderFieldKey(int posn) { - testLogger.test(prefix + "getHeaderFieldKey, " + posn); - return null; - } - - public long getIfModifiedSince() { - testLogger.test(prefix + "getIfModifiedSince"); - return 0; - } - - public long getLastModified() { - testLogger.test(prefix + "getLastModified"); - return 0; - } - - public OutputStream getOutputStream() throws IOException { - testLogger.test(prefix + "getOutputStream"); - outputStream = new ByteArrayOutputStream(); - return outputStream; - } - - public String getRequestProperty(String field) { - testLogger.test(prefix + "getRequestProperty, field " + field); - return null; - } - - public URL getURL() { - testLogger.test(prefix + "getURL"); - return this.url; - } - - public void setURL(URL url) { - testLogger.test(prefix + "setURL, " + url); - - } - - public boolean getUseCaches() { - testLogger.test(prefix + "getUseCaches"); - return false; - } - - public void setAllowUserInteraction(boolean newValue) { - testLogger.test(prefix + "setAllowUserInteraction, newValue " + newValue); - } - - public void setDefaultUseCaches(boolean newValue) { - testLogger.test(prefix + "setDefaultUseCaches, newValue " + newValue); - } - - public void setDoInput(boolean newValue) { - testLogger.test(prefix + "setDoInput, newValue " + newValue); - super.setDoInput(newValue); - } - - public void setDoOutput(boolean newValue) { - testLogger.test(prefix + "setDoOutput, newValue " + newValue); - super.setDoOutput(newValue); - } - - public void setIfModifiedSince(long newValue) { - testLogger.test(prefix + "setIfModifiedSince, newValue " + newValue); - } - - public void setRequestProperty(String field, String newValue) { - testLogger.test(prefix + "setRequestProperty, field " + field + ", newValue " + newValue); - super.setRequestProperty(field, newValue); - } - - public void setUseCaches(boolean newValue) { - testLogger.test(prefix + "setUseCaches, newValue " + newValue); - super.setUseCaches(newValue); - } - - public void setConnectTimeout(int timeoutMillis) { - testLogger.test(prefix + "setConnectTimeout, timeoutMillis " + timeoutMillis); - super.setConnectTimeout(timeoutMillis); - } - - public int getConnectTimeout() { - testLogger.test(prefix + "getConnectTimeout"); - return 0; - } - - public void setReadTimeout(int timeoutMillis) { - testLogger.test(prefix + "setReadTimeout, timeoutMillis " + timeoutMillis); - } - - public int getReadTimeout() { - testLogger.test(prefix + "getReadTimeout"); - return 0; - } - - public String toString() { - testLogger.test(prefix + "toString"); - return null; - } - - @Override - public String getCipherSuite() { - testLogger.test(prefix + "getCipherSuite"); - return null; - } - - @Override - public Certificate[] getLocalCertificates() { - testLogger.test(prefix + "getLocalCertificates"); - return new Certificate[0]; - } - - @Override - public Certificate[] getServerCertificates() throws SSLPeerUnverifiedException { - testLogger.test(prefix + "getServerCertificates"); - return new Certificate[0]; - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockLogger.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockLogger.java deleted file mode 100644 index 18ad6292a..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockLogger.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.adjust.sdk; - -import android.util.Log; -import android.util.SparseArray; - -import com.adjust.sdk.ILogger; -import com.adjust.sdk.LogLevel; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - -import static com.adjust.sdk.Constants.LOGTAG; - -public class MockLogger implements ILogger { - - private StringBuffer logBuffer; - private SparseArray> logMap; - public static final int TEST_LEVEL = 6; - public static final int CHECK_LEVEL = 7; - private long startTime; - private long lastTime; - - public class ContainsReturn { - boolean containsMessage; - String matchMessage; - ContainsReturn(boolean containsMessage, String matchMessage) { - this.containsMessage = containsMessage; - this.matchMessage = matchMessage; - } - } - - public MockLogger() { - reset(); - } - - public void reset() { - startTime = System.currentTimeMillis(); - lastTime = startTime; - - logBuffer = new StringBuffer(); - logMap = new SparseArray>(8); - logMap.put(LogLevel.VERBOSE.getAndroidLogLevel(), new ArrayList()); - logMap.put(LogLevel.DEBUG.getAndroidLogLevel(), new ArrayList()); - logMap.put(LogLevel.INFO.getAndroidLogLevel(), new ArrayList()); - logMap.put(LogLevel.WARN.getAndroidLogLevel(), new ArrayList()); - logMap.put(LogLevel.ERROR.getAndroidLogLevel(), new ArrayList()); - logMap.put(LogLevel.ASSERT.getAndroidLogLevel(), new ArrayList()); - logMap.put(TEST_LEVEL, new ArrayList()); - logMap.put(CHECK_LEVEL, new ArrayList()); - - test("Logger reset"); - } - - @Override - public String toString() { - String logging = logBuffer.toString(); - //Log.v("TestLogger ", logging); - return logging; - } - - @Override - public void setLogLevel(LogLevel logLevel, boolean isProductionEnvironment) { - test("MockLogger setLogLevel: " + logLevel + ", isProductionEnvironment: " + isProductionEnvironment); - } - - @Override - public void setLogLevelString(String logLevelString, boolean isProductionEnvironment) { - test("MockLogger setLogLevelString: " + logLevelString + ", isProductionEnvironment: " + isProductionEnvironment); - } - - private void logMessage(String message, Integer iLoglevel, String messagePrefix, int priority) { - long now = System.currentTimeMillis(); - long milliSecondsPassed = now - startTime; - long lastTimePassed = now - lastTime; - lastTime = now; - - List prefixedList = logMap.get(iLoglevel); - prefixedList.add(message); - - String longMessage = String.format("%d %d %s %s", milliSecondsPassed, lastTimePassed, messagePrefix, message); - Log.println(priority, LOGTAG, longMessage); - - String logBufferMessage = String.format("%s%s", longMessage, System.getProperty("line.separator")); - logBuffer.append(logBufferMessage); - //String sList = Arrays.toString(prefixedList.toArray()); - //String logBufferList = String.format("In %s", sList); - //logBuffer.append(logBufferList); - } - - @Override - public void verbose(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.VERBOSE.getAndroidLogLevel(), - "v", - Log.VERBOSE); - } - - @Override - public void debug(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.DEBUG.getAndroidLogLevel(), - "d", - Log.DEBUG); - } - - @Override - public void info(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.INFO.getAndroidLogLevel(), - "i", - Log.INFO); - } - - @Override - public void warn(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.WARN.getAndroidLogLevel(), - "w", - Log.WARN); - } - - @Override - public void warnInProduction(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.WARN.getAndroidLogLevel(), - "w", - Log.WARN); - } - - @Override - public void error(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.ERROR.getAndroidLogLevel(), - "e", - Log.ERROR); - } - - @Override - public void Assert(String message, Object... parameters) { - logMessage(String.format(Locale.US, message, parameters), - LogLevel.ASSERT.getAndroidLogLevel(), - "a", - Log.ASSERT); - } - - @Override - public void lockLogLevel() { - test("MockLogger lockLogLevel"); - } - - public void test(String message) { - logMessage(message, TEST_LEVEL, "t", Log.VERBOSE); - } - - private void check(String message) { - logMessage(message, CHECK_LEVEL, "c", Log.VERBOSE); - } - - private ContainsReturn mapContainsMessage(int level, String beginsWith) { - ArrayList list = logMap.get(level); - @SuppressWarnings("unchecked") - ArrayList listCopy = new ArrayList(list); - String sList = Arrays.toString(list.toArray()); - for (String log : list) { - listCopy.remove(0); - if (log.startsWith(beginsWith)) { - String foundMessage = String.format(Locale.US, "%s found", log); - //Log.println(Log.ASSERT, LOGTAG, foundMessage); - check(foundMessage); - logMap.put(level, listCopy); - return new ContainsReturn(true, log); - } - } - String notFoundMessage = String.format(Locale.US, "%s is not in %s", beginsWith, sList); - check(notFoundMessage); - //Log.println(Log.ASSERT, LOGTAG, notFoundMessage); - - return new ContainsReturn(false, null); - } - - public ContainsReturn containsMessage(LogLevel level, String beginsWith) { - return mapContainsMessage(level.getAndroidLogLevel(), beginsWith); - } - - public ContainsReturn containsTestMessage(String beginsWith) { - return mapContainsMessage(TEST_LEVEL, beginsWith); - } - - public void printLogMap(int level) { - ArrayList list = logMap.get(level); - String sList = Arrays.toString(list.toArray()); - - String message = String.format(Locale.US, "list level %d: %s", level, sList); - check(message); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java deleted file mode 100644 index 2c9742f40..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockPackageHandler.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; - -import java.util.ArrayList; -import java.util.List; - -public class MockPackageHandler implements IPackageHandler { - private MockLogger testLogger; - private String prefix = "PackageHandler "; - IActivityHandler activityHandler; - List queue; - Context context; - - public MockPackageHandler(MockLogger testLogger) { - this.testLogger = testLogger; - } - - @Override - public void init(IActivityHandler activityHandler, Context context, boolean startsSending) { - testLogger.test(prefix + "init, startsSending: " + startsSending); - this.activityHandler = activityHandler; - this.context = context; - this.queue = new ArrayList(); - } - - @Override - public void addPackage(ActivityPackage pack) { - testLogger.test(prefix + "addPackage"); - queue.add(pack); - } - - @Override - public void sendFirstPackage() { - testLogger.test(prefix + "sendFirstPackage"); - /* - if (activityHandler != null) { - activityHandler.finishedTrackingActivity(jsonResponse); - } - */ - } - - @Override - public void sendNextPackage(ResponseData responseData) { - testLogger.test(prefix + "sendNextPackage, " + responseData); - } - - @Override - public void closeFirstPackage(ResponseData responseData, ActivityPackage activityPackage) { - testLogger.test(prefix + "closeFirstPackage, responseData" + responseData); - testLogger.test(prefix + "closeFirstPackage, activityPackage" + activityPackage); - } - - @Override - public void pauseSending() { - testLogger.test(prefix + "pauseSending"); - } - - @Override - public void resumeSending() { - testLogger.test(prefix + "resumeSending"); - } - - @Override - public void updatePackages(SessionParameters sessionParameters) { - testLogger.test(prefix + "updatePackages, sessionParameters" + sessionParameters); - } - - @Override - public void teardown(boolean deleteState) { - testLogger.test(prefix + "teardown deleteState, " + deleteState); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java deleted file mode 100644 index 6605fa762..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockRequestHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.adjust.sdk; - -public class MockRequestHandler implements IRequestHandler { - private MockLogger testLogger; - private String prefix = "RequestHandler "; - IPackageHandler packageHandler; - - public MockRequestHandler(MockLogger testLogger) { - this.testLogger = testLogger; - } - - @Override - public void init(IPackageHandler packageHandler) { - testLogger.test(prefix + "init"); - this.packageHandler = packageHandler; - } - - @Override - public void sendPackage(ActivityPackage activityPackage, int queueSize) { - testLogger.test(prefix + "sendPackage, activityPackage " + activityPackage); - testLogger.test(prefix + "sendPackage, queueSize " + queueSize); - - /* - // respond successfully to the package handler - if (packageHandler != null && !errorNextSend) { - packageHandler.sendNextPackage(); - } - - if (packageHandler != null && errorNextSend) { - testLogger.test(packageHandler.getFailureMessage()); - packageHandler.closeFirstPackage(); - } - */ - } - - @Override - public void teardown() { - testLogger.test(prefix + "teardown"); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java deleted file mode 100644 index 9ab5bc517..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/MockSdkClickHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.adjust.sdk; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by pfms on 01/04/16. - */ -public class MockSdkClickHandler implements ISdkClickHandler { - private MockLogger testLogger; - private String prefix = "SdkClickHandler "; - List queue; - IActivityHandler activityHandler; - - public MockSdkClickHandler(MockLogger testLogger) { - this.testLogger = testLogger; - queue = new ArrayList(); - } - @Override - public void init(IActivityHandler activityHandler, boolean startsSending) { - this.activityHandler = activityHandler; - testLogger.test(prefix + "init, startsSending: " + startsSending); - } - - @Override - public void pauseSending() { - testLogger.test(prefix + "pauseSending"); - } - - @Override - public void resumeSending() { - testLogger.test(prefix + "resumeSending"); - } - - @Override - public void sendSdkClick(ActivityPackage sdkClick) { - testLogger.test(prefix + "sendSdkClick"); - queue.add(sdkClick); - } - - @Override - public void teardown() { - testLogger.test(prefix + "teardown"); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ResponseType.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ResponseType.java deleted file mode 100644 index 0f95969de..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/ResponseType.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 28/01/15. - */ -public enum ResponseType { - NULL, CLIENT_PROTOCOL_EXCEPTION, INTERNAL_SERVER_ERROR, WRONG_JSON, EMPTY_JSON, MESSAGE; -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java deleted file mode 100644 index 96f8be57f..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerConstructor.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.adjust.sdk; - -import com.adjust.sdk.ActivityHandler; -import com.adjust.sdk.AdjustConfig; -import com.adjust.sdk.IRunActivityHandler; -import com.adjust.sdk.LogLevel; - -import java.util.List; - -/** - * Created by pfms on 09/08/2016. - */ -public class StateActivityHandlerConstructor { - AdjustConfig config; - boolean startEnabled = true; - boolean isToUpdatePackages = false; - - StateActivityHandlerConstructor(AdjustConfig config) { - this.config = config; - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java deleted file mode 100644 index 2eb32d315..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateActivityHandlerInit.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.adjust.sdk; - -import com.adjust.sdk.ActivityHandler; - -/** - * Created by pfms on 09/08/2016. - */ -public class StateActivityHandlerInit { - ActivityHandler.InternalState internalState; - boolean startEnabled = true; - boolean updatePackages = false; - boolean startsSending = false; - boolean sdkClickHandlerAlsoStartsPaused = true; - String defaultTracker = null; - String pushToken = null; - boolean eventBufferingIsEnabled = false; - boolean sendInBackgroundConfigured = false; - boolean delayStartConfigured = false; - boolean activityStateAlreadyCreated = false; - String sendReferrer = null; - String readActivityState = null; - String readAttribution = null; - String readCallbackParameters = null; - String readPartnerParameters = null; - int foregroundTimerStart = 60; - int foregroundTimerCycle = 60; - - StateActivityHandlerInit(ActivityHandler activityHandler) { - internalState = activityHandler.getInternalState(); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateDelegates.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateDelegates.java deleted file mode 100644 index cbe6fb746..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateDelegates.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 15/08/2016. - */ -public class StateDelegates { - boolean attributionDelegatePresent; - boolean eventSuccessDelegatePresent; - boolean eventFailureDelegatePresent; - boolean sessionSuccessDelegatePresent; - boolean sessionFailureDelegatePresent; -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEndSession.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEndSession.java deleted file mode 100644 index d0a4e71a6..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEndSession.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 11/08/2016. - */ -public class StateEndSession { - boolean pausing = true; - boolean updateActivityState = true; - boolean eventBufferingEnabled = false; - boolean checkOnPause = false; - boolean foregroundAlreadySuspended = false; - boolean backgroundTimerStarts = false; -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEvent.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEvent.java deleted file mode 100644 index 57933092c..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 11/08/2016. - */ -public class StateEvent { - String bufferedSuffix = null; - Integer backgroundTimerStarts = null; - String activityStateSuffix = null; - String orderId = null; - boolean duplicatedOrderId = false; - boolean disabled = false; -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateSession.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateSession.java deleted file mode 100644 index b081aefa6..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/StateSession.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.adjust.sdk; - -/** - * Created by pfms on 09/08/2016. - */ -public class StateSession { - boolean toSend = true; - int sessionCount = 1; - int subsessionCount = 1; - SessionType sessionType = null; - int eventCount = 0; - Boolean getAttributionIsCalled = null; - boolean eventBufferingIsEnabled = false; - boolean foregroundTimerStarts = true; - boolean foregroundTimerAlreadyStarted = false; - boolean sendInBackgroundConfigured = false; - boolean sdkClickHandlerAlsoStartsPaused = true; - boolean startSubsession = true; - boolean disabled = false; - String delayStart = null; - boolean activityStateAlreadyCreated = false; - - public enum SessionType { - NEW_SESSION, - NEW_SUBSESSION, - TIME_TRAVEL, - NONSESSION, - DISABLED, - } - - StateSession(SessionType sessionType) { - this.sessionType = sessionType; - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java deleted file mode 100644 index a15daf343..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityHandler.java +++ /dev/null @@ -1,3468 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.SystemClock; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.test.mock.MockContext; -import android.test.suitebuilder.annotation.LargeTest; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * Created by pfms on 08/08/2016. - */ -@RunWith(AndroidJUnit4.class) -@LargeTest -public class TestActivityHandler { - protected MockLogger mockLogger; - protected MockPackageHandler mockPackageHandler; - protected MockAttributionHandler mockAttributionHandler; - protected MockSdkClickHandler mockSdkClickHandler; - protected com.adjust.sdk.test.UnitTestActivity activity; - protected Context context; - protected AssertUtil assertUtil; - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(com.adjust.sdk.test.UnitTestActivity.class); - - @Before - public void setUp() { - mockLogger = new MockLogger(); - mockPackageHandler = new MockPackageHandler(mockLogger); - mockAttributionHandler = new MockAttributionHandler(mockLogger); - mockSdkClickHandler = new MockSdkClickHandler(mockLogger); - assertUtil = new AssertUtil(mockLogger); - - AdjustFactory.setLogger(mockLogger); - AdjustFactory.setPackageHandler(mockPackageHandler); - AdjustFactory.setAttributionHandler(mockAttributionHandler); - AdjustFactory.setSdkClickHandler(mockSdkClickHandler); - - //activity = launchActivity(null); - activity = mActivityRule.getActivity(); - context = activity.getApplicationContext(); - - // deleting state to simulate fresh install - mockLogger.test("Was AdjustActivityState deleted? " + ActivityHandler.deleteActivityState(context)); - mockLogger.test("Was Attribution deleted? " + ActivityHandler.deleteAttribution(context)); - mockLogger.test("Was Session Callback Parameters deleted? " + ActivityHandler.deleteSessionCallbackParameters(context)); - mockLogger.test("Was Session Partner Parameters deleted? " + ActivityHandler.deleteSessionPartnerParameters(context)); - - // check the server url - assertUtil.isEqual(Constants.BASE_URL, "https://app.adjust.com"); - } - - @After - public void tearDown() { - AdjustFactory.setPackageHandler(null); - AdjustFactory.setAttributionHandler(null); - AdjustFactory.setSdkClickHandler(null); - AdjustFactory.setLogger(null); - AdjustFactory.setTimerInterval(-1); - AdjustFactory.setTimerStart(-1); - AdjustFactory.setSessionInterval(-1); - AdjustFactory.setSubsessionInterval(-1); - - SharedPreferences settings = context.getSharedPreferences(Constants.PREFERENCES_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.clear(); - editor.apply(); - - activity = null; - context = null; - } - - @Test - public void testFirstSession() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testFirstSession"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // checking the default values of the first session package - // should only have one package - assertUtil.isEqual(1, mockPackageHandler.queue.size()); - - ActivityPackage activityPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testActivityPackage = new TestActivityPackage(activityPackage); - - // set first session - testActivityPackage.testSessionPackage(1); - } - - @Test - public void testEventsBuffered() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testEventsBuffered"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // buffer events - config.setEventBufferingEnabled(true); - - // set default tracker - config.setDefaultTracker("default1234tracker"); - - // create handler and start the first session - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit initState = new StateActivityHandlerInit(activityHandler); - - initState.eventBufferingIsEnabled = true; - initState.defaultTracker = "default1234tracker"; - - StateSession stateSession = new StateSession(StateSession.SessionType.NEW_SESSION); - stateSession.eventBufferingIsEnabled = true; - - checkInitAndStart(activityHandler, initState, stateSession); - - // create the first Event - AdjustEvent firstEvent = new AdjustEvent("event1"); - - // add callback parameters - firstEvent.addCallbackParameter("keyCall", "valueCall"); - firstEvent.addCallbackParameter("keyCall", "valueCall2"); - firstEvent.addCallbackParameter("fooCall", "barCall"); - - // add partner paramters - firstEvent.addPartnerParameter("keyPartner", "valuePartner"); - firstEvent.addPartnerParameter("keyPartner", "valuePartner2"); - firstEvent.addPartnerParameter("fooPartner", "barPartner"); - - // check that callback parameter was overwritten - assertUtil.warn("Key keyCall was overwritten"); - - // check that partner parameter was overwritten - assertUtil.warn("Key keyPartner was overwritten"); - - // add revenue - firstEvent.setRevenue(0.001, "EUR"); - - // set order id - firstEvent.setOrderId("orderIdTest"); - - // track event - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1500); - - StateEvent stateEvent1 = new StateEvent(); - stateEvent1.orderId = "orderIdTest"; - stateEvent1.bufferedSuffix = "(0.00100 EUR, 'event1')"; - stateEvent1.activityStateSuffix = "ec:1"; - - checkEvent(stateEvent1); - - // create the second Event - AdjustEvent secondEvent = new AdjustEvent("event2"); - - // set order id - secondEvent.setOrderId("orderIdTest"); - - // track second event - activityHandler.trackEvent(secondEvent); - - SystemClock.sleep(1500); - - StateEvent stateEvent2 = new StateEvent(); - stateEvent2.duplicatedOrderId = true; - stateEvent2.orderId = "orderIdTest"; - - checkEvent(stateEvent2); - - // create third Event - AdjustEvent thirdEvent = new AdjustEvent("event3"); - - // set order id - thirdEvent.setOrderId("otherOrderId"); - - // add empty revenue - thirdEvent.setRevenue(0, "USD"); - - // track third event - activityHandler.trackEvent(thirdEvent); - - SystemClock.sleep(1500); - - StateEvent stateEvent3 = new StateEvent(); - stateEvent3.orderId = "otherOrderId"; - stateEvent3.bufferedSuffix = "(0.00000 USD, 'event3')"; - stateEvent3.activityStateSuffix = "ec:2"; - - checkEvent(stateEvent3); - - // create a forth Event object without revenue - AdjustEvent forthEvent = new AdjustEvent("event4"); - - // track third event - activityHandler.trackEvent(forthEvent); - - SystemClock.sleep(1500); - - StateEvent stateEvent4 = new StateEvent(); - stateEvent4.bufferedSuffix = "'event4'"; - stateEvent4.activityStateSuffix = "ec:3"; - - checkEvent(stateEvent4); - - // check the number of activity packages - // 1 session + 3 events - assertUtil.isEqual(4, mockPackageHandler.queue.size()); - - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testFirstSessionPackage = new TestActivityPackage(firstSessionPackage); - testFirstSessionPackage.eventBufferingEnabled = true; - testFirstSessionPackage.defaultTracker = "default1234tracker"; - - // set first session - testFirstSessionPackage.testSessionPackage(1); - - // first event - ActivityPackage firstEventPackage = mockPackageHandler.queue.get(1); - - // create event package test - TestActivityPackage testFirstEventPackage = new TestActivityPackage(firstEventPackage); - - // set event test parameters - testFirstEventPackage.eventCount = "1"; - testFirstEventPackage.suffix = "(0.00100 EUR, 'event1')"; - testFirstEventPackage.revenueString = "0.00100"; - testFirstEventPackage.currency = "EUR"; - testFirstEventPackage.callbackParams = "{\"keyCall\":\"valueCall2\",\"fooCall\":\"barCall\"}"; - testFirstEventPackage.partnerParams = "{\"keyPartner\":\"valuePartner2\",\"fooPartner\":\"barPartner\"}"; - testFirstEventPackage.eventBufferingEnabled = true; - - // test first event - testFirstEventPackage.testEventPackage("event1"); - - // second event - ActivityPackage secondEventPackage = mockPackageHandler.queue.get(2); - - // create event package test - TestActivityPackage testSecondEventPackage = new TestActivityPackage(secondEventPackage); - - // set event test parameters - testSecondEventPackage.eventCount = "2"; - testSecondEventPackage.suffix = "(0.00000 USD, 'event3')"; - testSecondEventPackage.revenueString = "0.00000"; - testSecondEventPackage.currency = "USD"; - testSecondEventPackage.eventBufferingEnabled = true; - - // test second event - testSecondEventPackage.testEventPackage("event3"); - - // third event - ActivityPackage thirdEventPackage = mockPackageHandler.queue.get(3); - - // create event package test - TestActivityPackage testThirdEventPackage = new TestActivityPackage(thirdEventPackage); - - // set event test parameters - testThirdEventPackage.eventCount = "3"; - testThirdEventPackage.suffix = "'event4'"; - testThirdEventPackage.eventBufferingEnabled = true; - - // test third event - testThirdEventPackage.testEventPackage("event4"); - } - - @Test - public void testEventsNotBuffered() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testEventsNotBuffered"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // create the first Event - AdjustEvent firstEvent = new AdjustEvent("event1"); - - // track event - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1500); - - StateEvent stateEvent = new StateEvent(); - checkEvent(stateEvent); - } - - @Test - public void testEventBeforeStart() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testEventBeforeStart"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // create the first Event - AdjustEvent firstEvent = new AdjustEvent("event1"); - - // create handler and start the first session - ActivityHandler activityHandler = getActivityHandler(config); - - // track event - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1500); - - // test init values - checkInitTests(activityHandler); - - // does not start the activity because it was started by the track event - - // test session - StateSession stateSession= new StateSession(StateSession.SessionType.NEW_SESSION); - // does not start session - stateSession.startSubsession = false; - stateSession.toSend = false; - - checkStartInternal(stateSession); - - StateEvent stateEvent = new StateEvent(); - checkEvent(stateEvent); - } - - @Test - public void testChecks() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testChecks"); - - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testChecks"); - - // config with null app token - AdjustConfig nullAppTokenConfig = new AdjustConfig(context, null, AdjustConfig.ENVIRONMENT_SANDBOX); - - assertUtil.error("Missing App Token"); - assertUtil.isFalse(nullAppTokenConfig.isValid()); - - // config with wrong size app token - AdjustConfig oversizeAppTokenConfig = new AdjustConfig(context, "1234567890123", AdjustConfig.ENVIRONMENT_SANDBOX); - - assertUtil.error("Malformed App Token '1234567890123'"); - assertUtil.isFalse(oversizeAppTokenConfig.isValid()); - - // config with null environment - AdjustConfig nullEnvironmentConfig = new AdjustConfig(context, "123456789012", null); - - assertUtil.error("Missing environment"); - assertUtil.isFalse(nullEnvironmentConfig.isValid()); - - // config with wrong environment - AdjustConfig wrongEnvironmentConfig = new AdjustConfig(context, "123456789012", "Other"); - - assertUtil.error("Unknown environment 'Other'"); - assertUtil.isFalse(wrongEnvironmentConfig.isValid()); - - // config with null context - AdjustConfig nullContextConfig = new AdjustConfig(null, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - - assertUtil.error("Missing context"); - assertUtil.isFalse(nullContextConfig.isValid()); - - // config without internet permission - Context mockContext = new MockContext() { - @Override - public int checkCallingOrSelfPermission(String permission) { - return PackageManager.PERMISSION_DENIED; - } - }; - AdjustConfig mockContextConfig = new AdjustConfig(mockContext, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - - assertUtil.error("Missing permission: INTERNET"); - assertUtil.isFalse(mockContextConfig.isValid()); - - // config without access wifi state permission - // TODO - - // start with null config - ActivityHandler nullConfigactivityHandler = ActivityHandler.getInstance(null); - - assertUtil.error("AdjustConfig missing"); - assertUtil.isNull(nullConfigactivityHandler); - - ActivityHandler invalidConfigactivityHandler = ActivityHandler.getInstance(nullAppTokenConfig); - - assertUtil.error("AdjustConfig not initialized correctly"); - assertUtil.isNull(invalidConfigactivityHandler); - - // event with null event token - AdjustEvent nullEventToken = new AdjustEvent(null); - - assertUtil.error("Missing Event Token"); - assertUtil.isFalse(nullEventToken.isValid()); - - // event with wrong size - AdjustEvent wrongEventTokenSize = new AdjustEvent("eventXX"); - - assertUtil.error("Malformed Event Token 'eventXX'"); - assertUtil.isFalse(wrongEventTokenSize.isValid()); - - // event - AdjustEvent event = new AdjustEvent("event1"); - - // event with negative revenue - event.setRevenue(-0.001, "EUR"); - - assertUtil.error("Invalid amount -0.001"); - - // event with null currency - event.setRevenue(0, null); - - assertUtil.error("Currency must be set with revenue"); - - // event with empty currency - event.setRevenue(0, ""); - - assertUtil.error("Currency is empty"); - - // callback parameter null key - event.addCallbackParameter(null, "callValue"); - - assertUtil.error("Callback parameter key is missing"); - - // callback parameter empty key - event.addCallbackParameter("", "callValue"); - - assertUtil.error("Callback parameter key is empty"); - - // callback parameter null value - event.addCallbackParameter("keyCall", null); - - assertUtil.error("Callback parameter value is missing"); - - // callback parameter empty value - event.addCallbackParameter("keyCall", ""); - - assertUtil.error("Callback parameter value is empty"); - - // partner parameter null key - event.addPartnerParameter(null, "callValue"); - - assertUtil.error("Partner parameter key is missing"); - - // partner parameter empty key - event.addPartnerParameter("", "callValue"); - - assertUtil.error("Partner parameter key is empty"); - - // partner parameter null value - event.addPartnerParameter("keyCall", null); - - assertUtil.error("Partner parameter value is missing"); - - // partner parameter empty value - event.addPartnerParameter("keyCall", ""); - - assertUtil.error("Partner parameter value is empty"); - - // create the config with wrong process name - AdjustConfig configWrongProcess = new AdjustConfig(context, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - configWrongProcess.setProcessName("com.wrong.process"); - - // create handler and start the first session - ActivityHandler.getInstance(configWrongProcess); - - assertUtil.info("Skipping initialization in background process (com.adjust.sdk.test.test)"); - - // create the config with correct process name - AdjustConfig configCorrectProcess = new AdjustConfig(context, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - configCorrectProcess.setProcessName("com.adjust.sdk.test.test"); - - // create handler and start the first session - ActivityHandler.getInstance(configCorrectProcess); - - assertUtil.notInInfo("Skipping initialization in background process"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // create handler and start the first session - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // track null event - activityHandler.trackEvent(null); - SystemClock.sleep(1000); - - assertUtil.error("Event missing"); - - activityHandler.trackEvent(nullEventToken); - SystemClock.sleep(1000); - - assertUtil.error("Event not initialized correctly"); - - activityHandler.resetSessionCallbackParameters(); - activityHandler.resetSessionPartnerParameters(); - - activityHandler.removeSessionCallbackParameter(null); - activityHandler.removeSessionCallbackParameter(""); - activityHandler.removeSessionCallbackParameter("nonExistent"); - - activityHandler.removeSessionPartnerParameter(null); - activityHandler.removeSessionPartnerParameter(""); - activityHandler.removeSessionPartnerParameter("nonExistent"); - - activityHandler.addSessionCallbackParameter(null, "value"); - activityHandler.addSessionCallbackParameter("", "value"); - - activityHandler.addSessionCallbackParameter("key", null); - activityHandler.addSessionCallbackParameter("key", ""); - - activityHandler.addSessionPartnerParameter(null, "value"); - activityHandler.addSessionPartnerParameter("", "value"); - - activityHandler.addSessionPartnerParameter("key", null); - activityHandler.addSessionPartnerParameter("key", ""); - - activityHandler.removeSessionCallbackParameter("nonExistent"); - activityHandler.removeSessionPartnerParameter("nonExistent"); - - SystemClock.sleep(1500); - - assertUtil.warn("Session Callback parameters are not set"); - assertUtil.warn("Session Partner parameters are not set"); - - assertUtil.error("Session Callback parameter key is missing"); - assertUtil.error("Session Callback parameter key is empty"); - assertUtil.warn("Session Callback parameters are not set"); - - assertUtil.error("Session Partner parameter key is missing"); - assertUtil.error("Session Partner parameter key is empty"); - assertUtil.warn("Session Partner parameters are not set"); - - assertUtil.error("Session Callback parameter key is missing"); - assertUtil.error("Session Callback parameter key is empty"); - assertUtil.error("Session Callback parameter value is missing"); - assertUtil.error("Session Callback parameter value is empty"); - - assertUtil.error("Session Partner parameter key is missing"); - assertUtil.error("Session Partner parameter key is empty"); - assertUtil.error("Session Partner parameter value is missing"); - assertUtil.error("Session Partner parameter value is empty"); - - assertUtil.warn("Session Callback parameters are not set"); - assertUtil.warn("Session Partner parameters are not set"); - } - - @Test - public void testSessions() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testSessions"); - - // adjust the session intervals for testing - AdjustFactory.setSessionInterval(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // end subsession - stopActivity(activityHandler); - - SystemClock.sleep(2000); - - // test the end of the subsession - checkEndSession(); - - // start a subsession - resumeActivity(activityHandler); - - SystemClock.sleep(2000); - - // test the new sub session - StateSession secondSubsession = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - secondSubsession.subsessionCount = 2; - checkStartInternal(secondSubsession); - - stopActivity(activityHandler); - - SystemClock.sleep(5000); - - // test the end of the subsession - checkEndSession(); - - // trigger a new session - activityHandler.onResume(); - - SystemClock.sleep(1500); - - // new session - StateSession secondSession = new StateSession(StateSession.SessionType.NEW_SESSION); - secondSession.sessionCount = 2; - checkStartInternal(secondSession); - - // stop and start the activity with little interval - // so it won't trigger a sub session - stopActivity(activityHandler); - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test the end of the subsession - StateEndSession stateEndSession = new StateEndSession(); - stateEndSession.pausing = false; - - checkEndSession(stateEndSession); - - // test non sub session - StateSession nonSessionState = new StateSession(StateSession.SessionType.NONSESSION); - checkStartInternal(nonSessionState); - - // 2 session packages - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - ActivityPackage firstSessionActivityPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testFirstSessionActivityPackage = new TestActivityPackage(firstSessionActivityPackage); - - // test first session - testFirstSessionActivityPackage.testSessionPackage(1); - - // get second session package - ActivityPackage secondSessionActivityPackage = mockPackageHandler.queue.get(1); - - // create second session test package - TestActivityPackage testSecondSessionActivityPackage = new TestActivityPackage(secondSessionActivityPackage); - - // check if it saved the second subsession in the new package - testSecondSessionActivityPackage.subsessionCount = 2; - - // test second session - testSecondSessionActivityPackage.testSessionPackage(2); - } - - @Test - public void testDisable() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testDisable"); - - // adjust the session intervals for testing - AdjustFactory.setSessionInterval(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // create handler and start the first session - ActivityHandler activityHandler = getActivityHandler(config); - - // check that it is enabled - assertUtil.isTrue(activityHandler.isEnabled()); - - // disable sdk - activityHandler.setEnabled(false); - - SystemClock.sleep(1000); - - // check that it is disabled - assertUtil.isFalse(activityHandler.isEnabled()); - - // not writing activity state because it set enable does not start the sdk - assertUtil.notInDebug("Wrote Activity state"); - - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.startsSending = false; - stateActivityHandlerInit.startEnabled = false; - - checkInitTests(stateActivityHandlerInit); - - // check if message the disable of the SDK - assertUtil.info("Handlers will start as paused due to the SDK being disabled"); - - checkHandlerStatus(true); - - // start the sdk - // foreground timer does not start because it's paused - resumeActivity(activityHandler); - AdjustEvent firstEvent = new AdjustEvent("event1"); - - activityHandler.trackEvent(firstEvent); - SystemClock.sleep(1500); - - // check initial created session - StateSession initialSessionDisabled = new StateSession(StateSession.SessionType.DISABLED); - initialSessionDisabled.toSend = false; - initialSessionDisabled.foregroundTimerStarts = false; - - checkStartInternal(initialSessionDisabled); - - // and failed event - StateEvent stateFailedEvent = new StateEvent(); - stateFailedEvent.disabled = true; - - checkEvent(stateFailedEvent); - - // try to pause session - stopActivity(activityHandler); - SystemClock.sleep(1500); - - StateEndSession stateEndSession = new StateEndSession(); - stateEndSession.checkOnPause = true; - stateEndSession.foregroundAlreadySuspended = true; - - checkEndSession(stateEndSession); - - SystemClock.sleep(4000); - - // try to generate a new session - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - StateSession sessionDisabled = new StateSession(StateSession.SessionType.DISABLED); - sessionDisabled.toSend = false; - sessionDisabled.foregroundTimerStarts = false; - sessionDisabled.disabled = true; - - checkStartInternal(sessionDisabled); - - // only the first session package should be sent - assertUtil.isEqual(0, mockPackageHandler.queue.size()); - - // put in offline mode - activityHandler.setOfflineMode(true); - - // wait to update status - SystemClock.sleep(1500); - - // pausing due to offline mode - assertUtil.info("Pausing handlers to put SDK offline mode"); - - // after pausing, even when it's already paused - // tries to update the status - checkHandlerStatus(true); - - // re-enable the SDK - activityHandler.setEnabled(true); - - // wait to update status - SystemClock.sleep(1500); - - // check that it is enabled - assertUtil.isTrue(activityHandler.isEnabled()); - - // check message of SDK still paused - assertUtil.info("Handlers remain paused"); - - // wait to generate a new session - SystemClock.sleep(5000); - - // even though it will remained paused, - // it will update the status to paused - checkHandlerStatus(true); - - // generate a new session - resumeActivity(activityHandler); - AdjustEvent secondEvent = new AdjustEvent("event2"); - - activityHandler.trackEvent(secondEvent); - - SystemClock.sleep(1500); - - // difference from the first session is that now the foreground timer starts - StateSession sessionOffline = new StateSession(StateSession.SessionType.NEW_SESSION); - sessionOffline.toSend = false; - sessionOffline.foregroundTimerStarts = true; - sessionOffline.foregroundTimerAlreadyStarted = false; - - checkStartInternal(sessionOffline); - - // and the event does not fail - StateEvent stateEvent = new StateEvent(); - - checkEvent(stateEvent); - - // it should have the second session and the event - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - ActivityPackage secondSessionPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testSecondSessionPackage = new TestActivityPackage(secondSessionPackage); - - // set the sub sessions - testSecondSessionPackage.subsessionCount = 1; - - // test second session - testSecondSessionPackage.testSessionPackage(2); - - ActivityPackage eventPackage = mockPackageHandler.queue.get(1); - - // create activity package test - TestActivityPackage testEventPackage = new TestActivityPackage(eventPackage); - - testEventPackage.suffix = "'event2'"; - - // test event - testEventPackage.testEventPackage("event2"); - - // end the session - stopActivity(activityHandler); - - SystemClock.sleep(1500); - - checkEndSession(); - - // put in online mode - activityHandler.setOfflineMode(false); - - SystemClock.sleep(1500); - - // message that is finally resuming - assertUtil.info("Resuming handlers to put SDK in online mode"); - - SystemClock.sleep(5000); - - // after un-pausing the sdk, tries to update the handlers - // it is still paused because it's on the background - checkHandlerStatus(true); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - StateSession thirdSessionStarting = new StateSession(StateSession.SessionType.NEW_SESSION); - thirdSessionStarting.sessionCount = 3; - thirdSessionStarting.eventCount = 1; - checkStartInternal(thirdSessionStarting); - } - - @Test - public void testOpenUrl() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testOpenUrl"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - Uri attributions = Uri.parse("AdjustTests://example.com/path/inApp?adjust_tracker=trackerValue&other=stuff&adjust_campaign=campaignValue&adjust_adgroup=adgroupValue&adjust_creative=creativeValue"); - Uri extraParams = Uri.parse("AdjustTests://example.com/path/inApp?adjust_foo=bar&other=stuff&adjust_key=value"); - Uri mixed = Uri.parse("AdjustTests://example.com/path/inApp?adjust_foo=bar&other=stuff&adjust_campaign=campaignValue&adjust_adgroup=adgroupValue&adjust_creative=creativeValue"); - Uri encodedSeparators = Uri.parse("AdjustTests://example.com/path/inApp?adjust_foo=b%26a%3B%3Dr&adjust_campaign=campaign%3DValue%26&other=stuff"); - Uri emptyQueryString = Uri.parse("AdjustTests://"); - Uri emptyString = Uri.parse(""); - Uri nullUri = null; - Uri single = Uri.parse("AdjustTests://example.com/path/inApp?adjust_foo"); - Uri prefix = Uri.parse("AdjustTests://example.com/path/inApp?adjust_=bar"); - Uri incomplete = Uri.parse("AdjustTests://example.com/path/inApp?adjust_foo="); - - long now = System.currentTimeMillis(); - - activityHandler.readOpenUrl(attributions, now); - activityHandler.readOpenUrl(extraParams, now); - activityHandler.readOpenUrl(mixed, now); - activityHandler.readOpenUrl(encodedSeparators, now); - activityHandler.readOpenUrl(emptyQueryString, now); - activityHandler.readOpenUrl(emptyString, now); - activityHandler.readOpenUrl(nullUri, now); - activityHandler.readOpenUrl(single, now); - activityHandler.readOpenUrl(prefix, now); - activityHandler.readOpenUrl(incomplete, now); - - SystemClock.sleep(1000); - - assertUtil.verbose("Url to parse (%s)", attributions); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", extraParams); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", mixed); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", encodedSeparators); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", emptyQueryString); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", single); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", prefix); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Url to parse (%s)", incomplete); - assertUtil.test("SdkClickHandler sendSdkClick"); - - // check that it did not send any other click package - assertUtil.notInTest("SdkClickHandler sendSdkClick"); - - // 8 clicks - assertUtil.isEqual(8, mockSdkClickHandler.queue.size()); - - // get the click package - ActivityPackage attributionClickPackage = mockSdkClickHandler.queue.get(0); - - // create activity package test - TestActivityPackage testAttributionClickPackage = new TestActivityPackage(attributionClickPackage); - - // create the attribution - AdjustAttribution firstAttribution = new AdjustAttribution(); - firstAttribution.trackerName = "trackerValue"; - firstAttribution.campaign = "campaignValue"; - firstAttribution.adgroup = "adgroupValue"; - firstAttribution.creative = "creativeValue"; - - // and set it - testAttributionClickPackage.attribution = firstAttribution; - - testAttributionClickPackage.deeplink = attributions.toString(); - - // test the first deeplink - testAttributionClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage extraParamsClickPackage = mockSdkClickHandler.queue.get(1); - - // create activity package test - TestActivityPackage testExtraParamsClickPackage = new TestActivityPackage(extraParamsClickPackage); - - // other deep link parameters - testExtraParamsClickPackage.otherParameters = "{\"key\":\"value\",\"foo\":\"bar\"}"; - - testExtraParamsClickPackage.deeplink = extraParams.toString(); - - // test the second deeplink - testExtraParamsClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage mixedClickPackage = mockSdkClickHandler.queue.get(2); - - // create activity package test - TestActivityPackage testMixedClickPackage = new TestActivityPackage(mixedClickPackage); - - // create the attribution - AdjustAttribution secondAttribution = new AdjustAttribution(); - secondAttribution.campaign = "campaignValue"; - secondAttribution.adgroup = "adgroupValue"; - secondAttribution.creative = "creativeValue"; - - // and set it - testMixedClickPackage.attribution = secondAttribution; - - // other deep link parameters - testMixedClickPackage.otherParameters = "{\"foo\":\"bar\"}"; - - testMixedClickPackage.deeplink = mixed.toString(); - - // test the third deeplink - testMixedClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage encodedClickPackage = mockSdkClickHandler.queue.get(3); - - // create activity package test - TestActivityPackage testEncodedClickPackage = new TestActivityPackage(encodedClickPackage); - - // create the attribution - AdjustAttribution thirdAttribution = new AdjustAttribution(); - thirdAttribution.campaign = "campaign=Value&"; - - // and set it - testEncodedClickPackage.attribution = thirdAttribution; - - // other deep link parameters - testEncodedClickPackage.otherParameters = "{\"foo\":\"b&a;=r\"}"; - - testEncodedClickPackage.deeplink = encodedSeparators.toString(); - - // test the third deeplink - testEncodedClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage emptyQueryStringClickPackage = mockSdkClickHandler.queue.get(4); - - // create activity package test - TestActivityPackage testEmptyQueryStringClickPackage = new TestActivityPackage(emptyQueryStringClickPackage); - - testEmptyQueryStringClickPackage.deeplink = emptyQueryString.toString(); - - testEmptyQueryStringClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage singleClickPackage = mockSdkClickHandler.queue.get(5); - - // create activity package test - TestActivityPackage testSingleClickPackage = new TestActivityPackage(singleClickPackage); - - testSingleClickPackage.deeplink = single.toString(); - - testSingleClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage prefixClickPackage = mockSdkClickHandler.queue.get(6); - - // create activity package test - TestActivityPackage testPrefixClickPackage = new TestActivityPackage(prefixClickPackage); - - testPrefixClickPackage.deeplink = prefix.toString(); - - testPrefixClickPackage.testClickPackage("deeplink"); - - // get the click package - ActivityPackage incompleteClickPackage = mockSdkClickHandler.queue.get(7); - - // create activity package test - TestActivityPackage testIncompleteClickPackage = new TestActivityPackage(incompleteClickPackage ); - - testIncompleteClickPackage.deeplink = incomplete.toString(); - - testIncompleteClickPackage.testClickPackage("deeplink"); - } - - @Test - public void testAttributionDelegate() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testAttributionDelegate"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnAttributionChangedListener(new OnAttributionChangedListener() { - @Override - public void onAttributionChanged(AdjustAttribution attribution) { - mockLogger.test("onAttributionChanged: " + attribution); - } - }); - - StateDelegates attributionDelegatePresent = new StateDelegates(); - attributionDelegatePresent.attributionDelegatePresent = true; - checkFinishTasks(config, attributionDelegatePresent); - } - - @Test - public void testSuccessDelegates() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testSuccessDelegates"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { - @Override - public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { - mockLogger.test("onFinishedEventTrackingSucceeded: " + eventSuccessResponseData); - } - }); - - config.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { - @Override - public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { - mockLogger.test("onFinishedSessionTrackingSucceeded: " + sessionSuccessResponseData); - } - }); - - StateDelegates successDelegatesPresent = new StateDelegates(); - successDelegatesPresent.eventSuccessDelegatePresent = true; - successDelegatesPresent.sessionSuccessDelegatePresent = true; - - checkFinishTasks(config, successDelegatesPresent); - } - - @Test - public void testFailureDelegates() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testFailureDelegates"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { - @Override - public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { - mockLogger.test("onFinishedEventTrackingFailed: " + eventFailureResponseData); - } - }); - - config.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { - @Override - public void onFinishedSessionTrackingFailed(AdjustSessionFailure failureResponseData) { - mockLogger.test("onFinishedSessionTrackingFailed: " + failureResponseData); - } - }); - - StateDelegates failureDelegatesPresent = new StateDelegates(); - failureDelegatesPresent.sessionFailureDelegatePresent = true; - failureDelegatesPresent.eventFailureDelegatePresent = true; - - checkFinishTasks(config, failureDelegatesPresent); - } - - private void checkFinishTasks(AdjustConfig config, - StateDelegates stateDelegates) - { - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // test first session package - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testActivityPackage = new TestActivityPackage(firstSessionPackage); - - // set first session - testActivityPackage.testSessionPackage(1); - - long now = System.currentTimeMillis(); - String dateString = Util.dateFormatter.format(now); - - // simulate a successful session - SessionResponseData successSessionResponseData = (SessionResponseData) ResponseData.buildResponseData(firstSessionPackage); - successSessionResponseData.success = true; - successSessionResponseData.message = "Session successfully tracked"; - successSessionResponseData.timestamp = dateString; - successSessionResponseData.adid = "adidValue"; - - activityHandler.finishedTrackingActivity(successSessionResponseData); - SystemClock.sleep(1000); - - // attribution handler should always receive the session response - assertUtil.test("AttributionHandler checkSessionResponse"); - - // attribution handler does not receive sdk click - assertUtil.notInTest("AttributionHandler checkSdkClickResponse"); - - // the first session does not trigger the event response delegate - assertUtil.notInDebug("Launching success event tracking listener"); - assertUtil.notInDebug("Launching failed event tracking listener"); - - activityHandler.launchSessionResponseTasks(successSessionResponseData); - SystemClock.sleep(1000); - - // if present, the first session triggers the success session delegate - if (stateDelegates.sessionSuccessDelegatePresent) { - assertUtil.debug("Launching success session tracking listener"); - assertUtil.test("onFinishedSessionTrackingSucceeded: Session Success msg:Session successfully tracked time:" + dateString + " adid:adidValue json:null"); - } else { - assertUtil.notInDebug("Launching success session tracking delegate"); - assertUtil.notInTest("onFinishedSessionTrackingSucceeded: Session Success "); - } - // it doesn't trigger the failure session delegate - assertUtil.notInDebug("Launching failed session tracking listener"); - - // simulate a failure session - SessionResponseData failureSessionResponseData = (SessionResponseData)ResponseData.buildResponseData(firstSessionPackage); - failureSessionResponseData.success = false; - failureSessionResponseData.message = "Session failure tracked"; - failureSessionResponseData.timestamp = dateString; - failureSessionResponseData.adid = "adidValue"; - - activityHandler.launchSessionResponseTasks(failureSessionResponseData); - SystemClock.sleep(1000); - - // it doesn't trigger the success session delegate - assertUtil.notInDebug("Launching success session tracking listener"); - - // if present, the first session triggers the failure session delegate - if (stateDelegates.sessionFailureDelegatePresent) { - assertUtil.debug("Launching failed session tracking listener"); - assertUtil.test("onFinishedSessionTrackingFailed: Session Failure msg:Session failure tracked time:" + dateString+ " adid:adidValue retry:false json:null"); - } else { - assertUtil.notInDebug("Launching failed session tracking listener"); - assertUtil.notInTest("onFinishedSessionTrackingFailed: Session Failure "); - } - - // test success event response data - activityHandler.trackEvent(new AdjustEvent("abc123")); - SystemClock.sleep(1000); - - ActivityPackage eventPackage = mockPackageHandler.queue.get(1); - EventResponseData eventSuccessResponseData = (EventResponseData)ResponseData.buildResponseData(eventPackage); - eventSuccessResponseData.success = true; - eventSuccessResponseData.message = "Event successfully tracked"; - eventSuccessResponseData.timestamp = dateString; - eventSuccessResponseData.adid = "adidValue"; - - activityHandler.finishedTrackingActivity(eventSuccessResponseData); - SystemClock.sleep(1000); - - // attribution handler should never receive the event response - assertUtil.notInTest("AttributionHandler checkSessionResponse"); - - // if present, the success event triggers the success event delegate - if (stateDelegates.eventSuccessDelegatePresent) { - assertUtil.debug("Launching success event tracking listener"); - assertUtil.test("onFinishedEventTrackingSucceeded: Event Success msg:Event successfully tracked time:" + dateString + " adid:adidValue event:abc123 json:null"); - } else { - assertUtil.notInDebug("Launching success event tracking listener"); - assertUtil.notInTest("onFinishedEventTrackingSucceeded: Event Success "); - } - // it doesn't trigger the failure event delegate - assertUtil.notInDebug("Launching failed event tracking listener"); - - // test failure event response data - EventResponseData eventFailureResponseData = (EventResponseData)ResponseData.buildResponseData(eventPackage); - eventFailureResponseData.success = false; - eventFailureResponseData.message = "Event failure tracked"; - eventFailureResponseData.timestamp = dateString; - eventFailureResponseData.adid = "adidValue"; - - activityHandler.finishedTrackingActivity(eventFailureResponseData); - SystemClock.sleep(1000); - - // attribution handler should never receive the event response - assertUtil.notInTest("AttributionHandler checkSessionResponse"); - - // if present, the failure event triggers the failure event delegate - if (stateDelegates.eventFailureDelegatePresent) { - assertUtil.debug("Launching failed event tracking listener"); - assertUtil.test("onFinishedEventTrackingFailed: Event Failure msg:Event failure tracked time:" + dateString + " adid:adidValue event:abc123 retry:false json:null"); - } else { - assertUtil.notInDebug("Launching failed event tracking listener"); - assertUtil.notInTest("onFinishedEventTrackingFailed: Event Failure "); - } - // it doesn't trigger the success event delegate - assertUtil.notInDebug("Launching success event tracking listener"); - - // test click - Uri attributions = Uri.parse("AdjustTests://example.com/path/inApp?adjust_tracker=trackerValue&other=stuff&adjust_campaign=campaignValue&adjust_adgroup=adgroupValue&adjust_creative=creativeValue"); - - activityHandler.readOpenUrl(attributions, now); - SystemClock.sleep(1000); - - assertUtil.test("SdkClickHandler sendSdkClick"); - - // test sdk_click response data - ActivityPackage sdkClickPackage = mockSdkClickHandler.queue.get(0); - SdkClickResponseData sdkClickResponseData = (SdkClickResponseData) ResponseData.buildResponseData(sdkClickPackage); - - activityHandler.finishedTrackingActivity(sdkClickResponseData); - SystemClock.sleep(1000); - - // attribution handler receives the click response - assertUtil.test("AttributionHandler checkSdkClickResponse"); - - // attribution handler does not receive session response - assertUtil.notInTest("AttributionHandler checkSessionResponse"); - - // it doesn't trigger the any event delegate - assertUtil.notInDebug("Launching success event tracking listener"); - assertUtil.notInDebug("Launching failed event tracking listener"); - } - - @Test - public void testLaunchDeepLink() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testLaunchDeepLink"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - ResponseData responseDataNull = null; - - activityHandler.finishedTrackingActivity(responseDataNull); - SystemClock.sleep(1500); - - // if the response is null - assertUtil.notInTest("AttributionHandler checkAttribution"); - assertUtil.notInError("Unable to open deferred deep link"); - assertUtil.notInInfo("Open deferred deep link"); - - // test success session response data - SessionResponseData sessionResponseDeeplink = (SessionResponseData) ResponseData.buildResponseData(mockPackageHandler.queue.get(0)); - try { - sessionResponseDeeplink.jsonResponse = new JSONObject("{ " + - "\"deeplink\" : \"adjustTestSchema://\" }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - activityHandler.launchSessionResponseTasks((SessionResponseData) sessionResponseDeeplink); - SystemClock.sleep(1500); - - // check that it was unable to open the url - assertUtil.notInError("Unable to open deferred deep link"); - assertUtil.notInInfo("Open deferred deep link"); - - // test attribution response - AttributionResponseData attributionResponseDeeplink = (AttributionResponseData)ResponseData.buildResponseData(mockAttributionHandler.attributionPackage); - attributionResponseDeeplink.deeplink = Uri.parse("adjustTestSchema://"); - - activityHandler.launchAttributionResponseTasks(attributionResponseDeeplink); - SystemClock.sleep(1500); - - assertUtil.info("Deferred deeplink received (adjustTestSchema://)"); - assertUtil.notInError("Unable to open deferred deep link (adjustTestSchema://)"); - assertUtil.info("Open deferred deep link (adjustTestSchema://)"); - - // checking the default values of the first session package - // should only have one package - assertUtil.isEqual(1, mockPackageHandler.queue.size()); - - AttributionResponseData attributionResponseWrongDeeplink = (AttributionResponseData)ResponseData.buildResponseData(mockAttributionHandler.attributionPackage); - attributionResponseWrongDeeplink.deeplink = Uri.parse("wrongDeeplink://"); - - activityHandler.launchAttributionResponseTasks(attributionResponseWrongDeeplink); - SystemClock.sleep(1500); - - assertUtil.info("Deferred deeplink received (wrongDeeplink://)"); - assertUtil.error("Unable to open deferred deep link (wrongDeeplink://)"); - assertUtil.notInInfo("Open deferred deep link (wrongDeeplink://)"); - } - - @Test - public void testNotLaunchDeeplinkCallback() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testNotLaunchDeeplinkCallback"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { - @Override - public boolean launchReceivedDeeplink(Uri deeplink) { - mockLogger.test("launchReceivedDeeplink, " + deeplink); - return false; - } - }); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // test attribution response - AttributionResponseData attributionResponseDeeplink = (AttributionResponseData)ResponseData.buildResponseData(mockAttributionHandler.attributionPackage); - attributionResponseDeeplink.deeplink = Uri.parse("adjustTestSchema://"); - - activityHandler.launchAttributionResponseTasks(attributionResponseDeeplink); - SystemClock.sleep(1500); - - // received the deferred deeplink - assertUtil.info("Deferred deeplink received (adjustTestSchema://)"); - // but it did not try to launch it - assertUtil.test("launchReceivedDeeplink, adjustTestSchema://"); - assertUtil.notInError("Unable to open deferred deep link (adjustTestSchema://)"); - assertUtil.notInInfo("Open deferred deep link (adjustTestSchema://)"); - } - - @Test - public void testDeeplinkCallback() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testDeeplinkCallback"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { - @Override - public boolean launchReceivedDeeplink(Uri deeplink) { - mockLogger.test("launchReceivedDeeplink, " + deeplink); - return true; - } - }); - - // start activity handler with config - ActivityHandler activityHandler = startAndCheckFirstSession(config); - - // set package handler to respond with a valid attribution - AttributionResponseData attributionResponseDeeplink = (AttributionResponseData)ResponseData.buildResponseData(mockAttributionHandler.attributionPackage); - attributionResponseDeeplink.deeplink = Uri.parse("adjustTestSchema://"); - - activityHandler.launchAttributionResponseTasks(attributionResponseDeeplink); - SystemClock.sleep(2000); - - // received the deferred deeplink - assertUtil.info("Deferred deeplink received (adjustTestSchema://)"); - // and it did launch it - assertUtil.test("launchReceivedDeeplink, adjustTestSchema://"); - assertUtil.notInError("Unable to open deferred deep link (adjustTestSchema://)"); - assertUtil.info("Open deferred deep link (adjustTestSchema://)"); - } - - @Test - public void testUpdateAttribution() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testUpdateAttribution"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler firstActivityHandler = startAndCheckFirstSession(config); - - JSONObject nullJsonObject = null; - AdjustAttribution nullAttribution = AdjustAttribution.fromJson(nullJsonObject, null); //XXX - - // check if Attribution wasn't built - assertUtil.isNull(nullAttribution); - - // check that it does not update a null attribution - assertUtil.isFalse(firstActivityHandler.updateAttributionI(nullAttribution)); - - // create an empty attribution - JSONObject emptyJsonResponse = null; - try { - emptyJsonResponse = new JSONObject("{ }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - AdjustAttribution emptyAttribution = AdjustAttribution.fromJson(emptyJsonResponse, null); // XXX - - // check that updates attribution - assertUtil.isTrue(firstActivityHandler.updateAttributionI(emptyAttribution)); - assertUtil.debug("Wrote Attribution: tt:null tn:null net:null cam:null adg:null cre:null cl:null"); - - emptyAttribution = AdjustAttribution.fromJson(emptyJsonResponse, null); // XXX - - // test first session package - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - - // simulate a session response with attribution data - SessionResponseData sessionResponseDataWithAttribution = (SessionResponseData)ResponseData.buildResponseData(firstSessionPackage); - sessionResponseDataWithAttribution.attribution = emptyAttribution; - - // check that it does not update the attribution - firstActivityHandler.launchSessionResponseTasks(sessionResponseDataWithAttribution); - SystemClock.sleep(1000); - assertUtil.notInDebug("Wrote Attribution"); - - // end session - firstActivityHandler.onPause(); - SystemClock.sleep(1000); - - checkEndSession(); - - // create the new config - config = getConfig(); - - config.setOnAttributionChangedListener(new OnAttributionChangedListener() { - @Override - public void onAttributionChanged(AdjustAttribution attribution) { - mockLogger.test("restartActivityHandler onAttributionChanged: " + attribution); - } - }); - - ActivityHandler restartActivityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - StateActivityHandlerInit restartActivityHandlerInit = new StateActivityHandlerInit(restartActivityHandler); - restartActivityHandlerInit.activityStateAlreadyCreated = true; - restartActivityHandlerInit.readActivityState = "ec:0 sc:1 ssc:1"; - restartActivityHandlerInit.readAttribution = "tt:null tn:null net:null cam:null adg:null cre:null cl:null"; - - // test init values - checkInitTests(restartActivityHandlerInit); - - resumeActivity(restartActivityHandler); - - SystemClock.sleep(2000); - - StateSession firstRestart = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - firstRestart.subsessionCount = 2; - firstRestart.foregroundTimerAlreadyStarted = false; - checkStartInternal(firstRestart); - - // check that it does not update the attribution after the restart - assertUtil.isFalse(restartActivityHandler.updateAttributionI(emptyAttribution)); - assertUtil.notInDebug("Wrote Attribution"); - - // new attribution - JSONObject firstAttributionJson = null; - try { - firstAttributionJson = new JSONObject("{ " + - "\"tracker_token\" : \"ttValue\" , " + - "\"tracker_name\" : \"tnValue\" , " + - "\"network\" : \"nValue\" , " + - "\"campaign\" : \"cpValue\" , " + - "\"adgroup\" : \"aValue\" , " + - "\"creative\" : \"ctValue\" , " + - "\"click_label\" : \"clValue\" }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - AdjustAttribution firstAttribution = AdjustAttribution.fromJson(firstAttributionJson, null); // XXX - - //check that it updates - sessionResponseDataWithAttribution.attribution = firstAttribution; - restartActivityHandler.launchSessionResponseTasks(sessionResponseDataWithAttribution); - SystemClock.sleep(1000); - - assertUtil.debug("Wrote Attribution: tt:ttValue tn:tnValue net:nValue cam:cpValue adg:aValue cre:ctValue cl:clValue"); - assertUtil.test("restartActivityHandler onAttributionChanged: tt:ttValue tn:tnValue net:nValue cam:cpValue adg:aValue cre:ctValue cl:clValue"); - - // test first session package - ActivityPackage attributionPackage = mockAttributionHandler.attributionPackage; - // simulate a session response with attribution data - AttributionResponseData attributionResponseDataWithAttribution = (AttributionResponseData)ResponseData.buildResponseData(attributionPackage); - - attributionResponseDataWithAttribution.attribution = firstAttribution; - // check that it does not update the attribution - restartActivityHandler.launchAttributionResponseTasks(attributionResponseDataWithAttribution); - SystemClock.sleep(1000); - - assertUtil.notInDebug("Wrote Attribution"); - - // end session - restartActivityHandler.onPause(); - SystemClock.sleep(1000); - - checkEndSession(); - - config = getConfig(); - - config.setOnAttributionChangedListener(new OnAttributionChangedListener() { - @Override - public void onAttributionChanged(AdjustAttribution attribution) { - mockLogger.test("secondRestartActivityHandler onAttributionChanged: " + attribution); - } - }); - - ActivityHandler secondRestartActivityHandler = getActivityHandler(config);; - - SystemClock.sleep(1500); - - StateActivityHandlerInit secondrestartActivityHandlerInit = new StateActivityHandlerInit(secondRestartActivityHandler); - secondrestartActivityHandlerInit.activityStateAlreadyCreated = true; - secondrestartActivityHandlerInit.readActivityState = "ec:0 sc:1 ssc:2"; - secondrestartActivityHandlerInit.readAttribution = "tt:ttValue tn:tnValue net:nValue cam:cpValue adg:aValue cre:ctValue cl:clValue"; - - SystemClock.sleep(2000); - - // test init values - checkInitTests(secondrestartActivityHandlerInit); - - resumeActivity(secondRestartActivityHandler); - - SystemClock.sleep(2000); - - StateSession secondRestart = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - secondRestart.subsessionCount = 3; - secondRestart.foregroundTimerAlreadyStarted = false; - - checkStartInternal(secondRestart); - - // check that it does not update the attribution after the restart - assertUtil.isFalse(secondRestartActivityHandler.updateAttributionI(firstAttribution)); - assertUtil.notInDebug("Wrote Attribution"); - - // new attribution - JSONObject secondAttributionJson = null; - try { - secondAttributionJson = new JSONObject("{ " + - "\"tracker_token\" : \"ttValue2\" , " + - "\"tracker_name\" : \"tnValue2\" , " + - "\"network\" : \"nValue2\" , " + - "\"campaign\" : \"cpValue2\" , " + - "\"adgroup\" : \"aValue2\" , " + - "\"creative\" : \"ctValue2\" , " + - "\"click_label\" : \"clValue2\" }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - AdjustAttribution secondAttribution = AdjustAttribution.fromJson(secondAttributionJson, null); // XXX - - //check that it updates - attributionResponseDataWithAttribution.attribution = secondAttribution; - secondRestartActivityHandler.launchAttributionResponseTasks(attributionResponseDataWithAttribution); - SystemClock.sleep(2000); - - assertUtil.debug("Wrote Attribution: tt:ttValue2 tn:tnValue2 net:nValue2 cam:cpValue2 adg:aValue2 cre:ctValue2 cl:clValue2"); - - // check that it launch the saved attribute - assertUtil.test("secondRestartActivityHandler onAttributionChanged: tt:ttValue2 tn:tnValue2 net:nValue2 cam:cpValue2 adg:aValue2 cre:ctValue2 cl:clValue2"); - - // check that it does not update the attribution - assertUtil.isFalse(secondRestartActivityHandler.updateAttributionI(secondAttribution)); - assertUtil.notInDebug("Wrote Attribution"); - } - - @Test - public void testOfflineMode() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testOfflineMode"); - - // adjust the session intervals for testing - AdjustFactory.setSessionInterval(2000); - AdjustFactory.setSubsessionInterval(500); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - // put SDK offline - activityHandler.setOfflineMode(true); - - SystemClock.sleep(1000); - - ActivityHandler.InternalState internalState = activityHandler.getInternalState(); - - // check if it's offline before the sdk starts - assertUtil.isTrue(internalState.isOffline()); - - SystemClock.sleep(1500); - - // not writing activity state because it set enable does not start the sdk - assertUtil.notInDebug("Wrote Activity state"); - - // test init values - checkInitTests(activityHandler); - - // check if message the disable of the SDK - assertUtil.info("Handlers will start paused due to SDK being offline"); - - // check change from set offline mode - checkHandlerStatus(true); - - // start the sdk - // foreground timer starts because it's offline, not disabled - resumeActivity(activityHandler); - - SystemClock.sleep(2500); - - // test first session start - StateSession firstSessionStartPaused = new StateSession(StateSession.SessionType.NEW_SESSION); - firstSessionStartPaused.toSend = false; - firstSessionStartPaused.foregroundTimerStarts = true; - - // check session that is paused - checkStartInternal(firstSessionStartPaused); - - stopActivity(activityHandler); - SystemClock.sleep(1500); - - // test end session of offline - StateEndSession stateOfflineEndSession = new StateEndSession(); - stateOfflineEndSession.checkOnPause = true; - stateOfflineEndSession.updateActivityState = false; // update too late on the session - checkEndSession(stateOfflineEndSession); - - // disable the SDK in the background - activityHandler.setEnabled(false); - - SystemClock.sleep(1000); - - // check that it is disabled - assertUtil.isFalse(activityHandler.isEnabled()); - - // writing activity state after disabling - assertUtil.debug("Wrote Activity state: ec:0 sc:1 ssc:1"); - - // check if message the disable of the SDK - assertUtil.info("Pausing handlers due to SDK being disabled"); - - // start a session while offline and disabled - SystemClock.sleep(2500); - - // check handler status update of disable - checkHandlerStatus(true); - - // try to start new session disabled - resumeActivity(activityHandler); - SystemClock.sleep(1500); - - // session not created for being disabled - // foreground timer does not start because it's offline, not disabled - StateSession sessionDisabled = new StateSession(StateSession.SessionType.DISABLED); - sessionDisabled.toSend = false; - sessionDisabled.foregroundTimerStarts = false; - sessionDisabled.disabled = true; - - checkStartInternal(sessionDisabled); - - // put SDK back online - activityHandler.setOfflineMode(false); - - SystemClock.sleep(1500); - - assertUtil.info("Handlers remain paused"); - - // test the update status, still paused - checkHandlerStatus(true); - - // try to do activities while SDK disabled - resumeActivity(activityHandler); - activityHandler.trackEvent(new AdjustEvent("event1")); - - SystemClock.sleep(2500); - - // check that timer was not executed - checkForegroundTimerFired(false); - - // session not created for being disabled - // foreground timer does not start because it's offline, not disabled - checkStartInternal(sessionDisabled); - - // end the session - stopActivity(activityHandler); - - SystemClock.sleep(1000); - - StateEndSession stateDisableEndSession = new StateEndSession(); - stateDisableEndSession.checkOnPause = true; - stateDisableEndSession.foregroundAlreadySuspended = true; // did not start timer disabled - stateDisableEndSession.updateActivityState = false; // update too late on the session - checkEndSession(stateDisableEndSession); - - // enable the SDK again - activityHandler.setEnabled(true); - - SystemClock.sleep(1000); - - // check that is enabled - assertUtil.isTrue(activityHandler.isEnabled()); - - assertUtil.debug("Wrote Activity state"); - - assertUtil.info("Resuming handlers due to SDK being enabled"); - - SystemClock.sleep(2500); - - // it is still paused because it's on the background - checkHandlerStatus(true); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - StateSession secondSessionState = new StateSession(StateSession.SessionType.NEW_SESSION); - secondSessionState.sessionCount = 2; - // test that is not paused anymore - checkStartInternal(secondSessionState); - } - - @Test - public void testSendReferrer() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testSendReferrer"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - long now = System.currentTimeMillis(); - - String referrerBeforeLaunch = "referrerBeforeLaunch"; - - SharedPreferences settings = context.getSharedPreferences(Constants.PREFERENCES_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putString(Constants.REFERRER_PREFKEY, referrerBeforeLaunch); - editor.putLong(Constants.REFERRER_CLICKTIME_PREFKEY, now); - editor.apply(); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - //stateActivityHandlerInit.sendReferrer = referrerBeforeLaunch; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - checkFirstSession(); - - String reftag = "adjust_reftag=referrerValue"; - String extraParams = "adjust_foo=bar&other=stuff&adjust_key=value"; - String mixed = "adjust_foo=bar&other=stuff&adjust_reftag=referrerValue"; - String encodedSeparators = "adjust_foo=b%26a%3B%3Dr&adjust_reftag=referrer%3DValue%26&other=stuff"; - String empty = ""; - String nullString = null; - String single = "adjust_foo"; - String prefix = "adjust_=bar"; - String incomplete = "adjust_foo="; - - activityHandler.sendReferrer(reftag, now); - activityHandler.sendReferrer(extraParams, now); - activityHandler.sendReferrer(mixed, now); - activityHandler.sendReferrer(encodedSeparators, now); - activityHandler.sendReferrer(empty, now); - activityHandler.sendReferrer(nullString, now); - activityHandler.sendReferrer(single, now); - activityHandler.sendReferrer(prefix, now); - activityHandler.sendReferrer(incomplete, now); - SystemClock.sleep(2000); - - assertUtil.verbose("Referrer to parse (%s)", reftag); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", extraParams); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", mixed); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", encodedSeparators); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", single); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", prefix); - assertUtil.test("SdkClickHandler sendSdkClick"); - - assertUtil.verbose("Referrer to parse (%s)", incomplete); - assertUtil.test("SdkClickHandler sendSdkClick"); - - // 7 click - assertUtil.isEqual(8, mockSdkClickHandler.queue.size()); - - ActivityPackage referrerBeforeLaunchPacakge = mockSdkClickHandler.queue.get(0); - - TestActivityPackage referrerBeforeLaunchTest = new TestActivityPackage(referrerBeforeLaunchPacakge); - - referrerBeforeLaunchTest.referrer = referrerBeforeLaunch; - - referrerBeforeLaunchTest.testClickPackage("reftag", true); - - ActivityPackage reftagClickPackage = mockSdkClickHandler.queue.get(1); - - TestActivityPackage reftagClickPackageTest = new TestActivityPackage(reftagClickPackage); - - reftagClickPackageTest.reftag = "referrerValue"; - reftagClickPackageTest.referrer = reftag; - - reftagClickPackageTest.testClickPackage("reftag"); - - // get the click package - ActivityPackage extraParamsClickPackage = mockSdkClickHandler.queue.get(2); - - // create activity package test - TestActivityPackage testExtraParamsClickPackage = new TestActivityPackage(extraParamsClickPackage); - - // other deep link parameters - testExtraParamsClickPackage.otherParameters = "{\"key\":\"value\",\"foo\":\"bar\"}"; - - testExtraParamsClickPackage.referrer = extraParams; - - // test the second deeplink - testExtraParamsClickPackage.testClickPackage("reftag"); - - // get the click package - ActivityPackage mixedClickPackage = mockSdkClickHandler.queue.get(3); - - // create activity package test - TestActivityPackage testMixedClickPackage = new TestActivityPackage(mixedClickPackage); - - testMixedClickPackage.reftag = "referrerValue"; - testMixedClickPackage.referrer = mixed; - - // other deep link parameters - testMixedClickPackage.otherParameters = "{\"foo\":\"bar\"}"; - - // test the third deeplink - testMixedClickPackage.testClickPackage("reftag"); - - // get the click package - ActivityPackage encodedClickPackage = mockSdkClickHandler.queue.get(4); - - // create activity package test - TestActivityPackage testEncodedClickPackage = new TestActivityPackage(encodedClickPackage); - - testEncodedClickPackage.reftag = "referrer=Value&"; - testEncodedClickPackage.referrer = encodedSeparators; - - // other deep link parameters - testEncodedClickPackage.otherParameters = "{\"foo\":\"b&a;=r\"}"; - - // test the third deeplink - testMixedClickPackage.testClickPackage("reftag"); - - // get the click package - ActivityPackage singleClickPackage = mockSdkClickHandler.queue.get(5); - - // create activity package test - TestActivityPackage testSingleClickPackage = new TestActivityPackage(singleClickPackage); - - testSingleClickPackage.referrer = single; - - testSingleClickPackage.testClickPackage("reftag"); - - // get the click package - ActivityPackage prefixClickPackage = mockSdkClickHandler.queue.get(6); - - // create activity package test - TestActivityPackage testPrefixClickPackage = new TestActivityPackage(prefixClickPackage); - - testPrefixClickPackage.referrer = prefix; - - testPrefixClickPackage.testClickPackage("reftag"); - - // get the click package - ActivityPackage incompleteClickPackage = mockSdkClickHandler.queue.get(7); - - // create activity package test - TestActivityPackage testIncompleteClickPackage = new TestActivityPackage(incompleteClickPackage); - - testIncompleteClickPackage.referrer = incomplete; - - testIncompleteClickPackage.testClickPackage("reftag"); - } - - @Test - public void testCheckAttributionState() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testCheckAttributionState"); - - // if it's the first launch - //if (internalState.isFirstLaunch()) { - // if (internalState.hasSessionResponseNotBeenProcessed()) { - // return; - // } - //} - //if (attribution != null && !activityState.askingAttribution) { - // return; - //} - //attributionHandler.getAttribution(); - - AdjustFactory.setSessionInterval(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setOnAttributionChangedListener(new OnAttributionChangedListener() { - @Override - public void onAttributionChanged(AdjustAttribution attribution) { - mockLogger.test("onAttributionChanged " + attribution); - } - }); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - checkInitTests(activityHandler); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // it's first launch - // session response has not been processed - // attribution is null - // -> not called - - StateSession newSessionState = new StateSession(StateSession.SessionType.NEW_SESSION); - newSessionState.getAttributionIsCalled = false; - checkStartInternal(newSessionState); - - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does not call because the session has not been processed - checkSubSession(1, 2, false); - - // it's first launch - // session response has been processed - // attribution is null - // -> called - - // simulate a successful session - SessionResponseData successSessionResponseData = (SessionResponseData) ResponseData.buildResponseData(firstSessionPackage); - successSessionResponseData.success = true; - successSessionResponseData.message = "Session successfully tracked"; - successSessionResponseData.adid = "adidValue"; - - activityHandler.launchSessionResponseTasks(successSessionResponseData); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does call because the session has been processed - checkSubSession(1, 3, true); - - // it's first launch - // session response has been processed - // attribution is not null - // askingAttribution is false - // -> not called - - // save the new attribution - successSessionResponseData.attribution = new AdjustAttribution(); - successSessionResponseData.attribution.trackerName = "trackerName"; - activityHandler.launchSessionResponseTasks(successSessionResponseData); - - activityHandler.setAskingAttribution(false); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does call because the session has been processed - checkSubSession(1, 4, false); - - // it's first launch - // session response has been processed - // attribution is not null - // askingAttribution is true - // -> called - - activityHandler.setAskingAttribution(true); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does call because the session has been processed - checkSubSession(1, 5, true); - - // it's not first launch - // attribution is null - // -> called - - // finish activity handler - activityHandler.teardown(false); - // delete attribution - ActivityHandler.deleteAttribution(context); - - // start new activity handler - SystemClock.sleep(5000); - activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.readActivityState = "ec:0 sc:1 ssc:5"; - - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - newSessionState = new StateSession(StateSession.SessionType.NEW_SESSION); - newSessionState.getAttributionIsCalled = true; - newSessionState.sessionCount = 2; - checkStartInternal(newSessionState); - - // it's not first launch - // attribution is not null - // askingAttribution is true - // -> called - - // save the new attribution - successSessionResponseData.attribution = new AdjustAttribution(); - successSessionResponseData.attribution.trackerName = "trackerName"; - activityHandler.launchSessionResponseTasks(successSessionResponseData); - - activityHandler.setAskingAttribution(true); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does call because the session has been processed - checkSubSession(2, 2, true); - - // it's not first launch - // attribution is not null - // askingAttribution is false - // -> not called - - activityHandler.setAskingAttribution(false); - - // trigger a new sub session - activityHandler.onResume(); - SystemClock.sleep(2000); - - // does call because the session has been processed - checkSubSession(2, 3, false); - } - - @Test - public void testForegroundTimer() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testForegroundTimer"); - - AdjustFactory.setTimerInterval(4000); - AdjustFactory.setTimerStart(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.foregroundTimerStart = 4; - stateActivityHandlerInit.foregroundTimerCycle = 4; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - checkFirstSession(); - - // wait enough to fire the first cycle - SystemClock.sleep(3000); - - checkForegroundTimerFired(true); - - // end subsession to stop timer - activityHandler.onPause(); - - // wait enough for a new cycle - SystemClock.sleep(6000); - - // start a new session - activityHandler.onResume(); - - SystemClock.sleep(1000); - - // check that not enough time passed to fire again - checkForegroundTimerFired(false); - } - - @Test - public void testSendBackground() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testSendBackground"); - - AdjustFactory.setTimerInterval(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // enable send in the background - config.setSendInBackground(true); - - // create activity handler without starting - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // handlers start sending - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.startsSending = true; - stateActivityHandlerInit.sendInBackgroundConfigured = true; - stateActivityHandlerInit.foregroundTimerCycle = 4; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - StateSession newStateSession= new StateSession(StateSession.SessionType.NEW_SESSION); - newStateSession.sendInBackgroundConfigured = true; - newStateSession.toSend = true; - checkStartInternal(newStateSession); - - // end subsession - // background timer starts - stopActivity(activityHandler); - - SystemClock.sleep(1500); - - // session end does not pause the handlers - StateEndSession stateEndSession1 = new StateEndSession(); - stateEndSession1.pausing = false; - stateEndSession1.checkOnPause = true; - stateEndSession1.backgroundTimerStarts = true; - checkEndSession(stateEndSession1); - - // end subsession again - // to test if background timer starts again - stopActivity(activityHandler); - - SystemClock.sleep(1500); - - // session end does not pause the handlers - StateEndSession stateEndSession2 = new StateEndSession(); - stateEndSession2.pausing = false; - stateEndSession2.checkOnPause = true; - stateEndSession2.foregroundAlreadySuspended = true; - checkEndSession(stateEndSession2); - - // wait for background timer launch - SystemClock.sleep(3000); - - // background timer fired - assertUtil.test("PackageHandler sendFirstPackage"); - - // wait enough time - SystemClock.sleep(3000); - - // check that background timer does not fire again - assertUtil.notInTest("PackageHandler sendFirstPackage"); - - activityHandler.trackEvent(new AdjustEvent("abc123")); - - SystemClock.sleep(1000); - - StateEvent stateEvent = new StateEvent(); - stateEvent.backgroundTimerStarts = 4; - checkEvent(stateEvent); - - // disable and enable the sdk while in the background - activityHandler.setEnabled(false); - - SystemClock.sleep(1000); - - // check that it is disabled - assertUtil.isFalse(activityHandler.isEnabled()); - - // check if message the disable of the SDK - assertUtil.info("Pausing handlers due to SDK being disabled"); - - SystemClock.sleep(1000); - - // handlers being paused because of the disable - checkHandlerStatus(true); - - activityHandler.setEnabled(true); - - SystemClock.sleep(1000); - - // check that it is enabled - assertUtil.isTrue(activityHandler.isEnabled()); - - // check if message the enable of the SDK - assertUtil.info("Resuming handlers due to SDK being enabled"); - - SystemClock.sleep(1000); - - // handlers being resumed because of the enable - // even in the background because of the sendInBackground option - checkHandlerStatus(false); - - // set offline and online the sdk while in the background - activityHandler.setOfflineMode(true); - - SystemClock.sleep(1000); - - ActivityHandler.InternalState internalState = activityHandler.getInternalState(); - - // check that it is offline - assertUtil.isTrue(internalState.isOffline()); - - // check if message the offline of the SDK - assertUtil.info("Pausing handlers to put SDK offline mode"); - - SystemClock.sleep(1000); - - // handlers being paused because of the offline - checkHandlerStatus(true); - - activityHandler.setOfflineMode(false); - - SystemClock.sleep(1000); - - // check that it is online - assertUtil.isTrue(internalState.isOnline()); - - // check if message the online of the SDK - assertUtil.info("Resuming handlers to put SDK in online mode"); - - SystemClock.sleep(1000); - - // handlers being resumed because of the online - // even in the background because of the sendInBackground option - checkHandlerStatus(false); - } - - @Test - public void testSessionParameters() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testSessionParameters"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - // create handler and start the first session - config.preLaunchActionsArray = new ArrayList(); - config.preLaunchActionsArray.add(new IRunActivityHandler() { - @Override - public void run(ActivityHandler activityHandler) { - // - activityHandler.addSessionCallbackParameterI("cKey", "cValue"); - activityHandler.addSessionCallbackParameterI("cFoo", "cBar"); - - activityHandler.addSessionCallbackParameterI("cKey", "cValue2"); - activityHandler.resetSessionCallbackParametersI(); - - activityHandler.addSessionCallbackParameterI("cKey", "cValue"); - activityHandler.addSessionCallbackParameterI("cFoo", "cBar"); - activityHandler.removeSessionCallbackParameterI("cKey"); - - // - activityHandler.addSessionPartnerParameterI("pKey", "pValue"); - activityHandler.addSessionPartnerParameterI("pFoo", "pBar"); - - activityHandler.addSessionPartnerParameterI("pKey", "pValue2"); - activityHandler.resetSessionPartnerParametersI(); - - activityHandler.addSessionPartnerParameterI("pKey", "pValue"); - activityHandler.addSessionPartnerParameterI("pFoo", "pBar"); - activityHandler.removeSessionPartnerParameterI("pKey"); - } - }); - - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - checkInitTests(activityHandler); - - checkSessionParameters(); - - resumeActivity(activityHandler); - - AdjustEvent firstEvent = new AdjustEvent("event1"); - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1500); - - // test session - checkFirstSession(); - - StateEvent stateEvent1 = new StateEvent(); - checkEvent(stateEvent1); - - // 1 session + 1 event - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - // get the session package - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - - // create event package test - TestActivityPackage testFirstSessionPackage = new TestActivityPackage(firstSessionPackage); - - // set event test parameters - testFirstSessionPackage.callbackParams = "{\"cFoo\":\"cBar\"}"; - testFirstSessionPackage.partnerParams = "{\"pFoo\":\"pBar\"}"; - - testFirstSessionPackage.testSessionPackage(1); - - // get the event - ActivityPackage firstEventPackage = mockPackageHandler.queue.get(1); - - // create event package test - TestActivityPackage testFirstEventPackage = new TestActivityPackage(firstEventPackage); - - // set event test parameters - testFirstEventPackage.eventCount = "1"; - testFirstEventPackage.suffix = "'event1'"; - testFirstEventPackage.callbackParams = "{\"cFoo\":\"cBar\"}"; - testFirstEventPackage.partnerParams = "{\"pFoo\":\"pBar\"}"; - - testFirstEventPackage.testEventPackage("event1"); - - // end current session - stopActivity(activityHandler); - SystemClock.sleep(1000); - - checkEndSession(); - activityHandler.teardown(false); - activityHandler = null; - - AdjustConfig newConfig = getConfig(); - ActivityHandler restartActivityHandler = getActivityHandler(newConfig); - - SystemClock.sleep(1500); - - // start new one - // delay start not configured because activity state is already created - StateActivityHandlerInit restartActivityHandlerInit = new StateActivityHandlerInit(restartActivityHandler); - restartActivityHandlerInit.activityStateAlreadyCreated = true; - restartActivityHandlerInit.readActivityState = "ec:1 sc:1"; - restartActivityHandlerInit.readCallbackParameters = "{cFoo=cBar}"; - restartActivityHandlerInit.readPartnerParameters = "{pFoo=pBar}"; - - // test init values - checkInitTests(restartActivityHandlerInit); - - resumeActivity(restartActivityHandler); - - SystemClock.sleep(1500); - - StateSession stateRestartSession = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - stateRestartSession.subsessionCount = 2; - stateRestartSession.eventCount = 1; - - checkStartInternal(stateRestartSession); - - // create the second Event - AdjustEvent secondEvent = new AdjustEvent("event2"); - secondEvent.addCallbackParameter("ceFoo", "ceBar"); - secondEvent.addPartnerParameter("peFoo", "peBar"); - - restartActivityHandler.trackEvent(secondEvent); - - AdjustEvent thirdEvent = new AdjustEvent("event3"); - thirdEvent.addCallbackParameter("cFoo", "ceBar"); - thirdEvent.addPartnerParameter("pFoo", "peBar"); - - restartActivityHandler.trackEvent(thirdEvent); - - SystemClock.sleep(1500); - - // 2 events - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - // get the event - ActivityPackage secondEventPackage = mockPackageHandler.queue.get(0); - - // create event package test - TestActivityPackage testSecondEventPackage = new TestActivityPackage(secondEventPackage); - - // set event test parameters - testSecondEventPackage.eventCount = "2"; - testSecondEventPackage.suffix = "'event2'"; - testSecondEventPackage.callbackParams = "{\"ceFoo\":\"ceBar\",\"cFoo\":\"cBar\"}"; - testSecondEventPackage.partnerParams = "{\"peFoo\":\"peBar\",\"pFoo\":\"pBar\"}"; - - testSecondEventPackage.testEventPackage("event2"); - - // get the event - ActivityPackage thirdEventPackage = mockPackageHandler.queue.get(1); - - // create event package test - TestActivityPackage testThirdEventPackage = new TestActivityPackage(thirdEventPackage); - - // set event test parameters - testThirdEventPackage.eventCount = "3"; - testThirdEventPackage.suffix = "'event3'"; - testThirdEventPackage.callbackParams = "{\"cFoo\":\"ceBar\"}"; - testThirdEventPackage.partnerParams = "{\"pFoo\":\"peBar\"}"; - - testThirdEventPackage.testEventPackage("event3"); - } - - private void checkSessionParameters() { - // - assertUtil.debug("Wrote Session Callback parameters: {cKey=cValue}"); - assertUtil.debug("Wrote Session Callback parameters: {cKey=cValue, cFoo=cBar}"); - - assertUtil.warn("Key cKey will be overwritten"); - assertUtil.debug("Wrote Session Callback parameters: {cKey=cValue2, cFoo=cBar}"); - - assertUtil.debug("Wrote Session Callback parameters: null"); - - assertUtil.debug("Wrote Session Callback parameters: {cKey=cValue}"); - assertUtil.debug("Wrote Session Callback parameters: {cKey=cValue, cFoo=cBar}"); - - assertUtil.debug("Key cKey will be removed"); - assertUtil.debug("Wrote Session Callback parameters: {cFoo=cBar}"); - - // - assertUtil.debug("Wrote Session Partner parameters: {pKey=pValue}"); - assertUtil.debug("Wrote Session Partner parameters: {pKey=pValue, pFoo=pBar}"); - - assertUtil.warn("Key pKey will be overwritten"); - assertUtil.debug("Wrote Session Partner parameters: {pKey=pValue2, pFoo=pBar}"); - - assertUtil.debug("Wrote Session Partner parameters: null"); - - assertUtil.debug("Wrote Session Partner parameters: {pKey=pValue}"); - assertUtil.debug("Wrote Session Partner parameters: {pKey=pValue, pFoo=pBar}"); - - assertUtil.debug("Key pKey will be removed"); - assertUtil.debug("Wrote Session Partner parameters: {pFoo=pBar}"); - } - - @Test - public void testDelayStartTimerFirst() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testDelayStartTimerFirst"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setDelayStart(4); - - config.preLaunchActionsArray = new ArrayList(); - config.preLaunchActionsArray.add(new IRunActivityHandler() { - @Override - public void run(ActivityHandler activityHandler) { - activityHandler.addSessionCallbackParameterI("scpKey", "scpValue"); - activityHandler.addSessionPartnerParameterI("sppKey", "sppValue"); - } - }); - - // create handler and start the first session - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.delayStartConfigured = true; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - resumeActivity(activityHandler); - - SystemClock.sleep(1000); - - StateSession newStateSession = new StateSession(StateSession.SessionType.NEW_SESSION); - // delay start means it starts paused - newStateSession.toSend = false; - // sdk click handler does not start paused - newStateSession.sdkClickHandlerAlsoStartsPaused = false; - // delay configured - newStateSession.delayStart = "4.0"; - - checkStartInternal(newStateSession); - - // change state session for non session - StateSession nonSession = new StateSession(StateSession.SessionType.NONSESSION); - // delay already processed - nonSession.delayStart = null; - nonSession.toSend = false; - nonSession.sdkClickHandlerAlsoStartsPaused = false; - nonSession.foregroundTimerAlreadyStarted = true; - - checkStartInternal(nonSession); - - // create the first Event object with callback and partner parameters - AdjustEvent firstEvent = new AdjustEvent("event1"); - - firstEvent.addCallbackParameter("keyCall", "valueCall"); - firstEvent.addPartnerParameter("keyPartner", "valuePartner"); - - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1000); - - StateEvent stateEvent = new StateEvent(); - checkEvent(stateEvent); - - SystemClock.sleep(4000); - - assertUtil.verbose("Delay Start timer fired"); - - checkSendFirstPackages(true, activityHandler.getInternalState(), true, false); - - activityHandler.sendFirstPackages(); - SystemClock.sleep(1000); - - checkSendFirstPackages(false, activityHandler.getInternalState(), true, false); - - // 1 session + 1 event - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - // get the first event - ActivityPackage firstEventPackage = mockPackageHandler.queue.get(1); - - // create event package test - TestActivityPackage testFirstEventPackage = new TestActivityPackage(firstEventPackage); - - // set event test parameters - testFirstEventPackage.eventCount = "1"; - testFirstEventPackage.savedCallbackParameters = new HashMap(1); - testFirstEventPackage.savedCallbackParameters.put("keyCall", "valueCall"); - testFirstEventPackage.savedPartnerParameters = new HashMap(1); - testFirstEventPackage.savedPartnerParameters.put("keyPartner", "valuePartner"); - testFirstEventPackage.suffix = "'event1'"; - - // test first event - testFirstEventPackage.testEventPackage("event1"); - } - - @Test - public void testDelayStartSendFirst() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testDelayStartSendFirst"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setDelayStart(5); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.delayStartConfigured = true; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - resumeActivity(activityHandler); - - SystemClock.sleep(1000); - - StateSession newStateSession = new StateSession(StateSession.SessionType.NEW_SESSION); - // delay start means it starts paused - newStateSession.toSend = false; - // sdk click handler does not start paused - newStateSession.sdkClickHandlerAlsoStartsPaused = false; - // delay configured - newStateSession.delayStart = "5.0"; - - checkStartInternal(newStateSession); - - // change state session for non session - StateSession nonSession = new StateSession(StateSession.SessionType.NONSESSION); - // delay already processed - nonSession.delayStart = null; - nonSession.toSend = false; - nonSession.sdkClickHandlerAlsoStartsPaused = false; - nonSession.foregroundTimerAlreadyStarted = true; - - checkStartInternal(nonSession); - - activityHandler.sendFirstPackages(); - - SystemClock.sleep(3000); - - assertUtil.notInVerbose("Delay Start timer fired"); - - checkSendFirstPackages(true,activityHandler.getInternalState(), true, false); - - activityHandler.sendFirstPackages(); - SystemClock.sleep(1000); - - checkSendFirstPackages(false,activityHandler.getInternalState(), true, false); - } - - @Test - public void testPushToken() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testPushToken"); - - AdjustConfig config = getConfig(); - // set the push token before the sdk starts - config.pushToken = "preStartPushToken"; - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.pushToken = "preStartPushToken"; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - checkFirstSession(); - - // create the first Event - AdjustEvent firstEvent = new AdjustEvent("event1"); - - // track event - activityHandler.trackEvent(firstEvent); - - SystemClock.sleep(1500); - - // checking the default values of the first session package - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - ActivityPackage activityPackage = mockPackageHandler.queue.get(0); - - // create activity package test - TestActivityPackage testActivityPackage = new TestActivityPackage(activityPackage); - testActivityPackage.pushToken = "preStartPushToken"; - - // set first session - testActivityPackage.testSessionPackage(1); - - // first event - ActivityPackage firstEventPackage = mockPackageHandler.queue.get(1); - - // create event package test - TestActivityPackage testFirstEventPackage = new TestActivityPackage(firstEventPackage); - - // set event test parameters - testFirstEventPackage.eventCount = "1"; - testFirstEventPackage.suffix = "'event1'"; - testFirstEventPackage.pushToken = "preStartPushToken"; - - // test first event - testFirstEventPackage.testEventPackage("event1"); - - // try to update with the same push token - activityHandler.setPushToken("preStartPushToken"); - SystemClock.sleep(1500); - - // should not have added a new package either in the package handler - assertUtil.isEqual(2, mockPackageHandler.queue.size()); - - // nor the click handler - assertUtil.notInTest("SdkClickHandler sendSdkClick"); - assertUtil.isEqual(0, mockSdkClickHandler.queue.size()); - - // update with new push token - activityHandler.setPushToken("newPushToken"); - SystemClock.sleep(1500); - - // check it was added to sdk click handler - assertUtil.notInTest("SdkClickHandler sendSdkClick"); - assertUtil.isEqual(0, mockSdkClickHandler.queue.size()); - - // check that info package was added - assertUtil.test("PackageHandler addPackage"); - - // check that event was sent to package handler - assertUtil.test("PackageHandler sendFirstPackage"); - - // checking that the info package was added - assertUtil.isEqual(3, mockPackageHandler.queue.size()); - - // get the click package - ActivityPackage sdkInfoPackage = mockPackageHandler.queue.get(2); - - // create activity package test - TestActivityPackage testInfoPackage = new TestActivityPackage(sdkInfoPackage); - - testInfoPackage.pushToken = "newPushToken"; - - // test the first deeplink - testInfoPackage.testInfoPackage("push"); - } - - @Test - public void testUpdateStart() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testUpdateStart"); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setDelayStart(10.1); - - ActivityHandler activityHandler = getActivityHandler(config); - SystemClock.sleep(1500); - - // test init values - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.delayStartConfigured = true; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - SystemClock.sleep(1000); - - StateSession newStateSession = new StateSession(StateSession.SessionType.NEW_SESSION); - // delay start means it starts paused - newStateSession.toSend = false; - // sdk click handler does not start paused - newStateSession.sdkClickHandlerAlsoStartsPaused = false; - // delay configured - newStateSession.delayStart = "10.0"; - - stopActivity(activityHandler); - SystemClock.sleep(1000); - - StateEndSession stateEndSession = new StateEndSession(); - checkEndSession(stateEndSession); - - activityHandler.teardown(false); - activityHandler = null; - - SystemClock.sleep(1000); - - ActivityHandler restartActivityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // start new one - // delay start not configured because activity state is already created - StateActivityHandlerInit restartActivityHandlerInit = new StateActivityHandlerInit(restartActivityHandler); - restartActivityHandlerInit.activityStateAlreadyCreated = true; - restartActivityHandlerInit.readActivityState = "ec:0 sc:1"; - restartActivityHandlerInit.updatePackages = true; - - // test init values - checkInitTests(restartActivityHandlerInit); - - resumeActivity(restartActivityHandler); - - SystemClock.sleep(1500); - - StateSession stateRestartSession = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - stateRestartSession.activityStateAlreadyCreated = true; - stateRestartSession.subsessionCount = 2; - - checkStartInternal(stateRestartSession); - } - - @Test - public void testLogLevel() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testLogLevel"); - - AdjustConfig config = getConfig(); - - config.setLogLevel(LogLevel.VERBOSE); - config.setLogLevel(LogLevel.DEBUG); - config.setLogLevel(LogLevel.INFO); - config.setLogLevel(LogLevel.WARN); - config.setLogLevel(LogLevel.ERROR); - config.setLogLevel(LogLevel.ASSERT); - - assertUtil.test("MockLogger setLogLevel: " + LogLevel.VERBOSE + ", isProductionEnvironment: false"); - assertUtil.test("MockLogger setLogLevel: " + LogLevel.DEBUG + ", isProductionEnvironment: false"); - assertUtil.test("MockLogger setLogLevel: " + LogLevel.INFO + ", isProductionEnvironment: false"); - assertUtil.test("MockLogger setLogLevel: " + LogLevel.WARN + ", isProductionEnvironment: false"); - assertUtil.test("MockLogger setLogLevel: " + LogLevel.ERROR + ", isProductionEnvironment: false"); - assertUtil.test("MockLogger setLogLevel: " + LogLevel.ASSERT + ", isProductionEnvironment: false"); - - config.setLogLevel(LogLevel.SUPRESS); - - // chooses Assert because config object was not configured to allow suppress - //assertUtil.test("MockLogger setLogLevel: " + LogLevel.ASSERT); - // changed when log in production was introduced - assertUtil.test("MockLogger setLogLevel: " + LogLevel.SUPRESS + ", isProductionEnvironment: false"); - - // init log level with assert because it was not configured to allow suppress - config = getConfig("production", "123456789012", false, context); - - config.setLogLevel(LogLevel.SUPRESS); - - // chooses Assert because config object was not configured to allow suppress - //assertUtil.test("MockLogger setLogLevel: " + LogLevel.ASSERT); - // changed when log in production was introduced - assertUtil.test("MockLogger setLogLevel: " + LogLevel.SUPRESS + ", isProductionEnvironment: true"); - - // init with info because it's sandbox - config = getConfig("sandbox", "123456789012", true, context); - - config.setLogLevel(LogLevel.SUPRESS); - // chooses Supress because config object was configured to allow suppress - assertUtil.test("MockLogger setLogLevel: " + LogLevel.SUPRESS + ", isProductionEnvironment: false"); - - // init with info because it's sandbox - config = getConfig("production", "123456789012", true, context); - - config.setLogLevel(LogLevel.ASSERT); - - // chooses Supress because config object was configured to allow suppress - //assertUtil.test("MockLogger setLogLevel: " + LogLevel.SUPRESS); - // changed when log in production was introduced - assertUtil.test("MockLogger setLogLevel: " + LogLevel.ASSERT + ", isProductionEnvironment: true"); - } - - @Test - public void testTeardown() { - // assert test name to read better in logcat - mockLogger.Assert("TestActivityHandler testTeardown"); - - // change the timer defaults - AdjustFactory.setTimerInterval(4000); - - // create the config to start the session - AdjustConfig config = getConfig(); - - config.setDelayStart(4); - - // enable send in the background - config.setSendInBackground(true); - - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - // handlers start sending - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - stateActivityHandlerInit.startsSending = false; - stateActivityHandlerInit.sendInBackgroundConfigured = true; - stateActivityHandlerInit.foregroundTimerCycle = 4; - stateActivityHandlerInit.delayStartConfigured = true; - stateActivityHandlerInit.sdkClickHandlerAlsoStartsPaused = false; - checkInitTests(stateActivityHandlerInit); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - StateSession newStateSession= new StateSession(StateSession.SessionType.NEW_SESSION); - newStateSession.sendInBackgroundConfigured = true; - newStateSession.toSend = false; - newStateSession.sdkClickHandlerAlsoStartsPaused = false; - newStateSession.delayStart = "4.0"; - checkStartInternal(newStateSession); - - activityHandler.teardown(false); - - assertUtil.test("PackageHandler teardown deleteState, false"); - assertUtil.test("AttributionHandler teardown"); - assertUtil.test("SdkClickHandler teardown"); - - activityHandler.teardown(false); - - assertUtil.notInTest("PackageHandler teardown deleteState, false"); - assertUtil.notInTest("AttributionHandler teardown"); - assertUtil.notInTest("SdkClickHandler teardown"); - } - - private AdjustConfig getConfig() { - return getConfig("sandbox", "123456789012", false, context); - } - - private AdjustConfig getConfig(String environment, - String appToken, - boolean allowSupressLogLevel, - Context context) - { - AdjustConfig adjustConfig = null; - - if (allowSupressLogLevel) { - adjustConfig = new AdjustConfig(context, appToken, environment, allowSupressLogLevel); - } else { - adjustConfig = new AdjustConfig(context, appToken, environment); - } - - if (adjustConfig != null) { - if (environment == "sandbox") { - assertUtil.test("MockLogger setLogLevel: " + LogLevel.INFO + ", isProductionEnvironment: " + false); - assertUtil.warn("SANDBOX: Adjust is running in Sandbox mode. Use this setting for testing. Don't forget to set the environment to `production` before publishing!"); - } else if (environment == "production" && !allowSupressLogLevel) { - assertUtil.test("MockLogger setLogLevel: " + LogLevel.INFO + ", isProductionEnvironment: " + true); - assertUtil.warn("PRODUCTION: Adjust is running in Production mode. Use this setting only for the build that you want to publish. Set the environment to `sandbox` if you want to test your app!"); - } else if (environment == "production" && allowSupressLogLevel) { - assertUtil.test("MockLogger setLogLevel: " + LogLevel.SUPRESS + ", isProductionEnvironment: " + true); - assertUtil.warn("PRODUCTION: Adjust is running in Production mode. Use this setting only for the build that you want to publish. Set the environment to `sandbox` if you want to test your app!"); - } else { - assertUtil.fail(); - } - } - - return adjustConfig; - } - - private ActivityHandler startAndCheckFirstSession(AdjustConfig config) { - // start activity handler with config - ActivityHandler activityHandler = getActivityHandler(config); - - SystemClock.sleep(1500); - - startAndCheckFirstSession(activityHandler); - - return activityHandler; - } - - private void startAndCheckFirstSession(ActivityHandler activityHandler) { - // test init values - checkInitTests(activityHandler); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - // test session - checkFirstSession(); - } - - private ActivityHandler getActivityHandler(AdjustConfig config) { - ActivityHandler activityHandler = ActivityHandler.getInstance(config); - - if (activityHandler != null) { - assertUtil.test("MockLogger lockLogLevel"); - - ActivityHandler.InternalState internalState = activityHandler.getInternalState(); - // test default values - assertUtil.isTrue(internalState.isEnabled()); - assertUtil.isTrue(internalState.isOnline()); - assertUtil.isTrue(internalState.isInBackground()); - assertUtil.isTrue(internalState.isNotInDelayedStart()); - assertUtil.isFalse(internalState.itHasToUpdatePackages()); - } - - return activityHandler; - } - - private void checkInitAndStart(ActivityHandler activityHandler, StateActivityHandlerInit initState, StateSession stateSession) { - checkInitTests(initState); - - resumeActivity(activityHandler); - - SystemClock.sleep(1500); - - checkStartInternal(stateSession); - } - - private void checkInitTests(ActivityHandler activityHandler) { - StateActivityHandlerInit stateActivityHandlerInit = new StateActivityHandlerInit(activityHandler); - checkInitTests(stateActivityHandlerInit); - } - - private void checkInitTests(StateActivityHandlerInit sInit) { - checkReadFile(sInit.readAttribution, "Attribution"); - checkReadFile(sInit.readActivityState, "Activity state"); - checkReadFile(sInit.readCallbackParameters, "Session Callback parameters"); - checkReadFile(sInit.readPartnerParameters, "Session Partner parameters"); - - // check values read from activity state - assertUtil.isEqual(sInit.internalState.isEnabled(), sInit.startEnabled); - //assertUtil.isEqual(sInit.internalState.itHasToUpdatePackages(), sInit.updatePackages); - - // check event buffering - if (sInit.eventBufferingIsEnabled) { - assertUtil.info("Event buffering is enabled"); - } else { - assertUtil.notInInfo("Event buffering is enabled"); - } - - // check Google play is set - assertUtil.info("Google Play Services Advertising ID read correctly at start time"); - - // check default tracker - if (sInit.defaultTracker != null) { - assertUtil.info("Default tracker: '%s'", sInit.defaultTracker); - } else { - assertUtil.notInInfo("Default tracker: "); - } - - // check push token - if (sInit.pushToken != null) { - assertUtil.info("Push token: '%s'", sInit.pushToken); - } else { - assertUtil.notInInfo("Push token: "); - } - - // check foreground timer was created - assertUtil.verbose("Foreground timer configured to fire after "+ sInit.foregroundTimerStart - + ".0 seconds of starting and cycles every " + sInit.foregroundTimerCycle + ".0 seconds"); - - // check background timer was created - if (sInit.sendInBackgroundConfigured) { - assertUtil.info("Send in background configured"); - } else { - assertUtil.notInInfo("Send in background configured"); - } - - if (sInit.delayStartConfigured) { - assertUtil.info("Delay start configured"); - assertUtil.isTrue(sInit.internalState.isInDelayedStart()); - } else { - assertUtil.notInInfo("Delay start configured"); - assertUtil.isFalse(sInit.internalState.isInDelayedStart()); - } - - if (sInit.startsSending) { - assertUtil.test("PackageHandler init, startsSending: true"); - assertUtil.test("AttributionHandler init, startsSending: true"); - assertUtil.test("SdkClickHandler init, startsSending: true"); - } else { - assertUtil.test("PackageHandler init, startsSending: false"); - assertUtil.test("AttributionHandler init, startsSending: false"); - if (sInit.sdkClickHandlerAlsoStartsPaused) { - assertUtil.test("SdkClickHandler init, startsSending: false"); - } else { - assertUtil.test("SdkClickHandler init, startsSending: true"); - } - } - - if (sInit.updatePackages) { - checkUpdatePackages(sInit.internalState, sInit.activityStateAlreadyCreated); - } else { - assertUtil.notInTest("PackageHandler updatePackages"); - } - - if (sInit.sendReferrer != null) { - assertUtil.verbose("Referrer to parse (%s)", sInit.sendReferrer); - assertUtil.test("SdkClickHandler sendSdkClick"); - } else { - assertUtil.notInVerbose("Referrer to parse "); - assertUtil.notInTest("SdkClickHandler sendSdkClick"); - } - } - - private void checkReadFile(String fileLog, String objectName) { - if (fileLog == null) { - assertUtil.debug(objectName + " file not found"); - } else { - assertUtil.debug("Read "+ objectName +": " + fileLog); - } - } - - private void resumeActivity(ActivityHandler activityHandler) { - // start activity - activityHandler.onResume(); - - ActivityHandler.InternalState internalState = activityHandler.getInternalState(); - - // comes to the foreground - assertUtil.isTrue(internalState.isInForeground()); - } - - private void checkFirstSession() { - StateSession newStateSession= new StateSession(StateSession.SessionType.NEW_SESSION); - checkStartInternal(newStateSession); - } - - private void checkSubSession(int sessionCount, int subsessionCount, boolean getAttributionIsCalled) { - StateSession subSessionState = new StateSession(StateSession.SessionType.NEW_SUBSESSION); - subSessionState.sessionCount = sessionCount; - subSessionState.subsessionCount = subsessionCount; - subSessionState.getAttributionIsCalled = getAttributionIsCalled; - subSessionState.foregroundTimerAlreadyStarted = true; - checkStartInternal(subSessionState); - } - - private void checkFurtherSessions(int sessionCount, boolean getAttributionIsCalled) { - StateSession subSessionState = new StateSession(StateSession.SessionType.NEW_SESSION); - subSessionState.sessionCount = sessionCount; - subSessionState.getAttributionIsCalled = getAttributionIsCalled; - subSessionState.foregroundTimerAlreadyStarted = true; - checkStartInternal(subSessionState); - } - - private void checkStartInternal(StateSession stateSession) - { - // check delay start - checkDelayStart(stateSession); - - // check onResume - checkOnResume(stateSession); - - // update Handlers Status - checkHandlerStatus((stateSession.disabled ? null : !stateSession.toSend), stateSession.eventBufferingIsEnabled, stateSession.sdkClickHandlerAlsoStartsPaused); - - // process Session - switch (stateSession.sessionType) { - case NEW_SESSION: - // if the package was build, it was sent to the Package Handler - assertUtil.test("PackageHandler addPackage"); - - // after adding, the activity handler ping the Package handler to send the package - assertUtil.test("PackageHandler sendFirstPackage"); - - // writes activity state - assertUtil.debug("Wrote Activity state: " + - "ec:" + stateSession.eventCount + " sc:" + stateSession.sessionCount + " ssc:" + stateSession.subsessionCount); - break; - case NEW_SUBSESSION: - // test the subsession message - assertUtil.verbose("Started subsession " + stateSession.subsessionCount + " of session " + stateSession.sessionCount); - // writes activity state - assertUtil.debug("Wrote Activity state: " + - "ec:" + stateSession.eventCount + " sc:" + stateSession.sessionCount + " ssc:" + stateSession.subsessionCount); - break; - case NONSESSION: - // stopped for a short time, not enough for a new sub subsession - assertUtil.verbose("Time span since last activity too short for a new subsession"); - // does not writes activity state - assertUtil.notInDebug("Wrote Activity state: "); - break; - case TIME_TRAVEL: - assertUtil.error("Time travel!"); - // writes activity state - assertUtil.debug("Wrote Activity state: " + - "ec:" + stateSession.eventCount + " sc:" + stateSession.sessionCount + " ssc:" + stateSession.subsessionCount); - break; - case DISABLED: - assertUtil.notInTest("PackageHandler addPackage"); - assertUtil.notInVerbose("Started subsession "); - assertUtil.notInVerbose("Time span since last activity too short for a new subsession"); - assertUtil.notInError("Time travel!"); - break; - } - - /* - // after processing the session, writes the activity state - if (stateSession.sessionType != stateSession.sessionType.NONSESSION && - stateSession.sessionType != stateSession.sessionType.DISABLED) - { - assertUtil.debug("Wrote Activity state: " + - "ec:" + stateSession.eventCount + " sc:" + stateSession.sessionCount + " ssc:" + stateSession.subsessionCount); - } else { - - } - */ - // check Attribution State - if (stateSession.getAttributionIsCalled != null) { - if (stateSession.getAttributionIsCalled) { - assertUtil.test("AttributionHandler getAttribution"); - } else { - assertUtil.notInTest("AttributionHandler getAttribution"); - } - } - } - - private void checkDelayStart(StateSession stateSession) { - if (stateSession.delayStart == null) { - assertUtil.notInWarn("Waiting"); - return; - } - - if (stateSession.delayStart.equals("10.1")) { - assertUtil.warn("Delay start of 10.1 seconds bigger than max allowed value of 10.0 seconds"); - stateSession.delayStart = "10.0"; - } - - assertUtil.info("Waiting " + stateSession.delayStart + " seconds before starting first session"); - - assertUtil.verbose("Delay Start timer starting. Launching in " + stateSession.delayStart + " seconds"); - - if (stateSession.activityStateAlreadyCreated) { - assertUtil.verbose("Wrote Activity state"); - } - } - - private void checkOnResume(StateSession stateSession) { - if (!stateSession.startSubsession) { - assertUtil.notInVerbose("Background timer canceled"); - assertUtil.notInVerbose("Foreground timer is already started"); - assertUtil.notInVerbose("Foreground timer starting"); - assertUtil.notInVerbose("Subsession start"); - return; - } - // TODO check delay start - - // stops background timer - if (stateSession.sendInBackgroundConfigured) { - assertUtil.verbose("Background timer canceled"); - } else { - assertUtil.notInVerbose("Background timer canceled"); - } - - // start foreground timer - if (stateSession.foregroundTimerStarts) { - if (stateSession.foregroundTimerAlreadyStarted) { - assertUtil.verbose("Foreground timer is already started"); - } else { - assertUtil.verbose("Foreground timer starting"); - } - } else { - assertUtil.notInVerbose("Foreground timer is already started"); - assertUtil.notInVerbose("Foreground timer starting"); - } - - // starts the subsession - assertUtil.verbose("Subsession start"); - } - - private void checkHandlerStatus(Boolean pausing) { - checkHandlerStatus(pausing, false, true); - } - - private void checkHandlerStatus(Boolean pausing, boolean eventBufferingEnabled, boolean sdkClickHandlerAlsoPauses) { - if (pausing == null) { - assertUtil.notInTest("AttributionHandler pauseSending"); - assertUtil.notInTest("PackageHandler pauseSending"); - assertUtil.notInTest("SdkClickHandler pauseSending"); - assertUtil.notInTest("AttributionHandler resumeSending"); - assertUtil.notInTest("PackageHandler resumeSending"); - assertUtil.notInTest("SdkClickHandler resumeSending"); - return; - } - if (pausing) { - assertUtil.test("AttributionHandler pauseSending"); - assertUtil.test("PackageHandler pauseSending"); - if (sdkClickHandlerAlsoPauses) { - assertUtil.test("SdkClickHandler pauseSending"); - } else { - assertUtil.test("SdkClickHandler resumeSending"); - } - } else { - assertUtil.test("AttributionHandler resumeSending"); - assertUtil.test("PackageHandler resumeSending"); - assertUtil.test("SdkClickHandler resumeSending"); - if (!eventBufferingEnabled) { - assertUtil.test("PackageHandler sendFirstPackage"); - } - } - } - - private void checkEvent(StateEvent stateEvent) { - if (stateEvent.disabled) { - assertUtil.notInInfo("Skipping duplicated order ID "); - assertUtil.notInVerbose("Added order ID "); - assertUtil.notInTest("PackageHandler addPackage"); - assertUtil.notInInfo("Buffered event "); - assertUtil.notInTest("PackageHandler sendFirstPackage"); - return; - } - if (stateEvent.duplicatedOrderId) { - // dropping duplicate transaction id - assertUtil.info("Skipping duplicated order ID '" + stateEvent.orderId + "'"); - // check that event package was not added - assertUtil.notInTest("PackageHandler addPackage"); - return; - } - - if (stateEvent.orderId != null) { - // check order id was added - assertUtil.verbose("Added order ID '" + stateEvent.orderId + "'"); - } else { - // check order id was not added - assertUtil.notInVerbose("Added order ID"); - } - - // check that event package was added - assertUtil.test("PackageHandler addPackage"); - - if(stateEvent.bufferedSuffix != null) { - // check that event was buffered - assertUtil.info("Buffered event " + stateEvent.bufferedSuffix); - - // and not sent to package handler - assertUtil.notInTest("PackageHandler sendFirstPackage"); - } else { - // check that event was sent to package handler - assertUtil.test("PackageHandler sendFirstPackage"); - // and not buffered - assertUtil.notInInfo("Buffered event"); - } - - if (stateEvent.backgroundTimerStarts != null) { - // does not fire background timer - assertUtil.verbose("Background timer starting. Launching in " + stateEvent.backgroundTimerStarts + ".0 seconds"); - } else { - // does not fire background timer - assertUtil.notInVerbose("Background timer starting"); - } - - // after tracking the event it should write the activity state - if (stateEvent.activityStateSuffix != null) { - assertUtil.debug("Wrote Activity state: " + stateEvent.activityStateSuffix); - } else { - assertUtil.debug("Wrote Activity state"); - } - } - - private void stopActivity(ActivityHandler activityHandler) { - // stop activity - activityHandler.onPause(); - - ActivityHandler.InternalState internalState = activityHandler.getInternalState(); - - // goes to the background - assertUtil.isTrue(internalState.isInBackground()); - } - - private void checkEndSession() { - StateEndSession stateEndSession = new StateEndSession(); - checkEndSession(stateEndSession); - } - - private void checkEndSession(StateEndSession stateEndSession) - { - if (stateEndSession.checkOnPause) { - checkOnPause(stateEndSession.foregroundAlreadySuspended, stateEndSession.backgroundTimerStarts); - } - - if (stateEndSession.pausing) { - checkHandlerStatus(stateEndSession.pausing, stateEndSession.eventBufferingEnabled, true); - } - - if (stateEndSession.updateActivityState) { - assertUtil.debug("Wrote Activity state: "); - } else { - assertUtil.notInDebug("Wrote Activity state: "); - } - } - - private void checkOnPause(boolean foregroundAlreadySuspended, - boolean backgroundTimerStarts) { - // stop foreground timer - if (foregroundAlreadySuspended) { - assertUtil.verbose("Foreground timer is already suspended"); - } else { - assertUtil.verbose("Foreground timer suspended"); - } - - // start background timer - if (backgroundTimerStarts) { - assertUtil.verbose("Background timer starting."); - } else { - assertUtil.notInVerbose("Background timer starting."); - } - - // starts the subsession - assertUtil.verbose("Subsession end"); - } - - private void checkForegroundTimerFired(boolean timerFired) { - // timer fired - if (timerFired) { - assertUtil.verbose("Foreground timer fired"); - } else { - assertUtil.notInVerbose("Foreground timer fired"); - } - } - - private void checkSendFirstPackages(boolean delayStart, - ActivityHandler.InternalState internalState, - boolean activityStateCreated, - boolean pausing) - { - if (!delayStart) { - assertUtil.info("Start delay expired or never configured"); - // did not update package - assertUtil.notInTest("PackageHandler updatePackages"); - return; - } - assertUtil.notInInfo("Start delay expired or never configured"); - - // update packages - checkUpdatePackages(internalState, activityStateCreated); - - // no longer is in delay start - assertUtil.isFalse(internalState.delayStart); - - // cancel timer - assertUtil.verbose("Delay Start timer canceled"); - - checkHandlerStatus(pausing, false, false); - } - - private void checkUpdatePackages(ActivityHandler.InternalState internalState, - boolean activityStateCreated) { - // update packages - assertUtil.test("PackageHandler updatePackages"); - assertUtil.isFalse(internalState.updatePackages); - if (activityStateCreated) { - assertUtil.debug("Wrote Activity state"); - } else { - assertUtil.notInDebug("Wrote Activity state"); - } - - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java deleted file mode 100644 index 349c547b5..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestActivityPackage.java +++ /dev/null @@ -1,479 +0,0 @@ -package com.adjust.sdk; - -import com.adjust.sdk.ActivityKind; -import com.adjust.sdk.ActivityPackage; -import com.adjust.sdk.AdjustAttribution; -import com.adjust.sdk.Constants; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; - -import junit.framework.Assert; - -import java.util.Map; - -/** - * Created by pfms on 09/01/15. - */ -public class TestActivityPackage { - - private ActivityPackage activityPackage; - private Map parameters; - public String appToken; - public String environment; - public String clientSdk; - public Boolean deviceKnow; - public boolean playServices; - public boolean eventBufferingEnabled; - public String pushToken; - // session - public Integer sessionCount; - public String defaultTracker; - public Integer subsessionCount; - // event - public String eventToken; - public String eventCount; - public String suffix; - public String revenueString; - public String currency; - public String callbackParams; - public String partnerParams; - public Map savedCallbackParameters; - public Map savedPartnerParameters; - // click - public String reftag; - public String otherParameters; - public AdjustAttribution attribution; - public String referrer; - public String deeplink; - - public TestActivityPackage(ActivityPackage activityPackage) { - this.activityPackage = activityPackage; - parameters = activityPackage.getParameters(); - - // default values - appToken = "123456789012"; - environment = "sandbox"; - clientSdk = "android4.38.5"; - suffix = ""; - attribution = new AdjustAttribution(); - playServices = true; - } - - public void testSessionPackage(int sessionCount) { - // set the session count - this.sessionCount = sessionCount; - - // test default package attributes - testDefaultAttributes("/session", ActivityKind.SESSION, "session"); - - // check default parameters - testDefaultParameters(); - - // session parameters - // last_interval - if (sessionCount == 1) { - assertParameterNull("last_interval"); - } else { - assertParameterNotNull("last_interval"); - } - // default_tracker - assertParameterEquals("default_tracker", defaultTracker); - // callback_params - assertJsonParameterEquals("callback_params", callbackParams); - // partner_params - assertJsonParameterEquals("partner_params", partnerParams); - } - - public void testEventPackage(String eventToken) { - // set the event token - this.eventToken = eventToken; - - // test default package attributes - testDefaultAttributes("/event", ActivityKind.EVENT, "event"); - - // check default parameters - testDefaultParameters(); - - // event parameters - // event_count - if (eventCount == null) { - assertParameterNotNull("event_count"); - } else { - assertParameterEquals("event_count", eventCount); - } - // event_token - assertParameterEquals("event_token", eventToken); - // revenue and currency must come together - if (parameters.get("revenue") != null && - parameters.get("currency") == null) { - assertFail(); - } - if (parameters.get("revenue") == null && - parameters.get("currency") != null) { - assertFail(); - } - // revenue - assertParameterEquals("revenue", revenueString); - // currency - assertParameterEquals("currency", currency); - // callback_params - assertJsonParameterEquals("callback_params", callbackParams); - // partner_params - assertJsonParameterEquals("partner_params", partnerParams); - - // saved callback parameters - if (savedCallbackParameters == null) { - Assert.assertNull(activityPackage.getExtendedString(), - activityPackage.getCallbackParameters()); - } else { - Assert.assertTrue(activityPackage.getExtendedString(), - savedCallbackParameters.equals(activityPackage.getCallbackParameters())); - } - // saved partner parameters - if (savedPartnerParameters == null) { - Assert.assertNull(activityPackage.getExtendedString(), - activityPackage.getPartnerParameters()); - } else { - Assert.assertTrue(activityPackage.getExtendedString(), - savedPartnerParameters.equals(activityPackage.getPartnerParameters())); - } - } - - public void testClickPackage(String source) { - testClickPackage(source, true); - } - - public void testClickPackage(String source, boolean hasActivityState) { - // test default package attributes - testDefaultAttributes("/sdk_click", ActivityKind.CLICK, "click"); - - // check device ids parameters - testDefaultParameters(hasActivityState); - - // click parameters - // source - assertParameterEquals("source", source); - - // referrer - assertParameterEquals(Constants.REFTAG, reftag); - - if (source == Constants.REFTAG) { - assertParameterEquals("referrer", referrer); - assertParameterNull("deeplink"); - } else if (source == Constants.DEEPLINK) { - assertParameterEquals("deeplink", deeplink); - assertParameterNull("referrer"); - } else { - assertFail(); - } - - // params - assertJsonParameterEquals("params", otherParameters); - - // click_time - // TODO add string click time to compare - assertParameterNotNull("click_time"); - - // attributions - if (attribution != null) { - // tracker - assertParameterEquals("tracker", attribution.trackerName); - // campaign - assertParameterEquals("campaign", attribution.campaign); - // adgroup - assertParameterEquals("adgroup", attribution.adgroup); - // creative - assertParameterEquals("creative", attribution.creative); - } - } - - public void testInfoPackage(String source) { - // test default package attributes - testDefaultAttributes("/sdk_info", ActivityKind.INFO, "info"); - - // check device ids parameters - testDeviceIdsParameters(); - - // click parameters - // source - assertParameterEquals("source", source); - - if (source == Constants.PUSH) { - } else { - assertFail(); - } - } - - public void testAttributionPackage() { - // test default package attributes - testDefaultAttributes("attribution", ActivityKind.ATTRIBUTION, "attribution"); - - testDeviceIdsParameters(); - } - - public static void testQueryStringRequest(String queryStringRequest, Integer queueSize) { - String[] queryPairs = queryStringRequest.split("&"); - boolean wasSentAtFound = false; - boolean wasQueueSizeFound = false; - int queueSizeFound = -1; - - for (String pair : queryPairs) { - String[] pairComponents = pair.split("="); - String key = pairComponents[0]; - String value = pairComponents[1]; - if (key.equals("sent_at")) { - wasSentAtFound = true; - } - if (key.equals("queue_size")) { - wasQueueSizeFound = true; - queueSizeFound = Integer.parseInt(value); - } - } - if (!wasSentAtFound) { - Assert.fail(queryStringRequest); - } - - if (queueSize == null) { - Assert.assertFalse(queryStringRequest, wasQueueSizeFound); - return; - } - - if (!wasQueueSizeFound) { - Assert.fail(queryStringRequest); - } else { - Assert.assertEquals(queryStringRequest, - queueSize.intValue(), queueSizeFound); - } - } - - private void testDefaultAttributes(String path, ActivityKind activityKind, String activityKindString) { - // check the Sdk version is being tested - assertEquals(activityPackage.getClientSdk(), clientSdk); - // check the path - assertEquals(activityPackage.getPath(), path); - // test activity kind - // check the activity kind - assertEquals(activityPackage.getActivityKind(), activityKind); - // the conversion from activity kind to String - assertEquals(activityPackage.getActivityKind().toString(), activityKindString); - // the conversion from String to activity kind - assertEquals(activityPackage.getActivityKind(), ActivityKind.fromString(activityKindString)); - // test suffix - assertEquals(activityPackage.getSuffix(), suffix); - } - - private void testDefaultParameters() { - testDefaultParameters(true); - } - - private void testDefaultParameters(boolean hasActivityState) { - testDeviceInfo(); - testConfig(); - if (hasActivityState) { - testActivityState(); - } else { - testWithoutActivityState(); - } - testCreatedAt(); - } - - private void testDeviceIdsParameters() { - testDeviceInfoIds(); - testConfig(); - testCreatedAt(); - } - - private void testCreatedAt() { - // created_at - assertParameterNotNull("created_at"); - } - - private void testDeviceInfo() { - testDeviceInfoIds(); - // fb_id - //assertParameterNotNull("fb_id"); - // package_name - assertParameterNotNull("package_name"); - // app_version - // device_type - assertParameterNotNull("device_type"); - // device_name - assertParameterNotNull("device_name"); - // device_manufacturer - assertParameterNotNull("device_manufacturer"); - // os_name - assertParameterEquals("os_name", "android"); - // os_version - assertParameterNotNull("os_version"); - // language - assertParameterNotNull("language"); - // country - assertParameterNotNull("country"); - // screen_size - assertParameterNotNull("screen_size"); - // screen_format - assertParameterNotNull("screen_format"); - // screen_density - assertParameterNotNull("screen_density"); - // display_width - assertParameterNotNull("display_width"); - // display_height - assertParameterNotNull("display_height"); - // hardware_name - assertParameterNotNull("hardware_name"); - // cpu_type - assertParameterNotNull("cpu_type"); - // os_build - assertParameterNotNull("os_build"); - // vm_isa - assertParameterNotNull("vm_isa"); - } - - private void testDeviceInfoIds() { - // play services - if (playServices) { - // android_id - assertParameterNull("android_id"); - } else { - // android_id - assertParameterNotNull("android_id"); - } - } - - private void testConfig() { - // app_token - assertParameterEquals("app_token", appToken); - // environment - assertParameterEquals("environment", environment); - // device_known - testParameterBoolean("device_known", deviceKnow); - // needs_attribution_data - testParameterBoolean("needs_response_details", true); - // play services - if (playServices) { - // gps_adid - assertParameterNotNull("gps_adid"); - // tracking_enabled - assertParameterNotNull("tracking_enabled"); - } else { - // gps_adid - assertParameterNull("gps_adid"); - // tracking_enabled - assertParameterNull("tracking_enabled"); - } - // event_buffering_enabled - testParameterBoolean("event_buffering_enabled", eventBufferingEnabled); - // push_token - assertParameterEquals("push_token", pushToken); - } - - private void testWithoutActivityState() { - // android_uuid - assertParameterNull("android_uuid"); - // session_count - assertParameterNull("session_count"); - // subsession_count - assertParameterNull("subsession_count"); - // session_length - assertParameterNull("session_length"); - // time_spent - assertParameterNull("time_spent"); - } - - private void testActivityState() { - testActivityStateIds(); - // session_count - if (sessionCount == null) { - assertParameterNotNull("session_count"); - } else { - assertParameterEquals("session_count", sessionCount); - } - // first session - if (sessionCount != null && sessionCount == 1) { - // subsession_count - assertParameterNull("subsession_count"); - // session_length - assertParameterNull("session_length"); - // time_spent - assertParameterNull("time_spent"); - } else { - // subsession_count - if (subsessionCount == null) - assertParameterNotNull("subsession_count"); - else - assertParameterEquals("subsession_count", subsessionCount); - // session_length - assertParameterNotNull("session_length"); - // time_spent - assertParameterNotNull("time_spent"); - } - } - - private void testActivityStateIds() { - // android_uuid - assertParameterNotNull("android_uuid"); - } - - private void assertParameterNotNull(String parameterName) { - Assert.assertNotNull(activityPackage.getExtendedString(), - parameters.get(parameterName)); - } - - private void assertParameterNull(String parameterName) { - Assert.assertNull(activityPackage.getExtendedString(), - parameters.get(parameterName)); - } - - private void assertParameterEquals(String parameterName, String value) { - if (value == null) { - assertParameterNull(parameterName); - return; - } - - Assert.assertEquals(activityPackage.getExtendedString(), - value, parameters.get(parameterName)); - } - - private void assertJsonParameterEquals(String parameterName, String value) { - if (value == null) { - assertParameterNull(parameterName); - return; - } - - JsonParser parser = new JsonParser(); - JsonElement e1 = parser.parse(value); - JsonElement e2 = parser.parse(parameters.get(parameterName)); - - assertEquals(e1, e2); - } - - private void assertParameterEquals(String parameterName, int value) { - Assert.assertEquals(activityPackage.getExtendedString(), - value, Integer.parseInt(parameters.get(parameterName))); - } - - - private void assertEquals(String field, String value) { - Assert.assertEquals(activityPackage.getExtendedString(), - value, field); - } - - private void assertEquals(Object field, Object value) { - Assert.assertEquals(activityPackage.getExtendedString(), - value, field); - } - - private void assertFail() { - Assert.fail(activityPackage.getExtendedString()); - } - - private void testParameterBoolean(String parameterName, Boolean value) { - if (value == null) { - assertParameterNull(parameterName); - } else if (value) { - assertParameterEquals(parameterName, "1"); - } else { - assertParameterEquals(parameterName, "0"); - } - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java deleted file mode 100644 index 95ca96751..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestAttributionHandler.java +++ /dev/null @@ -1,465 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; -import android.net.Uri; -import android.os.SystemClock; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import com.adjust.sdk.test.*; - -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Created by pfms on 28/01/15. - */ -@RunWith(AndroidJUnit4.class) -@LargeTest -public class TestAttributionHandler{ - private MockLogger mockLogger; - private MockActivityHandler mockActivityHandler; - private MockHttpsURLConnection mockHttpsURLConnection; - private AssertUtil assertUtil; - private com.adjust.sdk.test.UnitTestActivity activity; - private Context context; - private ActivityPackage attributionPackage; - private ActivityPackage firstSessionPackage; - private ActivityPackage sdkClickPackage; - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(com.adjust.sdk.test.UnitTestActivity.class); - - @Before - public void setUp() { - mockLogger = new MockLogger(); - mockActivityHandler = new MockActivityHandler(mockLogger); - mockHttpsURLConnection = new MockHttpsURLConnection(null, mockLogger); - - assertUtil = new AssertUtil(mockLogger); - - AdjustFactory.setLogger(mockLogger); - AdjustFactory.setActivityHandler(mockActivityHandler); - AdjustFactory.setHttpsURLConnection(mockHttpsURLConnection); - - activity = mActivityRule.getActivity(); - context = activity.getApplicationContext(); - - savePackages(); - - mockLogger.reset(); - } - - private void savePackages() { - MockAttributionHandler mockAttributionHandler = new MockAttributionHandler(mockLogger); - MockPackageHandler mockPackageHandler = new MockPackageHandler(mockLogger); - MockSdkClickHandler mockSdkClickHandler = new MockSdkClickHandler(mockLogger); - - AdjustFactory.setAttributionHandler(mockAttributionHandler); - AdjustFactory.setPackageHandler(mockPackageHandler); - AdjustFactory.setSdkClickHandler(mockSdkClickHandler); - - // deleting the activity state file to simulate a first session - boolean activityStateDeleted = ActivityHandler.deleteActivityState(context); - boolean attributionDeleted = ActivityHandler.deleteAttribution(context); - - // create the config to start the session - AdjustConfig config = new AdjustConfig(context, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - - // start activity handler with config - ActivityHandler activityHandler = ActivityHandler.getInstance(config); - - if (activityHandler != null) { - activityHandler.onResume(); - } - - Uri attributions = Uri.parse("AdjustTests://example.com/path/inApp?adjust_tracker=trackerValue&other=stuff&adjust_campaign=campaignValue&adjust_adgroup=adgroupValue&adjust_creative=creativeValue"); - long now = System.currentTimeMillis(); - - activityHandler.readOpenUrl(attributions, now); - - SystemClock.sleep(3000); - - ActivityPackage attributionPackage = activityHandler.getAttributionPackageI(); - - TestActivityPackage attributionPackageTest = new TestActivityPackage(attributionPackage); - - attributionPackageTest.testAttributionPackage(); - - this.firstSessionPackage = mockPackageHandler.queue.get(0); - - this.sdkClickPackage = mockSdkClickHandler.queue.get(0); - - this.attributionPackage = attributionPackage; - - AdjustFactory.setAttributionHandler(null); - AdjustFactory.setPackageHandler(null); - AdjustFactory.setSdkClickHandler(null); - } - - @After - public void tearDown() { - AdjustFactory.setHttpsURLConnection(null); - AdjustFactory.setActivityHandler(null); - AdjustFactory.setLogger(null); - - activity = null; - context = null; - } - - @Test - public void testGetAttribution() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testGetAttribution"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, true); - - // test null client - nullClientTest(attributionHandler); - - // test client exception - clientExceptionTest(attributionHandler); - - // test wrong json response - wrongJsonTest(attributionHandler); - - // test empty response - emptyJsonResponseTest(attributionHandler); - - // test server error - serverErrorTest(attributionHandler); - - // test ok response with message - okMessageTest(attributionHandler); - } - - @Test - public void testCheckSessionResponse() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testCheckSessionResponse"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, true); - - // new attribution - JSONObject attributionJson = null; - try { - attributionJson = new JSONObject("{ " + - "\"tracker_token\" : \"ttValue\" , " + - "\"tracker_name\" : \"tnValue\" , " + - "\"network\" : \"nValue\" , " + - "\"campaign\" : \"cpValue\" , " + - "\"adgroup\" : \"aValue\" , " + - "\"creative\" : \"ctValue\" , " + - "\"click_label\" : \"clValue\" }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - SessionResponseData sessionResponseData = (SessionResponseData) ResponseData.buildResponseData(firstSessionPackage); - sessionResponseData.jsonResponse = attributionJson; - - attributionHandler.checkSessionResponse(sessionResponseData); - - SystemClock.sleep(1000); - - // updated set askingAttribution to false - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - // it did not update to true - assertUtil.notInTest("ActivityHandler setAskingAttribution, true"); - - // and waiting for query - assertUtil.notInDebug("Waiting to query attribution"); - - // check attribution was called without ask_in - assertUtil.test("ActivityHandler launchSessionResponseTasks, message:null timestamp:null json:{\"tracker_token\":\"ttValue\",\"tracker_name\":\"tnValue\",\"network\":\"nValue\",\"campaign\":\"cpValue\",\"adgroup\":\"aValue\",\"creative\":\"ctValue\",\"click_label\":\"clValue\"}"); - } - - @Test - public void testCheckSdkClickResponse() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testCheckSdkClickResponse"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, true); - - // new attribution - JSONObject attributionJson = null; - try { - attributionJson = new JSONObject("{ " + - "\"tracker_token\" : \"ttValue\" , " + - "\"tracker_name\" : \"tnValue\" , " + - "\"network\" : \"nValue\" , " + - "\"campaign\" : \"cpValue\" , " + - "\"adgroup\" : \"aValue\" , " + - "\"creative\" : \"ctValue\" , " + - "\"click_label\" : \"clValue\" }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - SdkClickResponseData sdkClickResponseData = (SdkClickResponseData) ResponseData.buildResponseData(sdkClickPackage); - sdkClickResponseData.jsonResponse = attributionJson; - - attributionHandler.checkSdkClickResponse(sdkClickResponseData); - - SystemClock.sleep(1000); - - // updated set askingAttribution to false - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - // it did not update to true - assertUtil.notInTest("ActivityHandler setAskingAttribution, true"); - - // and waiting for query - assertUtil.notInDebug("Waiting to query attribution"); - - // check attribution was called without ask_in - assertUtil.test("ActivityHandler launchSdkClickResponseTasks, message:null timestamp:null json:{\"tracker_token\":\"ttValue\",\"tracker_name\":\"tnValue\",\"network\":\"nValue\",\"campaign\":\"cpValue\",\"adgroup\":\"aValue\",\"creative\":\"ctValue\",\"click_label\":\"clValue\"}"); - } - - @Test - public void testAskIn() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testAskIn"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, true); - - String response = "Response: { \"ask_in\" : 4000 }"; - - JSONObject askIn4sJson = null; - try { - askIn4sJson = new JSONObject("{ \"ask_in\" : 4000 }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - mockHttpsURLConnection.responseType = ResponseType.MESSAGE; - - SessionResponseData sessionResponseData = (SessionResponseData)ResponseData.buildResponseData(firstSessionPackage); - sessionResponseData.jsonResponse = askIn4sJson; - - attributionHandler.checkSessionResponse(sessionResponseData); - - // sleep enough not to trigger the timer - SystemClock.sleep(1000); - - // change the response to avoid a cycle; - mockHttpsURLConnection.responseType = ResponseType.MESSAGE; - - // check attribution was called with ask_in - assertUtil.notInTest("ActivityHandler updateAttribution"); - - // it did update to true - assertUtil.test("ActivityHandler setAskingAttribution, true"); - - // and waited to for query - assertUtil.debug("Waiting to query attribution in 4.0 seconds"); - - SystemClock.sleep(2000); - - JSONObject askIn5sJson = null; - try { - askIn5sJson = new JSONObject("{ \"ask_in\" : 5000 }"); - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - sessionResponseData.jsonResponse = askIn5sJson; - attributionHandler.checkSessionResponse(sessionResponseData); - - // sleep enough not to trigger the old timer - SystemClock.sleep(3000); - - // it did update to true - assertUtil.test("ActivityHandler setAskingAttribution, true"); - - // and waited to for query - assertUtil.debug("Waiting to query attribution in 5.0 seconds"); - - // it was been waiting for 1000 + 2000 + 3000 = 6 seconds - // check that the mock http client was not called because the original clock was reseted - assertUtil.notInTest("HttpClient execute"); - - // check that it was finally called after 6 seconds after the second ask_in - SystemClock.sleep(4000); - - okMessageTestLogs(attributionHandler); - - //requestTest(mockHttpClient.lastRequest); - } - - @Test - public void testPause() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testPause"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, false); - - mockHttpsURLConnection.responseType = ResponseType.MESSAGE; - - attributionHandler.getAttribution(); - - SystemClock.sleep(1000); - - // check that the activity handler is paused - assertUtil.debug("Attribution handler is paused"); - - // and it did not call the http client - //assertUtil.isNull(mockHttpClient.lastRequest); - - assertUtil.notInTest("MockHttpsURLConnection getInputStream"); - } - - @Test - public void testDeeplink() { - // assert test name to read better in logcat - mockLogger.Assert("TestAttributionHandler testDeeplink"); - - AttributionHandler attributionHandler = new AttributionHandler(mockActivityHandler, - attributionPackage, true); - - JSONObject responseJson = new JSONObject(); - - SessionResponseData sessionResponseDeeplink = (SessionResponseData) ResponseData.buildResponseData(firstSessionPackage); - try { - JSONObject internalAttributionJson = new JSONObject(); - internalAttributionJson.put("deeplink", "testDeeplinkAttribution://"); - - responseJson.put("deeplink", "testDeeplinkRoot://"); - responseJson.put("attribution", internalAttributionJson); - - //sessionResponseDeeplink.jsonResponse = new JSONObject("{ " + - // "\"deeplink\" : \"testDeeplinkRoot://\" }"); - - } catch (JSONException e) { - assertUtil.fail(e.getMessage()); - } - - sessionResponseDeeplink.jsonResponse = responseJson; - attributionHandler.checkSessionResponse(sessionResponseDeeplink); - SystemClock.sleep(2000); - - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - assertUtil.test("ActivityHandler launchSessionResponseTasks, message:null timestamp:null " + - "json:{\"deeplink\":\"testDeeplinkRoot:\\/\\/\",\"attribution\":{\"deeplink\":\"testDeeplinkAttribution:\\/\\/\"}}"); - - AttributionResponseData attributionResponseDeeplink = (AttributionResponseData)ResponseData.buildResponseData(attributionPackage); - - attributionResponseDeeplink.jsonResponse = responseJson; - attributionHandler.checkAttributionResponse(attributionResponseDeeplink); - SystemClock.sleep(2000); - - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - assertUtil.test("ActivityHandler launchAttributionResponseTasks, message:null timestamp:null " + - "json:{\"deeplink\":\"testDeeplinkRoot:\\/\\/\",\"attribution\":{\"deeplink\":\"testDeeplinkAttribution:\\/\\/\"}}"); - - assertUtil.isEqual(attributionResponseDeeplink.deeplink, Uri.parse("testDeeplinkAttribution://")); - } - - private void nullClientTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, null); - - // check response was not logged - assertUtil.notInVerbose("Response"); - } - - private void clientExceptionTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, ResponseType.CLIENT_PROTOCOL_EXCEPTION); - - // check the client error - assertUtil.error("Failed to get attribution (testResponseError)"); - } - - private void wrongJsonTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, ResponseType.WRONG_JSON); - - // check that the mock http client was called - assertUtil.test("MockHttpsURLConnection getInputStream"); - - assertUtil.verbose("Response: not a json response"); - - assertUtil.error("Failed to parse json response. (Value not of type java.lang.String cannot be converted to JSONObject)"); - } - - private void emptyJsonResponseTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, ResponseType.EMPTY_JSON); - - // check that the mock http client was called - assertUtil.test("MockHttpsURLConnection getInputStream"); - - assertUtil.verbose("Response: { }"); - - assertUtil.info("No message found"); - - // check attribution was called without ask_in - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - assertUtil.test("ActivityHandler launchAttributionResponseTasks, message:null timestamp:null json:{}"); - } - - private void serverErrorTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, ResponseType.INTERNAL_SERVER_ERROR); - - // check that the mock http client was called - assertUtil.test("MockHttpsURLConnection getErrorStream"); - - // the response logged - assertUtil.verbose("Response: { \"message\": \"testResponseError\"}"); - - // the message in the response - assertUtil.error("testResponseError"); - - // check attribution was called without ask_in - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - assertUtil.test("ActivityHandler launchAttributionResponseTasks, message:testResponseError timestamp:null json:{\"message\":\"testResponseError\"}"); - } - - private void okMessageTest(AttributionHandler attributionHandler) { - startGetAttributionTest(attributionHandler, ResponseType.MESSAGE); - - okMessageTestLogs(attributionHandler); - } - - private void okMessageTestLogs(AttributionHandler attributionHandler) { - /* - TestActivityPackage.testQueryStringRequest(attributionHandler.lastUrlUsed.getQuery(), null); - - // check that the mock http client was called - assertUtil.test("MockHttpsURLConnection getInputStream"); - - // the response logged - assertUtil.verbose("Response: { \"message\" : \"response OK\"}"); - - // the message in the response - assertUtil.info("response OK"); - - assertUtil.test("ActivityHandler setAskingAttribution, false"); - - // check attribution was called without ask_in - assertUtil.test("ActivityHandler launchAttributionResponseTasks, message:response OK timestamp:null json:{\"message\":\"response OK\"}"); - */ - } - - private void startGetAttributionTest(AttributionHandler attributionHandler, ResponseType responseType) { - mockHttpsURLConnection.responseType = responseType; - - attributionHandler.getAttribution(); - - SystemClock.sleep(1000); - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java deleted file mode 100644 index 6744213c5..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestPackageHandler.java +++ /dev/null @@ -1,581 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; -import android.os.SystemClock; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.test.suitebuilder.annotation.LargeTest; - -import com.adjust.sdk.test.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Created by pfms on 22/08/2016. - */ -@RunWith(AndroidJUnit4.class) -@LargeTest -public class TestPackageHandler { - private MockLogger mockLogger; - private MockActivityHandler mockActivityHandler; - protected MockRequestHandler mockRequestHandler; - private AssertUtil assertUtil; - private com.adjust.sdk.test.UnitTestActivity activity; - private Context context; - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(com.adjust.sdk.test.UnitTestActivity.class); - - @Before - public void setUp() { - mockLogger = new MockLogger(); - mockActivityHandler = new MockActivityHandler(mockLogger); - mockRequestHandler = new MockRequestHandler(mockLogger); - - assertUtil = new AssertUtil(mockLogger); - - AdjustFactory.setLogger(mockLogger); - AdjustFactory.setRequestHandler(mockRequestHandler); - - activity = mActivityRule.getActivity(); - context = activity.getApplicationContext(); - } - - @After - public void tearDown() { - AdjustFactory.setRequestHandler(null); - AdjustFactory.setLogger(null); - } - - @Test - public void testAddPackage() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testAddPackage"); - - PackageHandler packageHandler = startPackageHandler(); - - ActivityPackage firstClickPackage = createClickPackage("FirstPackage"); - - packageHandler.addPackage(firstClickPackage); - - SystemClock.sleep(1000); - - addPackageTests(1, "clickFirstPackage"); - - PackageHandler secondPackageHandler = addSecondPackageTest(null); - - ActivityPackage secondClickPackage = createClickPackage("ThirdPackage"); - - secondPackageHandler.addPackage(secondClickPackage); - - SystemClock.sleep(1000); - - addPackageTests(3, "clickThirdPackage"); - - // send the first click package/ first package - secondPackageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - assertUtil.test("RequestHandler sendPackage, activityPackage clickFirstPackage"); - assertUtil.test("RequestHandler sendPackage, queueSize 2"); - - // send the second click package/ third package - secondPackageHandler.sendNextPackage(null); - SystemClock.sleep(1000); - - assertUtil.test("RequestHandler sendPackage, activityPackage unknownSecondPackage"); - assertUtil.test("RequestHandler sendPackage, queueSize 1"); - - // send the unknow package/ second package - secondPackageHandler.sendNextPackage(null); - SystemClock.sleep(1000); - - assertUtil.test("RequestHandler sendPackage, activityPackage clickThirdPackage"); - assertUtil.test("RequestHandler sendPackage, queueSize 0"); - } - - @Test - public void testSendFirst() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testSendFirst"); - - PackageHandler packageHandler = startPackageHandler(); - - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.EMPTY_QUEUE, null, null); - - addAndSendFirstPackageTest(packageHandler); - - // try to send when it is still sending - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.IS_SENDING, null, null); - - // try to send paused - packageHandler.pauseSending(); - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.PAUSED, null, null); - - // unpause, it's still sending - packageHandler.resumeSending(); - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.IS_SENDING, null, null); - - // verify that both paused and isSending are reset with a new session - PackageHandler secondSessionPackageHandler = new PackageHandler(mockActivityHandler, context, true); - - secondSessionPackageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - // send the package to request handler - sendFirstTests(SendFirstState.SEND, "unknownFirstPackage", 0); - } - - @Test - public void testSendNext() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testSendNext"); - - // init package handler - PackageHandler packageHandler = startPackageHandler(); - - // add and send the first package - addAndSendFirstPackageTest(packageHandler); - - // try to send when it is still sending - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.IS_SENDING, null, null); - - // add a second package - addSecondPackageTest(packageHandler); - - //send next package - packageHandler.sendNextPackage(null); - SystemClock.sleep(2000); - - assertUtil.debug("Package handler wrote 1 packages"); - - // try to send the second package - sendFirstTests(SendFirstState.SEND, "unknownSecondPackage", 0); - } - - @Test - public void testCloseFirstPackage() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testCloseFirstPackage"); - AdjustFactory.setPackageHandlerBackoffStrategy(BackoffStrategy.NO_WAIT); - - PackageHandler packageHandler = startPackageHandler(); - - addAndSendFirstPackageTest(packageHandler); - - // try to send when it is still sending - packageHandler.sendFirstPackage(); - SystemClock.sleep(1000); - - sendFirstTests(SendFirstState.IS_SENDING, null, null); - - //send next package - ActivityPackage activityPackage = new ActivityPackage(ActivityKind.UNKNOWN); - ResponseData unknownResponseData = ResponseData.buildResponseData(activityPackage); - packageHandler.closeFirstPackage(unknownResponseData, null); - SystemClock.sleep(2000); - - assertUtil.test("ActivityHandler finishedTrackingActivity, message:null timestamp:null json:null"); - assertUtil.verbose("Package handler can send"); - - assertUtil.notInDebug("Package handler wrote"); - - // tries to send the next package after sleeping - sendFirstTests(SendFirstState.SEND, "unknownFirstPackage", 0); - } - - @Test - public void testBackoffJitter() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testBackoffJitter"); - - AdjustFactory.setPackageHandlerBackoffStrategy(BackoffStrategy.TEST_WAIT); - - PackageHandler packageHandler = startPackageHandler(); - - ActivityPackage activityPackage = new ActivityPackage(ActivityKind.UNKNOWN); - ResponseData unknownResponseData = ResponseData.buildResponseData(activityPackage); - Pattern pattern = Pattern.compile("Waiting for (\\d+\\.\\d) seconds before retrying the (\\d+) time"); - - // 1st - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - String matchingString = assertUtil.verbose("Waiting for "); - // Waiting for 0.1 seconds before retrying the 1 time - - checkSleeping(pattern, matchingString, 0.1, 0.2, 1, 0.5, 1); - - // 2nd - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - matchingString = assertUtil.verbose("Waiting for "); - - checkSleeping(pattern, matchingString, 0.2, 0.4, 1, 0.5, 2); - - // 3rd - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - matchingString = assertUtil.verbose("Waiting for "); - - checkSleeping(pattern, matchingString, 0.4, 0.8, 1, 0.5, 3); - - // 4th - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - matchingString = assertUtil.verbose("Waiting for "); - - checkSleeping(pattern, matchingString, 0.8, 1.6, 1, 0.5, 4); - - // 5th - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - matchingString = assertUtil.verbose("Waiting for "); - - checkSleeping(pattern, matchingString, 1.6, 3.2, 1, 0.5, 5); - - // 6th - packageHandler.closeFirstPackage(unknownResponseData, activityPackage); - SystemClock.sleep(1500); - - matchingString = assertUtil.verbose("Waiting for "); - - checkSleeping(pattern, matchingString, 6.4, 12.8, 1, 0.5, 6); - } - - @Test - public void testUpdate() { - // assert test name to read better in logcat - mockLogger.Assert("TestPackageHandler testUpdate"); - - List delayPackages = createDelayPackages(); - - ActivityPackage firstSessionPackage = delayPackages.get(0); - ActivityPackage firstEventPackage = delayPackages.get(1); - ActivityPackage secondEventPackage = delayPackages.get(2); - - // create event package test - TestActivityPackage testFirstSessionPackage = new TestActivityPackage(firstSessionPackage); - - testFirstSessionPackage.testSessionPackage(1); - - // create event package test - TestActivityPackage testFirstEventPackage = new TestActivityPackage(firstEventPackage); - - // set event test parameters - testFirstEventPackage.eventCount = "1"; - testFirstEventPackage.suffix = "'event1'"; - testFirstEventPackage.savedCallbackParameters = new HashMap(1); - testFirstEventPackage.savedCallbackParameters.put("ceFoo", "ceBar"); - testFirstEventPackage.savedPartnerParameters = new HashMap(1); - testFirstEventPackage.savedPartnerParameters.put("peFoo", "peBar"); - - // test first event - testFirstEventPackage.testEventPackage("event1"); - - // create event package test - TestActivityPackage testSecondEventPackage = new TestActivityPackage(secondEventPackage); - - // set event test parameters - testSecondEventPackage.eventCount = "2"; - testSecondEventPackage.suffix = "'event2'"; - testSecondEventPackage.savedCallbackParameters = new HashMap(1); - testSecondEventPackage.savedCallbackParameters.put("scpKey", "ceBar"); - testSecondEventPackage.savedPartnerParameters = new HashMap(1); - testSecondEventPackage.savedPartnerParameters.put("sppKey", "peBar"); - - // test second event - testSecondEventPackage.testEventPackage("event2"); - - // initialize Package Handler - IPackageHandler packageHandler = startPackageHandler(); - - sendFirstTests(SendFirstState.EMPTY_QUEUE, null, null); - - packageHandler.addPackage(firstSessionPackage); - packageHandler.addPackage(firstEventPackage); - packageHandler.addPackage(secondEventPackage); - - SystemClock.sleep(1000); - - addPackageTests(1, "session"); - - addPackageTests(2, "event'event1'"); - - addPackageTests(3, "event'event2'"); - - packageHandler.updatePackages(null); - - SystemClock.sleep(1000); - - assertUtil.notInDebug("Updating package handler queue"); - - SessionParameters emptySessionParameters = new SessionParameters(); - packageHandler.updatePackages(emptySessionParameters); - - SystemClock.sleep(1000); - - assertUtil.debug("Updating package handler queue"); - - assertUtil.verbose("Session callback parameters: null"); - assertUtil.verbose("Session partner parameters: null"); - - // writes the non-updated packages - assertUtil.debug("Wrote Package queue: [session, event'event1', event'event2']"); - assertUtil.debug("Package handler wrote 3 packages"); - - SessionParameters sessionParameters = new SessionParameters(); - sessionParameters.callbackParameters = new HashMap(1); - sessionParameters.callbackParameters.put("scpKey", "scpValue"); - sessionParameters.partnerParameters = new HashMap(1); - sessionParameters.partnerParameters.put("sppKey", "sppValue"); - - packageHandler.updatePackages(sessionParameters); - - SystemClock.sleep(1000); - - assertUtil.debug("Updating package handler queue"); - - assertUtil.verbose("Session callback parameters: {scpKey=scpValue}"); - assertUtil.verbose("Session partner parameters: {sppKey=sppValue}"); - - assertUtil.warn("Key scpKey with value scpValue from Callback parameter was replaced by value ceBar"); - assertUtil.warn("Key sppKey with value sppValue from Partner parameter was replaced by value peBar"); - assertUtil.debug("Package handler wrote 3 packages"); - - testFirstSessionPackage.callbackParams = "{scpKey=scpValue}"; - testFirstSessionPackage.partnerParams = "{sppKey=sppValue}"; - testFirstSessionPackage.testSessionPackage(1); - - testFirstEventPackage.callbackParams = "{scpKey=scpValue, ceFoo=ceBar}"; - testFirstEventPackage.partnerParams = "{sppKey=sppValue, peFoo=peBar}"; - - testFirstEventPackage.testEventPackage("event1"); - - testSecondEventPackage.callbackParams = "{scpKey=ceBar}"; - testSecondEventPackage.partnerParams = "{sppKey=peBar}"; - - testSecondEventPackage.testEventPackage("event2"); - } - - private List createDelayPackages() { - MockPackageHandler mockPackageHandler = new MockPackageHandler(mockLogger); - AdjustFactory.setPackageHandler(mockPackageHandler); - - MockSdkClickHandler mockSdkClickHandler = new MockSdkClickHandler(mockLogger); - AdjustFactory.setSdkClickHandler(mockSdkClickHandler); - - MockAttributionHandler mockAttributionHandler = new MockAttributionHandler(mockLogger); - AdjustFactory.setAttributionHandler(mockAttributionHandler); - - AdjustFactory.setSessionInterval(-1); - AdjustFactory.setSubsessionInterval(-1); - AdjustFactory.setTimerInterval(-1); - AdjustFactory.setTimerStart(-1); - - ActivityHandler.deleteActivityState(context); - ActivityHandler.deleteAttribution(context); - ActivityHandler.deleteSessionCallbackParameters(context); - ActivityHandler.deleteSessionPartnerParameters(context); - - AdjustConfig config = new AdjustConfig(context, "123456789012", "sandbox"); - - config.setDelayStart(4); - - IActivityHandler activityHandler = ActivityHandler.getInstance(config); - - activityHandler.addSessionCallbackParameter("scpKey", "scpValue"); - activityHandler.addSessionPartnerParameter("sppKey", "sppValue"); - - activityHandler.onResume(); - - AdjustEvent firstEvent = new AdjustEvent("event1"); - firstEvent.addCallbackParameter("ceFoo", "ceBar"); - firstEvent.addPartnerParameter("peFoo", "peBar"); - activityHandler.trackEvent(firstEvent); - - AdjustEvent secondEvent = new AdjustEvent("event2"); - secondEvent.addCallbackParameter("scpKey", "ceBar"); - secondEvent.addPartnerParameter("sppKey", "peBar"); - activityHandler.trackEvent(secondEvent); - - SystemClock.sleep(3000); - - ActivityPackage firstSessionPackage = mockPackageHandler.queue.get(0); - ActivityPackage firstEventPackage = mockPackageHandler.queue.get(1); - ActivityPackage secondEventPackage = mockPackageHandler.queue.get(2); - - mockLogger.reset(); - - return Arrays.asList(firstSessionPackage, firstEventPackage, secondEventPackage); - } - - private void checkSleeping(Pattern pattern, - String sleepingLog, - double minRange, - double maxRange, - long maxCeiling, - double minCeiling, - int numberRetries) - { - Matcher matcher = pattern.matcher(sleepingLog); - - if (!matcher.matches()) { - assertUtil.fail(); - } - Double sleepingTime = Double.valueOf(matcher.group(1)); - - boolean failsCeiling = sleepingTime > maxCeiling; - assertUtil.isFalse(failsCeiling); - - if (maxRange < maxCeiling) { - boolean failsMinRange = sleepingTime < minRange; - assertUtil.isFalse(failsMinRange); - } else { - boolean failsMinRange = sleepingTime < minCeiling ; - assertUtil.isFalse(failsMinRange); - } - - if (maxRange < maxCeiling) { - boolean failsMaxRange = sleepingTime > maxRange; - assertUtil.isFalse(failsMaxRange); - } else { - boolean failsMaxRange = sleepingTime > maxCeiling; - assertUtil.isFalse(failsMaxRange); - } - - Integer retryTime = Integer.valueOf(matcher.group(2)); - assertUtil.isEqual(numberRetries, retryTime); - } - - private PackageHandler startPackageHandler() { - // delete package queue for fresh start - deletePackageQueue(); - - PackageHandler packageHandler = new PackageHandler(mockActivityHandler, context, true); - - SystemClock.sleep(1000); - - assertUtil.debug("Package queue file not found"); - - return packageHandler; - } - - private PackageHandler addSecondPackageTest(PackageHandler packageHandler) { - if (packageHandler == null) { - packageHandler = new PackageHandler(mockActivityHandler, context, true); - - SystemClock.sleep(1000); - - // check that it can read the previously saved package - assertUtil.debug("Package handler read 1 packages"); - } - - ActivityPackage secondActivityPackage = createUnknowPackage("SecondPackage"); - - packageHandler.addPackage(secondActivityPackage); - - SystemClock.sleep(1000); - - addPackageTests(2, "unknownSecondPackage"); - - return packageHandler; - } - - private void addPackageTests(int packageNumber, String packageString) { - assertUtil.debug("Added package " + packageNumber + " (" + packageString + ")"); - - assertUtil.debug("Package handler wrote " + packageNumber + " packages"); - } - - private void addAndSendFirstPackageTest(PackageHandler packageHandler) { - // add a package - ActivityPackage activityPackage = createUnknowPackage("FirstPackage"); - - // send the first package - packageHandler.addPackage(activityPackage); - - packageHandler.sendFirstPackage(); - SystemClock.sleep(2000); - - addPackageTests(1, "unknownFirstPackage"); - - sendFirstTests(SendFirstState.SEND, "unknownFirstPackage", 0); - } - - private enum SendFirstState { - EMPTY_QUEUE, PAUSED, IS_SENDING, SEND - } - - private void sendFirstTests(SendFirstState sendFirstState, String packageString, Integer queueSize) { - if (sendFirstState == SendFirstState.PAUSED) { - assertUtil.debug("Package handler is paused"); - } else { - assertUtil.notInDebug("Package handler is paused"); - } - - if (sendFirstState == SendFirstState.IS_SENDING) { - assertUtil.verbose("Package handler is already sending"); - } else { - assertUtil.notInVerbose("Package handler is already sending"); - } - - if (sendFirstState == SendFirstState.SEND) { - assertUtil.test("RequestHandler sendPackage, activityPackage " + packageString); - assertUtil.test("RequestHandler sendPackage, queueSize " + queueSize); - } else { - assertUtil.notInTest("RequestHandler sendPackage"); - } - } - - private void deletePackageQueue() { - boolean packageQueueDeleted = PackageHandler.deletePackageQueue(context); - - mockLogger.test("Was PackageQueue deleted? " + packageQueueDeleted); - } - - private ActivityPackage createUnknowPackage(String suffix) { - ActivityPackage activityPackage = new ActivityPackage(ActivityKind.UNKNOWN); - activityPackage.setSuffix(suffix); - - return activityPackage; - } - - private ActivityPackage createClickPackage(String suffix) { - ActivityPackage activityPackage = new ActivityPackage(ActivityKind.CLICK); - activityPackage.setSuffix(suffix); - - return activityPackage; - } - -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java deleted file mode 100644 index b3f8dbb54..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestRequestHandler.java +++ /dev/null @@ -1,221 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; -import android.os.SystemClock; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import com.adjust.sdk.test.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Created by pfms on 30/01/15. - */ -@RunWith(AndroidJUnit4.class) -@LargeTest -public class TestRequestHandler { - private MockLogger mockLogger; - private MockPackageHandler mockPackageHandler; - private MockHttpsURLConnection mockHttpsURLConnection; - private AssertUtil assertUtil; - private com.adjust.sdk.test.UnitTestActivity activity; - private Context context; - - private ActivityPackage sessionPackage; - private RequestHandler requestHandler; - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(com.adjust.sdk.test.UnitTestActivity.class); - - @Before - public void setUp() throws Exception { - mockLogger = new MockLogger(); - mockPackageHandler = new MockPackageHandler(mockLogger); - mockHttpsURLConnection = new MockHttpsURLConnection(null, mockLogger); - - assertUtil = new AssertUtil(mockLogger); - - AdjustFactory.setLogger(mockLogger); - AdjustFactory.setPackageHandler(mockPackageHandler); - AdjustFactory.setHttpsURLConnection(mockHttpsURLConnection); - - activity = mActivityRule.getActivity(); - context = activity.getApplicationContext(); - - sessionPackage = getSessionPackage(); - } - - @After - public void tearDown() throws Exception { - AdjustFactory.setHttpsURLConnection(null); - AdjustFactory.setPackageHandler(null); - AdjustFactory.setLogger(null); - } - - @Test - public void testSend() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testSend"); - - requestHandler = new RequestHandler(mockPackageHandler); - - nullResponseTest(); - - clientExceptionTest(); - - serverErrorTest(); - - wrongJsonTest(); - - emptyJsonTest(); - - messageTest(); - } - -/* configure local test server - public void testTimeout() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testTimeout"); - - mockHttpsURLConnection.responseType = ResponseType.EMPTY_JSON; - - mockHttpsURLConnection.timeout = true; - - requestHandler = new RequestHandler(mockPackageHandler); - - requestHandler.sendPackage(sessionPackage); - - SystemClock.sleep(15000); - - assertUtil.fail(); - } -*/ - - private void nullResponseTest() { - mockHttpsURLConnection.responseType = null; - - requestHandler.sendPackage(sessionPackage, -1); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: null"); - - assertUtil.error("Failed to read response. (null)"); - - assertUtil.error("Failed to track session. (Runtime exception: java.lang.NullPointerException)"); - - assertUtil.test("PackageHandler sendNextPackage"); - } - - private void clientExceptionTest() { - mockHttpsURLConnection.responseType = ResponseType.CLIENT_PROTOCOL_EXCEPTION; - - requestHandler.sendPackage(sessionPackage, -1); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: CLIENT_PROTOCOL_EXCEPTION"); - - assertUtil.error("Failed to track session. (Request failed: java.io.IOException: testResponseError) Will retry later"); - - assertUtil.test("PackageHandler closeFirstPackage"); - } - - private void serverErrorTest() { - mockHttpsURLConnection.responseType = ResponseType.INTERNAL_SERVER_ERROR; - - requestHandler.sendPackage(sessionPackage, -1); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getErrorStream, responseType: INTERNAL_SERVER_ERROR"); - - assertUtil.verbose("Response: { \"message\": \"testResponseError\"}"); - - assertUtil.error("testResponseError"); - - assertUtil.test("PackageHandler sendNextPackage, message:testResponseError timestamp:null json:{\"message\":\"testResponseError\"}"); - } - - private void wrongJsonTest() { - mockHttpsURLConnection.responseType = ResponseType.WRONG_JSON; - - requestHandler.sendPackage(sessionPackage, -1); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: WRONG_JSON"); - - assertUtil.verbose("Response: not a json response"); - - assertUtil.error("Failed to parse json response. (Value not of type java.lang.String cannot be converted to JSONObject)"); - - assertUtil.test("PackageHandler closeFirstPackage"); - } - - private void emptyJsonTest() { - mockHttpsURLConnection.responseType = ResponseType.EMPTY_JSON; - - requestHandler.sendPackage(sessionPackage, -1); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: EMPTY_JSON"); - - assertUtil.verbose("Response: { }"); - - assertUtil.info("No message found"); - - assertUtil.test("PackageHandler sendNextPackage, message:null timestamp:null json:{}"); - } - - private void messageTest() { - mockHttpsURLConnection.responseType = ResponseType.MESSAGE; - - requestHandler.sendPackage(sessionPackage, 1); - SystemClock.sleep(1000); - - TestActivityPackage.testQueryStringRequest(mockHttpsURLConnection.readRequest(), 1); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: MESSAGE"); - - assertUtil.verbose("Response: { \"message\" : \"response OK\"}"); - - assertUtil.info("response OK"); - - assertUtil.test("PackageHandler sendNextPackage, message:response OK timestamp:null json:{\"message\":\"response OK\"}"); - } - - private ActivityPackage getSessionPackage() { - MockAttributionHandler mockAttributionHandler = new MockAttributionHandler(mockLogger); - MockSdkClickHandler mockSdkClickHandler = new MockSdkClickHandler(mockLogger); - - AdjustFactory.setAttributionHandler(mockAttributionHandler); - AdjustFactory.setSdkClickHandler(mockSdkClickHandler); - - // deleting the activity state file to simulate a first session - boolean activityStateDeleted = ActivityHandler.deleteActivityState(context); - boolean attributionDeleted = ActivityHandler.deleteAttribution(context); - - mockLogger.test("Was AdjustActivityState deleted? " + activityStateDeleted); - - // deleting the attribution file to simulate a first session - mockLogger.test("Was Attribution deleted? " + attributionDeleted); - - // create the config to start the session - AdjustConfig config = new AdjustConfig(context, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - - // start activity handler with config - ActivityHandler activityHandler = ActivityHandler.getInstance(config); - activityHandler.onResume(); - SystemClock.sleep(3000); - - ActivityPackage sessionPackage = mockPackageHandler.queue.get(0); - - mockLogger.reset(); - - return sessionPackage; - } -} diff --git a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java b/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java deleted file mode 100644 index 8d4f57913..000000000 --- a/Adjust/test-unit/src/androidTest/java/com/adjust/sdk/TestSdkClickHandler.java +++ /dev/null @@ -1,328 +0,0 @@ -package com.adjust.sdk; - -import android.content.Context; -import android.net.Uri; -import android.os.SystemClock; -import android.support.test.rule.ActivityTestRule; -import android.support.test.runner.AndroidJUnit4; -import android.test.ActivityInstrumentationTestCase2; -import android.test.suitebuilder.annotation.LargeTest; - -import com.adjust.sdk.test.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Created by pfms on 14/04/16. - */ -@RunWith(AndroidJUnit4.class) -@LargeTest -public class TestSdkClickHandler { - private MockLogger mockLogger; - private AssertUtil assertUtil; - private MockHttpsURLConnection mockHttpsURLConnection; - private com.adjust.sdk.test.UnitTestActivity activity; - private Context context; - private ActivityPackage sdkClickPackage; - private MockActivityHandler mockActivityHandler; - - @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(com.adjust.sdk.test.UnitTestActivity.class); - - @Before - public void setUp() { - mockLogger = new MockLogger(); - mockHttpsURLConnection = new MockHttpsURLConnection(null, mockLogger); - mockActivityHandler = new MockActivityHandler(mockLogger); - - assertUtil = new AssertUtil(mockLogger); - - AdjustFactory.setLogger(mockLogger); - AdjustFactory.setHttpsURLConnection(mockHttpsURLConnection); - - activity = mActivityRule.getActivity(); - context = activity.getApplicationContext(); - sdkClickPackage = getClickPackage(); - } - - @After - public void tearDown() { - AdjustFactory.setHttpsURLConnection(null); - AdjustFactory.setLogger(null); - } - - private ActivityPackage getClickPackage() { - MockSdkClickHandler mockSdkClickHandler = new MockSdkClickHandler(mockLogger); - MockAttributionHandler mockAttributionHandler = new MockAttributionHandler(mockLogger); - MockPackageHandler mockPackageHandler = new MockPackageHandler(mockLogger); - - AdjustFactory.setPackageHandler(mockPackageHandler); - AdjustFactory.setSdkClickHandler(mockSdkClickHandler); - AdjustFactory.setAttributionHandler(mockAttributionHandler); - - // create the config to start the session - AdjustConfig config = new AdjustConfig(context, "123456789012", AdjustConfig.ENVIRONMENT_SANDBOX); - - // start activity handler with config - ActivityHandler activityHandler = ActivityHandler.getInstance(config); - activityHandler.onResume(); - activityHandler.readOpenUrl(Uri.parse("AdjustTests://"), System.currentTimeMillis()); - SystemClock.sleep(2000); - - ActivityPackage sdkClickPackage = mockSdkClickHandler.queue.get(0); - mockLogger.reset(); - - return sdkClickPackage; - } - - @Test - public void testPaused() { - sdkClickPackage.setClientSdk("Test-First-Click"); - ActivityPackage secondSdkClickPackage = getClickPackage(); - secondSdkClickPackage.setClientSdk("Test-Second-Click"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testPaused"); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, false); - - mockHttpsURLConnection.responseType = ResponseType.CLIENT_PROTOCOL_EXCEPTION; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - // added first click package to the queue - assertUtil.debug("Added sdk_click 1"); - - assertUtil.verbose("Path: /sdk_click\n" + - "ClientSdk: Test-First-Click"); - - // but not send because it's paused - assertUtil.notInTest("MockHttpsURLConnection getInputStream"); - - // send second sdk click - sdkClickHandler.sendSdkClick(secondSdkClickPackage); - SystemClock.sleep(1000); - - // added second click package to the queue - assertUtil.debug("Added sdk_click 2"); - - assertUtil.verbose("Path: /sdk_click\n" + - "ClientSdk: Test-Second-Click"); - - // wait two seconds before sending - mockHttpsURLConnection.waitingTime = 2000L; - - // try to send first package - checkSendFirstPackage(sdkClickHandler, 1); - // and then the second - checkSendSecondPackage(sdkClickHandler, 1); - - // try to send first package again - checkSendFirstPackage(sdkClickHandler, 2); - // and then the second again - checkSendSecondPackage(sdkClickHandler, 2); - } - - private void checkSendFirstPackage(SdkClickHandler sdkClickHandler, int retries) { - // try to send the first package - sdkClickHandler.resumeSending(); - - SystemClock.sleep(1000); - - // prevent sending next again - sdkClickHandler.pauseSending(); - - SystemClock.sleep(2000); - - // check that it tried to send the first package - assertUtil.test("MockHttpsURLConnection setRequestProperty, field Client-SDK, newValue Test-First-Click"); - - // and that it will try to send it again - assertUtil.error("Retrying sdk_click package for the " + retries + " time"); - - // first package added again on the end of the queue - assertUtil.debug("Added sdk_click 2"); - - assertUtil.verbose("Path: /sdk_click\n" + - "ClientSdk: Test-First-Click"); - - // does not continue to send because it was paused - assertUtil.notInTest("MockHttpsURLConnection setRequestProperty"); - } - - private void checkSendSecondPackage(SdkClickHandler sdkClickHandler, int retries) { - // try to send the second package that is at the start of the queue - sdkClickHandler.resumeSending(); - - SystemClock.sleep(1000); - - // prevent sending next again - sdkClickHandler.pauseSending(); - - SystemClock.sleep(2000); - - // check that it tried to send the second package - assertUtil.test("MockHttpsURLConnection setRequestProperty, field Client-SDK, newValue Test-Second-Click"); - - // and that it will try to send it again - assertUtil.error("Retrying sdk_click package for the " + retries + " time"); - - // second package added again on the end of the queue - assertUtil.debug("Added sdk_click 2"); - - assertUtil.verbose("Path: /sdk_click\n" + - "ClientSdk: Test-Second-Click"); - - // does not continue to send because it was paused - assertUtil.notInTest("MockHttpsURLConnection setRequestProperty"); - } - - @Test - public void testNullResponse() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testNullResponse"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = null; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - - SystemClock.sleep(1000); - - assertUtil.debug("Added sdk_click 1"); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: null"); - - assertUtil.error("Failed to read response. (null)"); - - assertUtil.error("Failed to track click. (Sdk_click runtime exception: java.lang.NullPointerException)"); - - // does not to try to retry - assertUtil.notInError("Retrying sdk_click package for the"); - assertUtil.notInDebug("Added sdk_click"); - } - - @Test - public void testClientException() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testClientException"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = ResponseType.CLIENT_PROTOCOL_EXCEPTION; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: CLIENT_PROTOCOL_EXCEPTION"); - - assertUtil.error("Failed to track click. (Sdk_click request failed. Will retry later: java.io.IOException: testResponseError)"); - - // tries to retry - assertUtil.error("Retrying sdk_click package for the 1 time"); - - // adds to end of the queue - assertUtil.debug("Added sdk_click"); - } - - @Test - public void testServerError() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testServerError"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = ResponseType.INTERNAL_SERVER_ERROR; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getErrorStream, responseType: INTERNAL_SERVER_ERROR"); - - assertUtil.verbose("Response: { \"message\": \"testResponseError\"}"); - - assertUtil.error("testResponseError"); - } - - @Test - public void testWrongJson() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testWrongJson"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = ResponseType.WRONG_JSON; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: WRONG_JSON"); - - assertUtil.verbose("Response: not a json response"); - - assertUtil.error("Failed to parse json response. (Value not of type java.lang.String cannot be converted to JSONObject)"); - } - - @Test - public void testEmptyJson() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testWrongJson"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = ResponseType.EMPTY_JSON; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: EMPTY_JSON"); - - assertUtil.verbose("Response: { }"); - - assertUtil.info("No message found"); - } - - @Test - public void testMessage() { - // assert test name to read better in logcat - mockLogger.Assert("TestRequestHandler testWrongJson"); - - AdjustFactory.setSdkClickBackoffStrategy(BackoffStrategy.NO_WAIT); - - SdkClickHandler sdkClickHandler = new SdkClickHandler(mockActivityHandler, true); - - mockHttpsURLConnection.responseType = ResponseType.MESSAGE; - - sdkClickHandler.sendSdkClick(sdkClickPackage); - SystemClock.sleep(1000); - - TestActivityPackage.testQueryStringRequest(mockHttpsURLConnection.readRequest(), null); - - assertUtil.test("MockHttpsURLConnection getInputStream, responseType: MESSAGE"); - - assertUtil.verbose("Response: { \"message\" : \"response OK\"}"); - - assertUtil.info("response OK"); - - // sends response to activity handler to be checked - assertUtil.test("ActivityHandler finishedTrackingActivity, message:response OK timestamp:null json:{\"message\":\"response OK\"}"); - } -} diff --git a/Adjust/test-unit/src/main/AndroidManifest.xml b/Adjust/test-unit/src/main/AndroidManifest.xml deleted file mode 100644 index 88a0de621..000000000 --- a/Adjust/test-unit/src/main/AndroidManifest.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Adjust/test-unit/src/main/java/com/adjust/sdk/test/UnitTestActivity.java b/Adjust/test-unit/src/main/java/com/adjust/sdk/test/UnitTestActivity.java deleted file mode 100644 index 4f18fadda..000000000 --- a/Adjust/test-unit/src/main/java/com/adjust/sdk/test/UnitTestActivity.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.adjust.sdk.test; - -import android.app.Activity; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -public class UnitTestActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_unit_test); - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_unit_test, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } -} diff --git a/Adjust/test-unit/src/main/res/drawable-hdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 96a442e5b..000000000 Binary files a/Adjust/test-unit/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-unit/src/main/res/drawable-mdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 359047dfa..000000000 Binary files a/Adjust/test-unit/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-unit/src/main/res/drawable-xhdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 71c6d760f..000000000 Binary files a/Adjust/test-unit/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-unit/src/main/res/drawable-xxhdpi/ic_launcher.png b/Adjust/test-unit/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 4df189464..000000000 Binary files a/Adjust/test-unit/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/Adjust/test-unit/src/main/res/layout/activity_unit_test.xml b/Adjust/test-unit/src/main/res/layout/activity_unit_test.xml deleted file mode 100644 index b4e91d10a..000000000 --- a/Adjust/test-unit/src/main/res/layout/activity_unit_test.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - diff --git a/Adjust/test-unit/src/main/res/menu/menu_unit_test.xml b/Adjust/test-unit/src/main/res/menu/menu_unit_test.xml deleted file mode 100644 index e2e0db43e..000000000 --- a/Adjust/test-unit/src/main/res/menu/menu_unit_test.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/Adjust/test-unit/src/main/res/values-w820dp/dimens.xml b/Adjust/test-unit/src/main/res/values-w820dp/dimens.xml deleted file mode 100644 index 63fc81644..000000000 --- a/Adjust/test-unit/src/main/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - 64dp - diff --git a/Adjust/test-unit/src/main/res/values/dimens.xml b/Adjust/test-unit/src/main/res/values/dimens.xml deleted file mode 100644 index 47c822467..000000000 --- a/Adjust/test-unit/src/main/res/values/dimens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 16dp - 16dp - diff --git a/Adjust/test-unit/src/main/res/values/strings.xml b/Adjust/test-unit/src/main/res/values/strings.xml deleted file mode 100644 index 5ac683268..000000000 --- a/Adjust/test-unit/src/main/res/values/strings.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - Test - Hello world! - Settings - - diff --git a/Adjust/sdk-plugin-trademob/.gitignore b/Adjust/tests/test-app-core/.gitignore similarity index 100% rename from Adjust/sdk-plugin-trademob/.gitignore rename to Adjust/tests/test-app-core/.gitignore diff --git a/Adjust/test-app-core/build.gradle b/Adjust/tests/test-app-core/build.gradle similarity index 54% rename from Adjust/test-app-core/build.gradle rename to Adjust/tests/test-app-core/build.gradle index 86aeebad4..8afc89b76 100644 --- a/Adjust/test-app-core/build.gradle +++ b/Adjust/tests/test-app-core/build.gradle @@ -1,12 +1,18 @@ apply plugin: 'com.android.application' +repositories { + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } +} + android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.adjust.testapp" - minSdkVersion 14 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" } @@ -19,13 +25,15 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' + implementation 'com.google.android.gms:play-services-appset:16.1.0' implementation project(':sdk-core') - implementation project(':test-options') - implementation project(':test-library') + implementation project(':tests:test-options') + implementation project(':tests:test-library') } diff --git a/Adjust/test-kotlin/proguard-rules.pro b/Adjust/tests/test-app-core/proguard-rules.pro similarity index 100% rename from Adjust/test-kotlin/proguard-rules.pro rename to Adjust/tests/test-app-core/proguard-rules.pro diff --git a/Adjust/test-app-core/src/main/AndroidManifest.xml b/Adjust/tests/test-app-core/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/test-app-core/src/main/AndroidManifest.xml rename to Adjust/tests/test-app-core/src/main/AndroidManifest.xml diff --git a/Adjust/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java similarity index 58% rename from Adjust/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java rename to Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java index 39f1d7280..828c7b379 100644 --- a/Adjust/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java +++ b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/AdjustCommandExecutor.java @@ -1,5 +1,8 @@ package com.adjust.testapp; +import static com.adjust.testapp.MainActivity.baseUrl; +import static com.adjust.testapp.MainActivity.gdprUrl; + import android.content.Context; import android.net.Uri; import android.os.Handler; @@ -11,34 +14,37 @@ import com.adjust.sdk.AdjustAdRevenue; import com.adjust.sdk.AdjustAttribution; import com.adjust.sdk.AdjustConfig; +import com.adjust.sdk.AdjustDeeplink; import com.adjust.sdk.AdjustEvent; import com.adjust.sdk.AdjustEventFailure; import com.adjust.sdk.AdjustEventSuccess; -import com.adjust.sdk.AdjustPurchase; +import com.adjust.sdk.AdjustPlayStoreSubscription; +import com.adjust.sdk.AdjustPlayStorePurchase; import com.adjust.sdk.AdjustPurchaseVerificationResult; +import com.adjust.sdk.AdjustRemoteTrigger; import com.adjust.sdk.AdjustSessionFailure; import com.adjust.sdk.AdjustSessionSuccess; -import com.adjust.sdk.AdjustPlayStoreSubscription; +import com.adjust.sdk.AdjustStoreInfo; import com.adjust.sdk.AdjustTestOptions; import com.adjust.sdk.AdjustThirdPartySharing; +import com.adjust.sdk.AdjustThirdPartySharingResult; import com.adjust.sdk.LogLevel; import com.adjust.sdk.OnAttributionChangedListener; -import com.adjust.sdk.OnDeeplinkResponseListener; +import com.adjust.sdk.OnDeeplinkResolvedListener; +import com.adjust.sdk.OnDeferredDeeplinkResponseListener; import com.adjust.sdk.OnEventTrackingFailedListener; import com.adjust.sdk.OnEventTrackingSucceededListener; -import com.adjust.sdk.OnDeeplinkResolvedListener; +import com.adjust.sdk.OnLastDeeplinkReadListener; import com.adjust.sdk.OnPurchaseVerificationFinishedListener; +import com.adjust.sdk.OnRemoteTriggerListener; import com.adjust.sdk.OnSessionTrackingFailedListener; import com.adjust.sdk.OnSessionTrackingSucceededListener; +import com.adjust.sdk.OnThirdPartySharingSettingsChangedListener; import com.adjust.test_options.TestConnectionOptions; -import org.json.JSONException; -import org.json.JSONObject; - +import java.util.HashMap; import java.util.List; - -import static com.adjust.testapp.MainActivity.baseUrl; -import static com.adjust.testapp.MainActivity.gdprUrl; +import java.util.Map; /** * Created by nonelse on 10.03.17. @@ -74,26 +80,37 @@ public void executeCommand(final Command sentCommand) { 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 "addGlobalCallbackParameter": addGlobalCallbackParameter(); break; + case "addGlobalPartnerParameter": addGlobalPartnerParameter(); break; + case "removeGlobalCallbackParameter": removeGlobalCallbackParameter(); break; + case "removeGlobalPartnerParameter": removeGlobalPartnerParameter(); break; + case "removeGlobalCallbackParameters": removeGlobalCallbackParameters(); break; + case "removeGlobalPartnerParameters": removeGlobalPartnerParameters(); break; case "setPushToken": setPushToken(); break; // case "teardown": teardown(); break; case "openDeeplink": openDeeplink(); break; case "sendReferrer": sendReferrer(); break; case "gdprForgetMe": gdprForgetMe(); break; - case "disableThirdPartySharing": disableThirdPartySharing(); break; case "thirdPartySharing" : thirdPartySharing(); break; case "measurementConsent" : measurementConsent(); break; - case "trackAdRevenue": trackAdRevenue(); break; - case "trackAdRevenueV2" : trackAdRevenueV2(); break; - case "trackSubscription": trackSubscription(); break; + case "trackAdRevenue" : trackAdRevenue(); break; + case "trackSubscription": trackPlayStoreSubscription(); break; case "verifyPurchase": verifyPurchase(); break; + case "verifyTrack": verifyTrack(); break; case "processDeeplink" : processDeeplink(); break; + case "attributionGetter" : attributionGetter(); break; + case "attributionGetterWithTimeout" : attributionGetterWithTimeout(); break; + case "adidGetter" : adidGetter(); break; + case "adidGetterWithTimeout" : adidGetterWithTimeout(); break; + case "getLastDeeplink" : getLastDeeplink(); break; + case "endFirstSessionDelay" : endFirstSessionDelay(); break; + case "coppaComplianceInDelay" : coppaComplianceInDelay(); break; + case "playStoreKidsComplianceInDelay" : playStoreKidsComplianceInDelay(); break; + case "externalDeviceIdInDelay" : externalDeviceIdInDelay(); break; + case "sdkVersionGetter" : sdkVersionGetter(); break; + case "googleAdIdGetter" : googleAdIdGetter(); break; + case "amazonAdIdGetter" : amazonAdIdGetter(); break; + case "tpsSettingsGetter" : tpsSettingsGetter(); break; //case "testBegin": testBegin(); break; // case "testEnd": testEnd(); break; } @@ -165,6 +182,18 @@ private void testOptions() { testOptions.noBackoffWait = noBackoffWaitBoolean; } } + if (command.containsParameter("doNotIgnoreSystemLifecycleBootstrap")) { + String doNotIgnoreSystemLifecycleBootstrapString = + command.getFirstParameterValue("doNotIgnoreSystemLifecycleBootstrap"); + Boolean doNotIgnoreSystemLifecycleBootstrap = + Util.strictParseStringToBoolean(doNotIgnoreSystemLifecycleBootstrapString); + if (doNotIgnoreSystemLifecycleBootstrap != null + && doNotIgnoreSystemLifecycleBootstrap.booleanValue()) + { + testOptions.ignoreSystemLifecycleBootstrap = false; + } + } + boolean useTestConnectionOptions = false; if (command.containsParameter("teardown")) { List teardownOptions = command.parameters.get("teardown"); @@ -254,7 +283,7 @@ private void config() { break; case "assert": logLevel = LogLevel.ASSERT; break; - case "suppress": logLevel = LogLevel.SUPRESS; + case "suppress": logLevel = LogLevel.SUPPRESS; break; } Log.d("TestApp", logLevel.toString()); @@ -271,59 +300,26 @@ private void config() { 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 ignored) { - - } - } - - 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("needsCost")) { - String needsCostS = command.getFirstParameterValue("needsCost"); - boolean needsCost = "true".equals(needsCostS); - adjustConfig.setNeedsCost(needsCost); - } - - if (command.containsParameter("eventBufferingEnabled")) { - String eventBufferingEnabledS = command.getFirstParameterValue("eventBufferingEnabled"); - boolean eventBufferingEnabled = "true".equals(eventBufferingEnabledS); - adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); + String isCostDataInAttributionEnabledS = command.getFirstParameterValue("needsCost"); + boolean isCostDataInAttributionEnabled = "true".equals(isCostDataInAttributionEnabledS); + if (isCostDataInAttributionEnabled) { + adjustConfig.enableCostDataInAttribution(); + } } if (command.containsParameter("sendInBackground")) { - String sendInBackgroundS = command.getFirstParameterValue("sendInBackground"); - boolean sendInBackground = "true".equals(sendInBackgroundS); - adjustConfig.setSendInBackground(sendInBackground); + String isSendingInBackgroundEnabledS = command.getFirstParameterValue("sendInBackground"); + boolean isSendingInBackgroundEnabled = "true".equals(isSendingInBackgroundEnabledS); + if (isSendingInBackgroundEnabled) { + adjustConfig.enableSendingInBackground(); + } } - if (command.containsParameter("userAgent")) { - String userAgent = command.getFirstParameterValue("userAgent"); - adjustConfig.setUserAgent(userAgent); + if (command.containsParameter("eventDeduplicationIdsMaxSize")) { + String eventDeduplicationIdsMaxSizeS = command.getFirstParameterValue("eventDeduplicationIdsMaxSize"); + int eventDeduplicationIdsMaxSize = Integer.parseInt(eventDeduplicationIdsMaxSizeS); + adjustConfig.setEventDeduplicationIdsMaxSize(eventDeduplicationIdsMaxSize); } if (command.containsParameter("externalDeviceId")) { @@ -334,23 +330,33 @@ private void config() { if (command.containsParameter("coppaCompliant")) { String coppaCompliantS = command.getFirstParameterValue("coppaCompliant"); boolean coppaCompliant = "true".equals(coppaCompliantS); - adjustConfig.setCoppaCompliantEnabled(coppaCompliant); + if (coppaCompliant) { + adjustConfig.enableCoppaCompliance(); + } } if (command.containsParameter("playStoreKids")) { String playStoreKidsS = command.getFirstParameterValue("playStoreKids"); boolean playStoreKids = "true".equals(playStoreKidsS); - adjustConfig.setPlayStoreKidsAppEnabled(playStoreKids); + if (playStoreKids) { + adjustConfig.enablePlayStoreKidsCompliance(); + } } - if (command.containsParameter("finalAttributionEnabled")) { - String finalAttributionEnabledS = command.getFirstParameterValue("finalAttributionEnabled"); - boolean finalAttributionEnabled = "true".equals(finalAttributionEnabledS); - adjustConfig.setFinalAttributionEnabled(finalAttributionEnabled); + if (command.containsParameter("storeName")) { + AdjustStoreInfo storeInfo; + String storeName = command.getFirstParameterValue("storeName"); + storeInfo = new AdjustStoreInfo(storeName); + + if (command.containsParameter("storeAppId")) { + String storeAppId = command.getFirstParameterValue("storeAppId"); + storeInfo.setStoreAppId(storeAppId); + } + adjustConfig.setStoreInfo(storeInfo); } if(command.containsParameter("deferredDeeplinkCallback")) { - adjustConfig.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + adjustConfig.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { @Override public boolean launchReceivedDeeplink(Uri deeplink) { if (deeplink == null) { @@ -372,7 +378,37 @@ public boolean launchReceivedDeeplink(Uri deeplink) { public void onAttributionChanged(AdjustAttribution attribution) { Log.d("TestApp", "attribution = " + attribution.toString()); - MainActivity.testLibrary.setInfoToSend(attribution.toMap()); + // TODO: do we wanna map actual backend param names into the toMap() method? + // MainActivity.testLibrary.setInfoToSend(attribution.toMap()); + Map fields = new HashMap<>(); + if (attribution.trackerToken != null) fields.put("tracker_token", attribution.trackerToken); + if (attribution.trackerName != null) fields.put("tracker_name", attribution.trackerName); + if (attribution.network != null) fields.put("network", attribution.network); + if (attribution.campaign != null) fields.put("campaign", attribution.campaign); + if (attribution.adgroup != null) fields.put("adgroup", attribution.adgroup); + if (attribution.creative != null) fields.put("creative", attribution.creative); + if (attribution.clickLabel != null) fields.put("click_label", attribution.clickLabel); + if (attribution.costType != null) fields.put("cost_type", attribution.costType); + if (attribution.costAmount != null) fields.put("cost_amount", attribution.costAmount.toString()); + if (attribution.costCurrency != null) fields.put("cost_currency", attribution.costCurrency); + if (attribution.fbInstallReferrer != null) fields.put("fb_install_referrer", attribution.fbInstallReferrer); + if (attribution.jsonResponse != null) fields.put("json_response", attribution.jsonResponse); + MainActivity.testLibrary.setInfoToSend(fields); + MainActivity.testLibrary.sendInfoToServer(localBasePath); + } + }); + } + + if (command.containsParameter("thirdPartySharingSettingsChangedCallbackSendAll")) { + final String localBasePath = basePath; + adjustConfig.setOnThirdPartySharingSettingsChangedListener(new OnThirdPartySharingSettingsChangedListener() { + @Override + public void onThirdPartySharingSettingsChanged(AdjustThirdPartySharingResult result) { + Map fields = new HashMap<>(); + if (result != null && result.getThirdPartySharingSettingsJson() != null) { + fields.put("third_party_sharing_settings", result.getThirdPartySharingSettingsJson()); + } + MainActivity.testLibrary.setInfoToSend(fields); MainActivity.testLibrary.sendInfoToServer(localBasePath); } }); @@ -382,7 +418,7 @@ public void onAttributionChanged(AdjustAttribution attribution) { final String localBasePath = basePath; adjustConfig.setOnSessionTrackingSucceededListener(new OnSessionTrackingSucceededListener() { @Override - public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { + public void onSessionTrackingSucceeded(AdjustSessionSuccess sessionSuccessResponseData) { Log.d("TestApp", "session_success = " + sessionSuccessResponseData.toString()); MainActivity.testLibrary.addInfoToSend("message", sessionSuccessResponseData.message); @@ -400,7 +436,7 @@ public void onFinishedSessionTrackingSucceeded(AdjustSessionSuccess sessionSucce final String localBasePath = basePath; adjustConfig.setOnSessionTrackingFailedListener(new OnSessionTrackingFailedListener() { @Override - public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { + public void onSessionTrackingFailed(AdjustSessionFailure sessionFailureResponseData) { Log.d("TestApp", "session_fail = " + sessionFailureResponseData.toString()); MainActivity.testLibrary.addInfoToSend("message", sessionFailureResponseData.message); @@ -419,7 +455,7 @@ public void onFinishedSessionTrackingFailed(AdjustSessionFailure sessionFailureR final String localBasePath = basePath; adjustConfig.setOnEventTrackingSucceededListener(new OnEventTrackingSucceededListener() { @Override - public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { + public void onEventTrackingSucceeded(AdjustEventSuccess eventSuccessResponseData) { Log.d("TestApp", "event_success = " + eventSuccessResponseData.toString()); MainActivity.testLibrary.addInfoToSend("message", eventSuccessResponseData.message); @@ -439,7 +475,7 @@ public void onFinishedEventTrackingSucceeded(AdjustEventSuccess eventSuccessResp final String localBasePath = basePath; adjustConfig.setOnEventTrackingFailedListener(new OnEventTrackingFailedListener() { @Override - public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { + public void onEventTrackingFailed(AdjustEventFailure eventFailureResponseData) { Log.d("TestApp", "event_fail = " + eventFailureResponseData.toString()); MainActivity.testLibrary.addInfoToSend("message", eventFailureResponseData.message); @@ -460,7 +496,7 @@ public void onFinishedEventTrackingFailed(AdjustEventFailure eventFailureRespons String launchDeferredDeeplinkS = command.getFirstParameterValue("deferredDeeplinkCallback"); final boolean launchDeferredDeeplink = "true".equals(launchDeferredDeeplinkS); final String localBasePath = basePath; - adjustConfig.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + adjustConfig.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { @Override public boolean launchReceivedDeeplink(Uri deeplink) { Log.d("TestApp", "deferred_deep_link = " + deeplink.toString()); @@ -470,6 +506,92 @@ public boolean launchReceivedDeeplink(Uri deeplink) { } }); } + + if (command.containsParameter("remoteTriggerCallback")) { + Log.d("TestApp", "remoteTriggerCallback detected"); + final String localBasePath = basePath; + adjustConfig.setOnRemoteTriggerListener(new OnRemoteTriggerListener() { + @Override + public void onRemoteTrigger(AdjustRemoteTrigger trigger) { + Log.d("TestApp", "Remote trigger callback called!"); + Log.d("TestApp", String.format("onRemoteTrigger label: %s, payload: %s", trigger.getLabel(), trigger.getPayload())); + MainActivity.testLibrary.addInfoToSend("label", trigger.getLabel()); + + if (trigger.getPayload() != null) { + MainActivity.testLibrary.addInfoToSend("payload", trigger.getPayload().toString()); + } else { + Log.d("TestApp", "Remote trigger payload is null"); + MainActivity.testLibrary.addInfoToSend("payload", "null"); + } + + MainActivity.testLibrary.sendInfoToServer(localBasePath); + } + }); + } + + if (command.containsParameter("firstSessionDelayEnabled")) { + String firstSessionDelayEnabledS = command.getFirstParameterValue("firstSessionDelayEnabled"); + boolean firstSessionDelayEnabled = "true".equals(firstSessionDelayEnabledS); + if (firstSessionDelayEnabled) { + adjustConfig.enableFirstSessionDelay(); + } + } + + if (command.containsParameter("googleAdIdReadingEnabled")) { + String googleAdIdReadingEnabledS = command.getFirstParameterValue("googleAdIdReadingEnabled"); + boolean googleAdIdReadingEnabled = "true".equals(googleAdIdReadingEnabledS); + if (!googleAdIdReadingEnabled) { + adjustConfig.disableGoogleAdIdReading(); + } + } + + if (command.containsParameter("androidIdReadingEnabled")) { + String androidIdReadingEnabledS = command.getFirstParameterValue("androidIdReadingEnabled"); + boolean androidIdReadingEnabled = "true".equals(androidIdReadingEnabledS); + if (!androidIdReadingEnabled) { + adjustConfig.disableAndroidIdReading(); + } + } + + if (command.containsParameter("appSetIdReadingEnabled")) { + String appSetIdReadingEnabledS = command.getFirstParameterValue("appSetIdReadingEnabled"); + boolean appSetIdReadingEnabled = "true".equals(appSetIdReadingEnabledS); + if (!appSetIdReadingEnabled) { + adjustConfig.disableAppSetIdReading(); + } + } + + if (command.containsParameter("fbIdReadingEnabled")) { + String fbIdReadingEnabledS = command.getFirstParameterValue("fbIdReadingEnabled"); + boolean fbIdReadingEnabled = "true".equals(fbIdReadingEnabledS); + if (!fbIdReadingEnabled) { + adjustConfig.disableFbIdReading(); + } + } + + if (command.containsParameter("fireAdIdReadingEnabled")) { + String fireAdIdReadingEnabledS = command.getFirstParameterValue("fireAdIdReadingEnabled"); + boolean fireAdIdReadingEnabled = "true".equals(fireAdIdReadingEnabledS); + if (!fireAdIdReadingEnabled) { + adjustConfig.disableFireAdIdReading(); + } + } + + if (command.containsParameter("deviceIdsFromPluginsReadingEnabled")) { + String deviceIdsFromPluginsReadingEnabledS = command.getFirstParameterValue("deviceIdsFromPluginsReadingEnabled"); + boolean deviceIdsFromPluginsReadingEnabled = "true".equals(deviceIdsFromPluginsReadingEnabledS); + if (!deviceIdsFromPluginsReadingEnabled) { + adjustConfig.disableDeviceIdsFromPluginsReading(); + } + } + + if (command.containsParameter("deviceIdsReadingEnabled")) { + String deviceIdsReadingEnabledS = command.getFirstParameterValue("deviceIdsReadingEnabled"); + boolean deviceIdsReadingEnabled = "true".equals(deviceIdsReadingEnabledS); + if (!deviceIdsReadingEnabled) { + adjustConfig.disableDeviceIdsReading(); + } + } } private void start() { @@ -483,7 +605,7 @@ private void start() { AdjustConfig adjustConfig = savedConfigs.get(configNumber); //adjustConfig.setBasePath(basePath); - Adjust.onCreate(adjustConfig); + Adjust.initSdk(adjustConfig); this.savedConfigs.remove(0); } @@ -531,6 +653,10 @@ private void event() throws NullPointerException { String orderId = command.getFirstParameterValue("orderId"); adjustEvent.setOrderId(orderId); } + if (command.parameters.containsKey("deduplicationId")) { + String deduplicationId = command.getFirstParameterValue("deduplicationId"); + adjustEvent.setDeduplicationId(deduplicationId); + } if (command.parameters.containsKey("callbackId")) { String callbackId = command.getFirstParameterValue("callbackId"); adjustEvent.setCallbackId(callbackId); @@ -576,66 +702,70 @@ private void resume() { private void setEnabled() { Boolean enabled = Boolean.valueOf(command.getFirstParameterValue("enabled")); - Adjust.setEnabled(enabled); + if (enabled){ + Adjust.enable(); + }else { + Adjust.disable(); + } } private void setOfflineMode() { Boolean enabled = Boolean.valueOf(command.getFirstParameterValue("enabled")); - Adjust.setOfflineMode(enabled); - } - - private void sendFirstPackages() { - Adjust.sendFirstPackages(); + if (enabled) { + Adjust.switchToOfflineMode(); + }else { + Adjust.switchBackToOnlineMode(); + } } - private void addSessionCallbackParameter() { + private void addGlobalCallbackParameter() { 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 { + MainActivity.testLibrary.addInfoToSend("verification_status", result.getVerificationStatus()); + MainActivity.testLibrary.addInfoToSend("code", String.valueOf(result.getCode())); + MainActivity.testLibrary.addInfoToSend("message", result.getMessage()); + MainActivity.testLibrary.sendInfoToServer(localBasePath); + }); + + this.savedEvents.remove(0); + } + private void processDeeplink() { String deeplink = command.getFirstParameterValue("deeplink"); Uri deeplinkUri = Uri.parse(deeplink); final String localBasePath = basePath; - Adjust.processDeeplink(deeplinkUri, context, new OnDeeplinkResolvedListener() { + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(deeplinkUri); + Adjust.processAndResolveDeeplink(adjustDeeplink, context, new OnDeeplinkResolvedListener() { @Override public void onDeeplinkResolved(String resolvedLink) { MainActivity.testLibrary.addInfoToSend("resolved_link", resolvedLink); @@ -846,6 +988,197 @@ public void onDeeplinkResolved(String resolvedLink) { } }); } + + private void attributionGetter() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getAttribution(attribution -> { + Map fields = new HashMap<>(); + fields.put("test_callback_id", testCallbackId); + if (attribution.trackerToken != null) + fields.put("tracker_token", attribution.trackerToken); + if (attribution.trackerName != null) + fields.put("tracker_name", attribution.trackerName); + if (attribution.network != null) + fields.put("network", attribution.network); + if (attribution.campaign != null) + fields.put("campaign", attribution.campaign); + if (attribution.adgroup != null) + fields.put("adgroup", attribution.adgroup); + if (attribution.creative != null) + fields.put("creative", attribution.creative); + if (attribution.clickLabel != null) + fields.put("click_label", attribution.clickLabel); + if (attribution.costType != null) + fields.put("cost_type", attribution.costType); + if (attribution.costAmount != null) + fields.put("cost_amount", attribution.costAmount.toString()); + if (attribution.costCurrency != null) + fields.put("cost_currency", attribution.costCurrency); + if (attribution.fbInstallReferrer != null) + fields.put("fb_install_referrer", attribution.fbInstallReferrer); + if (attribution.jsonResponse != null) + fields.put("json_response", attribution.jsonResponse); + + MainActivity.testLibrary.setInfoToSend(fields); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void attributionGetterWithTimeout() { + long timeout = Long.parseLong(command.getFirstParameterValue("timeout")); + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getAttributionWithTimeout(context, timeout, attribution -> { + Map fields = new HashMap<>(); + fields.put("test_callback_id", testCallbackId); + if (attribution != null) { + if (attribution.trackerToken != null) + fields.put("tracker_token", attribution.trackerToken); + if (attribution.trackerName != null) + fields.put("tracker_name", attribution.trackerName); + if (attribution.network != null) + fields.put("network", attribution.network); + if (attribution.campaign != null) + fields.put("campaign", attribution.campaign); + if (attribution.adgroup != null) + fields.put("adgroup", attribution.adgroup); + if (attribution.creative != null) + fields.put("creative", attribution.creative); + if (attribution.clickLabel != null) + fields.put("click_label", attribution.clickLabel); + if (attribution.costType != null) + fields.put("cost_type", attribution.costType); + if (attribution.costAmount != null) + fields.put("cost_amount", attribution.costAmount.toString()); + if (attribution.costCurrency != null) + fields.put("cost_currency", attribution.costCurrency); + if (attribution.fbInstallReferrer != null) + fields.put("fb_install_referrer", attribution.fbInstallReferrer); + if (attribution.jsonResponse != null) + fields.put("json_response", attribution.jsonResponse); + + MainActivity.testLibrary.setInfoToSend(fields); + } else { + MainActivity.testLibrary.addInfoToSend("attribution", "null"); + } + + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void adidGetter() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getAdid(adid -> { + MainActivity.testLibrary.addInfoToSend("adid", adid); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void adidGetterWithTimeout() { + long timeout = Long.parseLong(command.getFirstParameterValue("timeout")); + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getAdidWithTimeout(context, timeout, adid -> { + if (adid != null) { + MainActivity.testLibrary.addInfoToSend("adid", adid); + } else { + MainActivity.testLibrary.addInfoToSend("adid", "null"); + } + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void tpsSettingsGetter() { + long timeout = Long.parseLong(command.getFirstParameterValue("timeout")); + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getThirdPartySharingSettingsWithTimeout(context, timeout, adjustThirdPartySharingResult -> { + Map fields = new HashMap<>(); + if (adjustThirdPartySharingResult != null) { + fields.put("third_party_sharing", adjustThirdPartySharingResult.getThirdPartySharingSettingsJson()); + } + MainActivity.testLibrary.setInfoToSend(fields); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void getLastDeeplink() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + final String localBasePath = basePath; + + Adjust.getLastDeeplink(context, new OnLastDeeplinkReadListener() { + @Override + public void onLastDeeplinkRead(Uri deeplink) { + MainActivity.testLibrary.addInfoToSend("last_deeplink", deeplink == null ? "" : deeplink.toString()); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(localBasePath); + } + }); + } + + private void endFirstSessionDelay() { + Adjust.endFirstSessionDelay(); + } + + private void coppaComplianceInDelay() { + String isEnabledString = command.getFirstParameterValue("isEnabled"); + if ("true".equals(isEnabledString)) { + Adjust.enableCoppaComplianceInDelay(); + } + if ("false".equals(isEnabledString)) { + Adjust.disableCoppaComplianceInDelay(); + } + } + + private void playStoreKidsComplianceInDelay() { + String isEnabledString = command.getFirstParameterValue("isEnabled"); + if ("true".equals(isEnabledString)) { + Adjust.enablePlayStoreKidsComplianceInDelay(); + } + if ("false".equals(isEnabledString)) { + Adjust.disablePlayStoreKidsComplianceInDelay(); + } + } + + private void externalDeviceIdInDelay() { + String externalDeviceId = command.getFirstParameterValue("externalDeviceId"); + Adjust.setExternalDeviceIdInDelay(externalDeviceId); + } + + private void sdkVersionGetter() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getSdkVersion(sdkVersion -> { + MainActivity.testLibrary.addInfoToSend("sdk_version", sdkVersion); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void googleAdIdGetter() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getGoogleAdId(context, googleAdId -> { + MainActivity.testLibrary.addInfoToSend("gps_adid", googleAdId); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } + + private void amazonAdIdGetter() { + String testCallbackId = command.getFirstParameterValue("testCallbackId"); + + Adjust.getAmazonAdId(context, amazonAdId -> { + MainActivity.testLibrary.addInfoToSend("fire_adid", amazonAdId); + MainActivity.testLibrary.addInfoToSend("test_callback_id", testCallbackId); + MainActivity.testLibrary.sendInfoToServer(basePath); + }); + } /* private void testBegin() { if (command.containsParameter("teardown")) { diff --git a/Adjust/test-app-core/src/main/java/com/adjust/testapp/Command.java b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/Command.java similarity index 100% rename from Adjust/test-app-core/src/main/java/com/adjust/testapp/Command.java rename to Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/Command.java diff --git a/Adjust/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java similarity index 100% rename from Adjust/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java rename to Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/CommandListener.java diff --git a/Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java similarity index 57% rename from Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java rename to Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java index f56cdc0ad..a7ec2a0d9 100644 --- a/Adjust/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java +++ b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/MainActivity.java @@ -7,6 +7,8 @@ import androidx.appcompat.app.AppCompatActivity; import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; +import com.adjust.sdk.OnSdkVersionReadListener; import com.adjust.test.TestLibrary; public class MainActivity extends AppCompatActivity { @@ -21,23 +23,32 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - // Check if deferred deep link was received + // Check if deferred deeplink was received Intent intent = getIntent(); Uri deeplinkData = intent.getData(); if (deeplinkData != null) { - Adjust.appWillOpenUrl(deeplinkData, getApplicationContext()); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(deeplinkData); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); return; } - testLibrary = new TestLibrary(baseUrl, controlUrl, new CommandListener(this.getApplicationContext())); + testLibrary = new TestLibrary(baseUrl, controlUrl, this.getApplicationContext(), + new CommandListener(this.getApplicationContext())); // testLibrary.doNotExitAfterEnd(); startTestSession(); } private void startTestSession() { - // testLibrary.addTestDirectory("current/gdpr"); + //testLibrary.addTestDirectory("app-secret"); + //testLibrary.addTest("Test_Event_Params"); + + Adjust.getSdkVersion(new OnSdkVersionReadListener() { + @Override + public void onSdkVersionRead(String sdkVersion) { + testLibrary.startTestSession(sdkVersion); + } + }); - testLibrary.startTestSession(Adjust.getSdkVersion()); } } diff --git a/Adjust/test-app-core/src/main/java/com/adjust/testapp/Util.java b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/Util.java similarity index 97% rename from Adjust/test-app-core/src/main/java/com/adjust/testapp/Util.java rename to Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/Util.java index 3fced07ed..7a66a814c 100644 --- a/Adjust/test-app-core/src/main/java/com/adjust/testapp/Util.java +++ b/Adjust/tests/test-app-core/src/main/java/com/adjust/testapp/Util.java @@ -39,11 +39,12 @@ static UtilNetworking.IConnectionOptions testConnectionOptions() { return new UtilNetworking.IConnectionOptions() { @Override public void applyConnectionOptions(final HttpsURLConnection connection, - final String clientSdk) + final String clientSdk, + final int timeout) { UtilNetworking.IConnectionOptions defaultConnectionOption = UtilNetworking.createDefaultConnectionOptions(); - defaultConnectionOption.applyConnectionOptions(connection, clientSdk); + defaultConnectionOption.applyConnectionOptions(connection, clientSdk, timeout); try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[]{ diff --git a/Adjust/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/tests/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/tests/test-app-core/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/test-app-core/src/main/res/drawable/ic_launcher_background.xml b/Adjust/tests/test-app-core/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/tests/test-app-core/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/test-app-core/src/main/res/layout/activity_main.xml b/Adjust/tests/test-app-core/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/layout/activity_main.xml rename to Adjust/tests/test-app-core/src/main/res/layout/activity_main.xml diff --git a/Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/tests/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/tests/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/tests/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/tests/test-app-core/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/tests/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/tests/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/tests/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/tests/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/tests/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-core/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-core/src/main/res/values/colors.xml b/Adjust/tests/test-app-core/src/main/res/values/colors.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/values/colors.xml rename to Adjust/tests/test-app-core/src/main/res/values/colors.xml diff --git a/Adjust/test-app-core/src/main/res/values/strings.xml b/Adjust/tests/test-app-core/src/main/res/values/strings.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/values/strings.xml rename to Adjust/tests/test-app-core/src/main/res/values/strings.xml diff --git a/Adjust/test-app-core/src/main/res/values/styles.xml b/Adjust/tests/test-app-core/src/main/res/values/styles.xml similarity index 100% rename from Adjust/test-app-core/src/main/res/values/styles.xml rename to Adjust/tests/test-app-core/src/main/res/values/styles.xml diff --git a/Adjust/sdk-plugin-webbridge/.gitignore b/Adjust/tests/test-app-webbridge/.gitignore similarity index 100% rename from Adjust/sdk-plugin-webbridge/.gitignore rename to Adjust/tests/test-app-webbridge/.gitignore diff --git a/Adjust/test-app-webbridge/build.gradle b/Adjust/tests/test-app-webbridge/build.gradle similarity index 61% rename from Adjust/test-app-webbridge/build.gradle rename to Adjust/tests/test-app-webbridge/build.gradle index dd83f91e0..6cdeeb988 100644 --- a/Adjust/test-app-webbridge/build.gradle +++ b/Adjust/tests/test-app-webbridge/build.gradle @@ -1,12 +1,18 @@ apply plugin: 'com.android.application' +repositories { + maven { + url "https://central.sonatype.com/repository/maven-snapshots/" + } +} + android { - compileSdk 34 + compileSdk 37 defaultConfig { applicationId "com.example.testappwebbridge" - minSdkVersion 17 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 versionCode 1 versionName "1.0" } @@ -14,7 +20,7 @@ android { buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } namespace 'com.example.testappwebbridge' @@ -24,11 +30,12 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.constraintlayout:constraintlayout:2.1.1" - implementation 'com.google.android.gms:play-services-ads-identifier:17.1.0' + implementation 'com.google.android.gms:play-services-ads-identifier:18.2.0' implementation 'com.android.installreferrer:installreferrer:2.2' + implementation 'com.adjust.signature:adjust-android-signature:5.0.0' implementation project(':sdk-core') - implementation project(':sdk-plugin-webbridge') - implementation project(':test-options') - implementation project(':test-library') + implementation project(':plugins:sdk-plugin-webbridge') + implementation project(':tests:test-options') + implementation project(':tests:test-library') } diff --git a/Adjust/test-library/proguard-rules.pro b/Adjust/tests/test-app-webbridge/proguard-rules.pro similarity index 100% rename from Adjust/test-library/proguard-rules.pro rename to Adjust/tests/test-app-webbridge/proguard-rules.pro diff --git a/Adjust/test-app-webbridge/src/main/AndroidManifest.xml b/Adjust/tests/test-app-webbridge/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/AndroidManifest.xml rename to Adjust/tests/test-app-webbridge/src/main/AndroidManifest.xml diff --git a/Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html b/Adjust/tests/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html similarity index 85% rename from Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html rename to Adjust/tests/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html index e4a0ed006..48f6af4f7 100755 --- a/Adjust/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html +++ b/Adjust/tests/test-app-webbridge/src/main/assets/AdjustTestApp-WebView.html @@ -11,6 +11,7 @@ + @@ -22,7 +23,9 @@

Adjust Web View SDK Test

window.onload = function() { // TestLibrary.addTestDirectory('current/user-agent'); // TestLibrary.addTest('current/deeplink-deferred/Test_DeferredDeeplink_callback_false'); - TestLibrary.startTestSession(Adjust.getSdkVersion()); + Adjust.getSdkVersion(function(sdkVersion) { + TestLibrary.startTestSession(sdkVersion); + }); }
diff --git a/Adjust/test-app-webbridge/src/main/assets/command_executor.js b/Adjust/tests/test-app-webbridge/src/main/assets/command_executor.js similarity index 57% rename from Adjust/test-app-webbridge/src/main/assets/command_executor.js rename to Adjust/tests/test-app-webbridge/src/main/assets/command_executor.js index be549df22..dcebe38b4 100644 --- a/Adjust/test-app-webbridge/src/main/assets/command_executor.js +++ b/Adjust/tests/test-app-webbridge/src/main/assets/command_executor.js @@ -122,21 +122,31 @@ AdjustCommandExecutor.prototype.executeCommand = function(command, idx) { case "setEnabled" : this.setEnabled(command.params); break; case "setReferrer" : this.setReferrer(command.params); break; case "setOfflineMode" : this.setOfflineMode(command.params); break; - case "sendFirstPackages" : this.sendFirstPackages(command.params); break; - case "addSessionCallbackParameter" : this.addSessionCallbackParameter(command.params); break; - case "addSessionPartnerParameter" : this.addSessionPartnerParameter(command.params); break; - case "removeSessionCallbackParameter" : this.removeSessionCallbackParameter(command.params); break; - case "removeSessionPartnerParameter" : this.removeSessionPartnerParameter(command.params); break; - case "resetSessionCallbackParameters" : this.resetSessionCallbackParameters(command.params); break; - case "resetSessionPartnerParameters" : this.resetSessionPartnerParameters(command.params); break; + case "addGlobalCallbackParameter" : this.addGlobalCallbackParameter(command.params); break; + case "addGlobalPartnerParameter" : this.addGlobalPartnerParameter(command.params); break; + case "removeGlobalCallbackParameter" : this.removeGlobalCallbackParameter(command.params); break; + case "removeGlobalPartnerParameter" : this.removeGlobalPartnerParameter(command.params); break; + case "removeGlobalCallbackParameters" : this.removeGlobalCallbackParameters(command.params); break; + case "removeGlobalPartnerParameters" : this.removeGlobalPartnerParameters(command.params); break; case "setPushToken" : this.setPushToken(command.params); break; case "openDeeplink" : this.openDeeplink(command.params); break; case "sendReferrer" : this.sendReferrer(command.params); break; case "gdprForgetMe" : this.gdprForgetMe(command.params); break; - case "disableThirdPartySharing" : this.disableThirdPartySharing(command.params); break; case "thirdPartySharing" : this.thirdPartySharing(command.params); break; case "measurementConsent" : this.measurementConsent(command.params); break; case "trackAdRevenue" : this.trackAdRevenue(command.params); break; + case "attributionGetter" : this.attributionGetter(command.params); break; + case "attributionGetterWithTimeout" : this.attributionGetterWithTimeout(command.params); break; + case "adidGetter" : this.adidGetter(command.params); break; + case "adidGetterWithTimeout" : this.adidGetterWithTimeout(command.params); break; + case "endFirstSessionDelay" : this.endFirstSessionDelay(command.params); break; + case "coppaComplianceInDelay" : this.coppaComplianceInDelay(command.params); break; + case "playStoreKidsComplianceInDelay" : this.playStoreKidsComplianceInDelay(command.params); break; + case "externalDeviceIdInDelay" : this.externalDeviceIdInDelay(command.params); break; + case "sdkVersionGetter" : this.sdkVersionGetter(command.params); break; + case "googleAdIdGetter" : this.googleAdIdGetter(command.params); break; + case "amazonAdIdGetter" : this.amazonAdIdGetter(command.params); break; + case "tpsSettingsGetter" : this.tpsSettingsGetter(command.params); break; break; } @@ -290,89 +300,152 @@ AdjustCommandExecutor.prototype.config = function(params) { } if ('externalDeviceId' in params) { - var externalDeviceId = getFirstParameterValue(params, 'externalDeviceId'); - adjustConfig.setExternalDeviceId(externalDeviceId); + var externalDeviceId = getFirstParameterValue(params, 'externalDeviceId'); + adjustConfig.setExternalDeviceId(externalDeviceId); + } + + if ('needsCost' in params) { + var isCostDataInAttributionEnabledS = getFirstParameterValue(params, 'needsCost'); + var isCostDataInAttributionEnabled = isCostDataInAttributionEnabledS == 'true'; + if (isCostDataInAttributionEnabled == true) { + adjustConfig.enableCostDataInAttribution(); } + } - if ('appSecret' in params) { - var appSecretArray = getValueFromKey(params, 'appSecret'); - var secretId = appSecretArray[0].toString(); - var info1 = appSecretArray[1].toString(); - var info2 = appSecretArray[2].toString(); - var info3 = appSecretArray[3].toString(); - var info4 = appSecretArray[4].toString(); + if ('sendInBackground' in params) { + var isSendingInBackgroundEnabledS = getFirstParameterValue(params, 'sendInBackground'); + var isSendingInBackgroundEnabled = isSendingInBackgroundEnabledS == 'true'; + if (isSendingInBackgroundEnabled == true) { + adjustConfig.enableSendingInBackground(); + } + } - adjustConfig.setAppSecret(secretId, info1, info2, info3, info4); + if ('eventDeduplicationIdsMaxSize' in params) { + var eventDeduplicationIdsMaxSizeS = getFirstParameterValue(params, 'eventDeduplicationIdsMaxSize'); + var eventDeduplicationIdsMaxSize = parseInt(eventDeduplicationIdsMaxSizeS); + adjustConfig.setEventDeduplicationIdsMaxSize(eventDeduplicationIdsMaxSize); } - if ('delayStart' in params) { - var delayStartS = getFirstParameterValue(params, 'delayStart'); - var delayStart = parseFloat(delayStartS); - adjustConfig.setDelayStart(delayStart); + if ('coppaCompliant' in params) { + var coppaCompliantS = getFirstParameterValue(params, 'coppaCompliant'); + var coppaCompliant = coppaCompliantS == 'true'; + if (coppaCompliant == true) { + adjustConfig.enableCoppaCompliance(); + } } - if ('deviceKnown' in params) { - var deviceKnownS = getFirstParameterValue(params, 'deviceKnown'); - var deviceKnown = deviceKnownS == 'true'; - adjustConfig.setDeviceKnown(deviceKnown); + if ('playStoreKids' in params) { + var playStoreKidsS = getFirstParameterValue(params, 'playStoreKids'); + var playStoreKids = playStoreKidsS == 'true'; + if (playStoreKids == true) { + adjustConfig.enablePlayStoreKidsCompliance(); + } } - if ('needsCost' in params) { - var needsCostS = getFirstParameterValue(params, 'needsCost'); - var needsCost = needsCostS == 'true'; - adjustConfig.setNeedsCost(needsCost); + if ('firstSessionDelayEnabled' in params) { + var firstSessionDelayEnabledS = getFirstParameterValue(params, 'firstSessionDelayEnabled'); + var firstSessionDelayEnabled = firstSessionDelayEnabledS == 'true'; + if (firstSessionDelayEnabled == true) { + adjustConfig.enableFirstSessionDelay(); + } } - if ('eventBufferingEnabled' in params) { - var eventBufferingEnabledS = getFirstParameterValue(params, 'eventBufferingEnabled'); - var eventBufferingEnabled = eventBufferingEnabledS == 'true'; - adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); + if ('googleAdIdReadingEnabled' in params) { + var googleAdIdReadingEnabledS = getFirstParameterValue(params, 'googleAdIdReadingEnabled'); + var googleAdIdReadingEnabled = googleAdIdReadingEnabledS == 'true'; + if (googleAdIdReadingEnabled == false) { + adjustConfig.disableGoogleAdIdReading(); + } } - if ('sendInBackground' in params) { - var sendInBackgroundS = getFirstParameterValue(params, 'sendInBackground'); - var sendInBackground = sendInBackgroundS == 'true'; - adjustConfig.setSendInBackground(sendInBackground); + if ('androidIdReadingEnabled' in params) { + var androidIdReadingEnabledS = getFirstParameterValue(params, 'androidIdReadingEnabled'); + var androidIdReadingEnabled = androidIdReadingEnabledS == 'true'; + if (androidIdReadingEnabled == false) { + adjustConfig.disableAndroidIdReading(); + } } - if ('userAgent' in params) { - var userAgent = getFirstParameterValue(params, 'userAgent'); - adjustConfig.setUserAgent(userAgent); + if ('appSetIdReadingEnabled' in params) { + var appSetIdReadingEnabledS = getFirstParameterValue(params, 'appSetIdReadingEnabled'); + var appSetIdReadingEnabled = appSetIdReadingEnabledS == 'true'; + if (appSetIdReadingEnabled == false) { + adjustConfig.disableAppSetIdReading(); + } } - if ('coppaCompliant' in params) { - var coppaCompliantS = getFirstParameterValue(params, 'coppaCompliant'); - var coppaCompliant = coppaCompliantS == 'true'; - adjustConfig.setCoppaCompliantEnabled(coppaCompliant); + if ('fbIdReadingEnabled' in params) { + var fbIdReadingEnabledS = getFirstParameterValue(params, 'fbIdReadingEnabled'); + var fbIdReadingEnabled = fbIdReadingEnabledS == 'true'; + if (fbIdReadingEnabled == false) { + adjustConfig.disableFbIdReading(); + } } - if ('playStoreKids' in params) { - var playStoreKidsS = getFirstParameterValue(params, 'playStoreKids'); - var playStoreKids = playStoreKidsS == 'true'; - adjustConfig.setPlayStoreKidsAppEnabled(playStoreKids); + if ('fireAdIdReadingEnabled' in params) { + var fireAdIdReadingEnabledS = getFirstParameterValue(params, 'fireAdIdReadingEnabled'); + var fireAdIdReadingEnabled = fireAdIdReadingEnabledS == 'true'; + if (fireAdIdReadingEnabled == false) { + adjustConfig.disableFireAdIdReading(); + } } - if ('finalAttributionEnabled' in params) { - var finalAttributionEnabledS = getFirstParameterValue(params, 'finalAttributionEnabled'); - var finalAttributionEnabled = finalAttributionEnabledS == 'true'; - adjustConfig.setFinalAttributionEnabled(finalAttributionEnabled); + if ('deviceIdsFromPluginsReadingEnabled' in params) { + var deviceIdsFromPluginsReadingEnabledS = getFirstParameterValue(params, 'deviceIdsFromPluginsReadingEnabled'); + var deviceIdsFromPluginsReadingEnabled = deviceIdsFromPluginsReadingEnabledS == 'true'; + if (deviceIdsFromPluginsReadingEnabled == false) { + adjustConfig.disableDeviceIdsFromPluginsReading(); + } + } + + if ('deviceIdsReadingEnabled' in params) { + var deviceIdsReadingEnabledS = getFirstParameterValue(params, 'deviceIdsReadingEnabled'); + var deviceIdsReadingEnabled = deviceIdsReadingEnabledS == 'true'; + if (deviceIdsReadingEnabled == false) { + adjustConfig.disableDeviceIdsReading(); + } + } + + if ('storeName' in params) { + var storeInfo; + var storeName = getFirstParameterValue(params, 'storeName'); + storeInfo = new AdjustStoreInfo(storeName); + + if ('storeAppId' in params) { + var storeAppId = getFirstParameterValue(params, 'storeAppId'); + storeInfo.setStoreAppId(storeAppId); + } + adjustConfig.setStoreInfo(storeInfo); } if ('attributionCallbackSendAll' in params) { var basePath = this.basePath; adjustConfig.setAttributionCallback(function(attribution) { - TestLibrary.addInfoToSend("trackerToken", attribution.trackerToken); - TestLibrary.addInfoToSend("trackerName", attribution.trackerName); + TestLibrary.addInfoToSend("tracker_token", attribution.trackerToken); + TestLibrary.addInfoToSend("tracker_name", attribution.trackerName); TestLibrary.addInfoToSend("network", attribution.network); TestLibrary.addInfoToSend("campaign", attribution.campaign); TestLibrary.addInfoToSend("adgroup", attribution.adgroup); TestLibrary.addInfoToSend("creative", attribution.creative); - TestLibrary.addInfoToSend("clickLabel", attribution.clickLabel); - TestLibrary.addInfoToSend("adid", attribution.adid); - TestLibrary.addInfoToSend("costType", attribution.costType); - TestLibrary.addInfoToSend("costAmount", attribution.costAmount); - TestLibrary.addInfoToSend("costCurrency", attribution.costCurrency); - TestLibrary.addInfoToSend("fbInstallReferrer", attribution.fbInstallReferrer); + TestLibrary.addInfoToSend("click_label", attribution.clickLabel); + TestLibrary.addInfoToSend("cost_type", attribution.costType); + TestLibrary.addInfoToSend("cost_amount", attribution.costAmount); + TestLibrary.addInfoToSend("cost_currency", attribution.costCurrency); + TestLibrary.addInfoToSend("fb_install_referrer", attribution.fbInstallReferrer); + TestLibrary.addInfoToSend("json_response", JSON.stringify(attribution.jsonResponse)); + + TestLibrary.sendInfoToServer(basePath); + }); + } + + if ('thirdPartySharingSettingsChangedCallbackSendAll' in params) { + var basePath = this.basePath; + adjustConfig.setThirdPartySharingSettingsChangedCallback(function(result) { + if (result != null) { + TestLibrary.addInfoToSend("third_party_sharing_settings", result.thirdPartySharingSettingsJson); + } else { + TestLibrary.addInfoToSend("third_party_sharing_settings", null); + } TestLibrary.sendInfoToServer(basePath); }); @@ -434,14 +507,27 @@ AdjustCommandExecutor.prototype.config = function(params) { if ('deferredDeeplinkCallback' in params) { var basePath = this.basePath; - var openDeeplinkS = getFirstParameterValue(params, 'deferredDeeplinkCallback'); - var openDeeplink = openDeeplinkS == 'true'; - adjustConfig.setOpenDeferredDeeplink(openDeeplink); + var isOpeningDeferredDeeplinkEnabledS = getFirstParameterValue(params, 'deferredDeeplinkCallback'); + var isOpeningDeferredDeeplinkEnabled = isOpeningDeferredDeeplinkEnabledS == 'true'; + if (isOpeningDeferredDeeplinkEnabled == false) { + adjustConfig.disableDeferredDeeplinkOpening(); + } + adjustConfig.setDeferredDeeplinkCallback(function(deeplink) { TestLibrary.addInfoToSend("deeplink", deeplink); TestLibrary.sendInfoToServer(basePath); }); } + + if ('remoteTriggerCallback' in params) { + var basePath = this.basePath; + adjustConfig.setRemoteTriggerCallback(function(remoteTrigger) { + TestLibrary.addInfoToSend("label", remoteTrigger.label); + TestLibrary.addInfoToSend("payload", JSON.stringify(remoteTrigger.payload)); + + TestLibrary.sendInfoToServer(basePath); + }); + } }; AdjustCommandExecutor.prototype.start = function(params) { @@ -453,7 +539,7 @@ AdjustCommandExecutor.prototype.start = function(params) { } var adjustConfig = this.savedConfigs[configNumber]; - Adjust.onCreate(adjustConfig); + Adjust.initSdk(adjustConfig); delete this.savedConfigs[0]; }; @@ -499,9 +585,9 @@ AdjustCommandExecutor.prototype.event = function(params) { } } - if ('orderId' in params) { - var orderId = getFirstParameterValue(params, 'orderId'); - adjustEvent.setOrderId(orderId); + if ('deduplicationId' in params) { + var deduplicationId = getFirstParameterValue(params, 'deduplicationId'); + adjustEvent.setDeduplicationId(deduplicationId); } if ('callbackId' in params) { @@ -549,26 +635,26 @@ AdjustCommandExecutor.prototype.resume = function(params) { AdjustCommandExecutor.prototype.setEnabled = function(params) { var enabled = getFirstParameterValue(params, "enabled") == 'true'; - Adjust.setEnabled(enabled); + if(enabled){ + Adjust.enable(); + }else{ + Adjust.disable(); + } }; AdjustCommandExecutor.prototype.setOfflineMode = function(params) { var enabled = getFirstParameterValue(params, "enabled") == 'true'; - Adjust.setOfflineMode(enabled); -}; - -AdjustCommandExecutor.prototype.sendFirstPackages = function(params) { - Adjust.sendFirstPackages(); + if (enabled){ + Adjust.switchToOfflineMode() + }else{ + Adjust.switchBackToOnlineMode() + } }; AdjustCommandExecutor.prototype.gdprForgetMe = function(params) { Adjust.gdprForgetMe(); } -AdjustCommandExecutor.prototype.disableThirdPartySharing = function(params) { - Adjust.disableThirdPartySharing(); -} - AdjustCommandExecutor.prototype.thirdPartySharing = function(params) { var isEnabled = null; if ('isEnabled' in params) { @@ -591,7 +677,7 @@ AdjustCommandExecutor.prototype.thirdPartySharing = function(params) { for (var i = 0; i < partnerSharingSettings.length; i = i + 3) { var partnerName = partnerSharingSettings[i]; var key = partnerSharingSettings[i + 1]; - var value = partnerSharingSettings[i + 2]; + var value = partnerSharingSettings[i + 2] == 'true'; adjustThirdPartySharing.addPartnerSharingSetting(partnerName, key, value); } } @@ -604,54 +690,81 @@ AdjustCommandExecutor.prototype.measurementConsent = function(params) { Adjust.trackMeasurementConsent(isEnabled); } -AdjustCommandExecutor.prototype.addSessionCallbackParameter = function(params) { +AdjustCommandExecutor.prototype.endFirstSessionDelay = function(params) { + Adjust.endFirstSessionDelay(); +} + +AdjustCommandExecutor.prototype.coppaComplianceInDelay = function(params) { + var enabled = getFirstParameterValue(params, "isEnabled") == 'true'; + if (enabled){ + Adjust.enableCoppaComplianceInDelay() + }else{ + Adjust.disableCoppaComplianceInDelay() + } +} + +AdjustCommandExecutor.prototype.playStoreKidsComplianceInDelay = function(params) { + var enabled = getFirstParameterValue(params, "isEnabled") == 'true'; + if (enabled){ + Adjust.enablePlayStoreKidsComplianceInDelay() + }else{ + Adjust.disablePlayStoreKidsComplianceInDelay() + } +} + +AdjustCommandExecutor.prototype.externalDeviceIdInDelay = function(params) { + var externalDeviceId = getFirstParameterValue(params, "externalDeviceId"); + Adjust.setExternalDeviceIdInDelay(externalDeviceId); +} + +AdjustCommandExecutor.prototype.addGlobalCallbackParameter = function(params) { var list = getValueFromKey(params, "KeyValue"); for (var i = 0; i < list.length; i = i+2){ var key = list[i]; var value = list[i+1]; - Adjust.addSessionCallbackParameter(key, value); + Adjust.addGlobalCallbackParameter(key, value); } }; -AdjustCommandExecutor.prototype.addSessionPartnerParameter = function(params) { +AdjustCommandExecutor.prototype.addGlobalPartnerParameter = function(params) { var list = getValueFromKey(params, "KeyValue"); for (var i = 0; i < list.length; i = i+2){ var key = list[i]; var value = list[i+1]; - Adjust.addSessionPartnerParameter(key, value); + Adjust.addGlobalPartnerParameter(key, value); } }; -AdjustCommandExecutor.prototype.removeSessionCallbackParameter = function(params) { +AdjustCommandExecutor.prototype.removeGlobalCallbackParameter = function(params) { if ('key' in params) { var list = getValueFromKey(params, 'key'); for (var i = 0; i < list.length; i++) { - Adjust.removeSessionCallbackParameter(list[i]); + Adjust.removeGlobalCallbackParameter(list[i]); } } }; -AdjustCommandExecutor.prototype.removeSessionPartnerParameter = function(params) { +AdjustCommandExecutor.prototype.removeGlobalPartnerParameter = function(params) { if ('key' in params) { var list = getValueFromKey(params, 'key'); for (var i = 0; i < list.length; i++) { - Adjust.removeSessionPartnerParameter(list[i]); + Adjust.removeGlobalPartnerParameter(list[i]); } } }; -AdjustCommandExecutor.prototype.resetSessionCallbackParameters = function(params) { - Adjust.resetSessionCallbackParameters(); +AdjustCommandExecutor.prototype.removeGlobalCallbackParameters = function(params) { + Adjust.removeGlobalCallbackParameters(); }; -AdjustCommandExecutor.prototype.resetSessionPartnerParameters = function(params) { - Adjust.resetSessionPartnerParameters(); +AdjustCommandExecutor.prototype.removeGlobalPartnerParameters = function(params) { + Adjust.removeGlobalPartnerParameters(); }; AdjustCommandExecutor.prototype.setPushToken = function(params) { @@ -659,16 +772,143 @@ AdjustCommandExecutor.prototype.setPushToken = function(params) { Adjust.setPushToken(token); }; -AdjustCommandExecutor.prototype.openDeeplink = function(params) { - var deeplink = getFirstParameterValue(params, "deeplink"); - Adjust.appWillOpenUrl(deeplink); -}; - AdjustCommandExecutor.prototype.sendReferrer = function(params) { var referrer = getFirstParameterValue(params, 'referrer'); Adjust.setReferrer(referrer); }; +AdjustCommandExecutor.prototype.attributionGetter = function(params) { + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getAttribution(function(attribution) { + TestLibrary.addInfoToSend("tracker_token", attribution.trackerToken); + TestLibrary.addInfoToSend("tracker_name", attribution.trackerName); + TestLibrary.addInfoToSend("network", attribution.network); + TestLibrary.addInfoToSend("campaign", attribution.campaign); + TestLibrary.addInfoToSend("adgroup", attribution.adgroup); + TestLibrary.addInfoToSend("creative", attribution.creative); + TestLibrary.addInfoToSend("click_label", attribution.clickLabel); + TestLibrary.addInfoToSend("cost_type", attribution.costType); + TestLibrary.addInfoToSend("cost_amount", attribution.costAmount); + TestLibrary.addInfoToSend("cost_currency", attribution.costCurrency); + TestLibrary.addInfoToSend("fb_install_referrer", attribution.fbInstallReferrer); + TestLibrary.addInfoToSend("json_response", JSON.stringify(attribution.jsonResponse)); + + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.sdkVersionGetter = function(params) { + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getSdkVersion(function(sdkVersion) { + TestLibrary.addInfoToSend("sdk_version", sdkVersion); + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.googleAdIdGetter = function(params) { + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getGoogleAdId(function(googleAdId) { + TestLibrary.addInfoToSend("gps_adid", googleAdId); + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.amazonAdIdGetter = function(params) { + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getAmazonAdId(function(amazonAdId) { + TestLibrary.addInfoToSend("fire_adid", amazonAdId); + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.attributionGetterWithTimeout = function(params) { + var timeoutS = getFirstParameterValue(params, 'timeout'); + var timeout = parseInt(timeoutS); + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getAttributionWithTimeout(timeout, function(attribution) { + if (attribution != null) { + TestLibrary.addInfoToSend("tracker_token", attribution.trackerToken); + TestLibrary.addInfoToSend("tracker_name", attribution.trackerName); + TestLibrary.addInfoToSend("network", attribution.network); + TestLibrary.addInfoToSend("campaign", attribution.campaign); + TestLibrary.addInfoToSend("adgroup", attribution.adgroup); + TestLibrary.addInfoToSend("creative", attribution.creative); + TestLibrary.addInfoToSend("click_label", attribution.clickLabel); + TestLibrary.addInfoToSend("cost_type", attribution.costType); + TestLibrary.addInfoToSend("cost_amount", attribution.costAmount); + TestLibrary.addInfoToSend("cost_currency", attribution.costCurrency); + TestLibrary.addInfoToSend("fb_install_referrer", attribution.fbInstallReferrer); + TestLibrary.addInfoToSend("json_response", JSON.stringify(attribution.jsonResponse)); + } else { + TestLibrary.addInfoToSend("attribution", "null"); + } + + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.adidGetter = function(params) { + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getAdid(function(adid) { + TestLibrary.addInfoToSend("adid", adid); + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.adidGetterWithTimeout = function(params) { + var timeoutS = getFirstParameterValue(params, 'timeout'); + var timeout = parseInt(timeoutS); + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getAdidWithTimeout(timeout, function(adid) { + if (adid != null) { + TestLibrary.addInfoToSend("adid", adid); + } else { + TestLibrary.addInfoToSend("adid", "null"); + } + + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + +AdjustCommandExecutor.prototype.tpsSettingsGetter = function(params) { + var timeoutS = getFirstParameterValue(params, 'timeout'); + var timeout = parseInt(timeoutS); + var testCallbackId = getFirstParameterValue(params, 'testCallbackId'); + var basePath = this.basePath; + + Adjust.getThirdPartySharingSettingsWithTimeout(timeout, function(adjustThirdPartySharingResult) { + if (adjustThirdPartySharingResult != null) { + TestLibrary.addInfoToSend("third_party_sharing", adjustThirdPartySharingResult.thirdPartySharingSettingsJson); + } else { + TestLibrary.addInfoToSend("third_party_sharing", null); + } + + TestLibrary.addInfoToSend("test_callback_id", testCallbackId); + TestLibrary.sendInfoToServer(basePath); + }); +}; + //Util //====================== function getValueFromKey(params, key) { diff --git a/Adjust/test-app-webbridge/src/main/assets/test_library.js b/Adjust/tests/test-app-webbridge/src/main/assets/test_library.js similarity index 100% rename from Adjust/test-app-webbridge/src/main/assets/test_library.js rename to Adjust/tests/test-app-webbridge/src/main/assets/test_library.js diff --git a/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java b/Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java similarity index 83% rename from Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java rename to Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java index 0c0c16a16..5d0f916fa 100644 --- a/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java +++ b/Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/MainActivity.java @@ -49,22 +49,10 @@ public boolean onConsoleMessage(ConsoleMessage consoleMessage) { Log.d("testappwebbridge", "loadUrl, exception: " + e.getMessage()); e.printStackTrace(); } - - // Check if deferred deep link was received - Intent intent = getIntent(); - Uri deeplinkData = intent.getData(); - if (deeplinkData != null) { - Adjust.appWillOpenUrl(deeplinkData, getApplicationContext()); - } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - - Uri deeplink = intent.getData(); - if (deeplink != null) { - Adjust.appWillOpenUrl(deeplink, getApplicationContext()); - } } } diff --git a/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java b/Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java similarity index 99% rename from Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java rename to Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java index bd2327392..0f3a9fb04 100644 --- a/Adjust/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java +++ b/Adjust/tests/test-app-webbridge/src/main/java/com/example/testappwebbridge/TestLibraryBridge.java @@ -40,7 +40,7 @@ public static void startTestSession(String clientSdk) { } private static void initTestLibrary() { - TestLibraryBridge.testLibrary = new TestLibrary(baseUrl, controlUrl, new ICommandRawJsonListener() { + TestLibraryBridge.testLibrary = new TestLibrary(baseUrl, controlUrl, application, new ICommandRawJsonListener() { @Override public void executeCommand(String json) { Log.d("testappwebbridge", String.format("execRawTestCommandCallback %s, %d", json, order)); diff --git a/Adjust/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Adjust/tests/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml rename to Adjust/tests/test-app-webbridge/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/Adjust/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml b/Adjust/tests/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml rename to Adjust/tests/test-app-webbridge/src/main/res/drawable/ic_launcher_background.xml diff --git a/Adjust/test-app-webbridge/src/main/res/layout/activity_main.xml b/Adjust/tests/test-app-webbridge/src/main/res/layout/activity_main.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/layout/activity_main.xml rename to Adjust/tests/test-app-webbridge/src/main/res/layout/activity_main.xml diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png rename to Adjust/tests/test-app-webbridge/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/Adjust/test-app-webbridge/src/main/res/values/colors.xml b/Adjust/tests/test-app-webbridge/src/main/res/values/colors.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/values/colors.xml rename to Adjust/tests/test-app-webbridge/src/main/res/values/colors.xml diff --git a/Adjust/test-app-webbridge/src/main/res/values/strings.xml b/Adjust/tests/test-app-webbridge/src/main/res/values/strings.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/values/strings.xml rename to Adjust/tests/test-app-webbridge/src/main/res/values/strings.xml diff --git a/Adjust/test-app-webbridge/src/main/res/values/styles.xml b/Adjust/tests/test-app-webbridge/src/main/res/values/styles.xml similarity index 100% rename from Adjust/test-app-webbridge/src/main/res/values/styles.xml rename to Adjust/tests/test-app-webbridge/src/main/res/values/styles.xml diff --git a/Adjust/sdk-plugin-xiaomi-referrer/.gitignore b/Adjust/tests/test-library/.gitignore similarity index 100% rename from Adjust/sdk-plugin-xiaomi-referrer/.gitignore rename to Adjust/tests/test-library/.gitignore diff --git a/Adjust/test-library/build.gradle b/Adjust/tests/test-library/build.gradle similarity index 95% rename from Adjust/test-library/build.gradle rename to Adjust/tests/test-library/build.gradle index dc397ace7..43be2df9c 100644 --- a/Adjust/test-library/build.gradle +++ b/Adjust/tests/test-library/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdk 34 + compileSdk 37 defaultConfig { - minSdkVersion 9 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 } namespace 'com.adjust.test_library' } diff --git a/Adjust/tests/test-library/proguard-rules.pro b/Adjust/tests/test-library/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/Adjust/tests/test-library/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/sdk-plugin-sociomantic/src/main/AndroidManifest.xml b/Adjust/tests/test-library/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/sdk-plugin-sociomantic/src/main/AndroidManifest.xml rename to Adjust/tests/test-library/src/main/AndroidManifest.xml diff --git a/Adjust/test-library/src/main/java/com/adjust/test/Constants.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/Constants.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/Constants.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/Constants.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandJsonListener.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ICommandListener.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandListener.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ICommandListener.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandListener.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ICommandRawJsonListener.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/IOnExitListener.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/IOnExitListener.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/IOnExitListener.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/IOnExitListener.java diff --git a/Adjust/tests/test-library/src/main/java/com/adjust/test/Networking.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/Networking.java new file mode 100644 index 000000000..36e60dea4 --- /dev/null +++ b/Adjust/tests/test-library/src/main/java/com/adjust/test/Networking.java @@ -0,0 +1,354 @@ +package com.adjust.test; + +import static com.adjust.test.Constants.ONE_MINUTE; +import static com.adjust.test.Utils.debug; +import static com.adjust.test.Utils.error; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.os.Build; + +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.math.BigInteger; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.URL; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +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; + +public class Networking { + private static final class DebugTrustManager implements X509TrustManager { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + debug("getAcceptedIssuers"); + + return null; + } + + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + debug("checkClientTrusted"); + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) { + debug("checkServerTrusted"); + } + } + + private static final class AllowAllHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + public static class Response { + public String response = null; + public Integer responseCode = null; + public Map> headerFields = null; + } + + // region Injected dependencies + private final String baseUrl; + private final Context context; + // endregion + + // region Internal variables + private TrustManager[] trustAllCerts; + private HostnameVerifier hostnameVerifier;; + private String fingerprint; + // endregion + + public String clientSdk; + public String testNames; + + // region Instantiation and Dependencies + public Networking(final String baseUrl, final Context context) { + this.baseUrl = baseUrl; + this.context = context; + this.fingerprint = fingerprint(context); + + trustAllCerts = new TrustManager[]{ + new DebugTrustManager() + }; + hostnameVerifier = new AllowAllHostnameVerifier(); + } + // endregion + + // region Public API + public Response sendPost(String path) { + return sendPost(path, null, null); + } + public Response sendPost(String path, String base) { + return sendPost(path, base, null); + } + public Response sendPost(String path, Map postBody) { + return sendPost(path, null, postBody); + } + public Response sendPost(String path, String base, Map postBody) { + String merged = base == null ? path : base + path; + String targetURL = baseUrl + merged; + + try { + HttpsURLConnection connection = createPOSTHttpsURLConnection( + targetURL, postBody); + Response response = readHttpResponse(connection); + debug("Response: %s", response.response); + + response.headerFields= connection.getHeaderFields(); + debug("Headers: %s", response.headerFields); + + return response; + } catch (IOException e) { + error(e.getMessage()); + } catch (Exception e) { + error(e.getMessage()); + } + return null; + } + // endregion + + // region Internal Methods + private HttpsURLConnection createPOSTHttpsURLConnection( + String urlString, + Map postBody) + throws IOException + { + DataOutputStream wr = null; + HttpsURLConnection connection = null; + + try { + debug("POST request: %s", urlString); + URL url = new URL(urlString); + connection = (HttpsURLConnection) url.openConnection(); + + 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) { + } + } + } + + private void applyConnectionOptions(HttpsURLConnection connection) { + if (clientSdk != null) { + connection.setRequestProperty("Client-SDK", clientSdk); + } + if (testNames != null) { + connection.setRequestProperty("Test-Names", testNames); + } + if (fingerprint != null) { + connection.setRequestProperty("Fingerprint", fingerprint); + } + + //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()); + } + } + + private 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 ""; + } + + 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 Response readHttpResponse(HttpsURLConnection connection) throws Exception { + StringBuffer sb = new StringBuffer(); + Response response = new Response(); + + try { + connection.connect(); + + response.responseCode = connection.getResponseCode(); + InputStream inputStream; + + if (response.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(); + } + } + + response.response = sb.toString(); + return response; + } + + private static String fingerprint(final Context context) { + if (context == null) { + return null; + } + + final PackageManager packageManager = context.getPackageManager(); + final String packageName = context.getPackageName(); + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + final PackageInfo packageInfo = packageManager.getPackageInfo( + packageName, PackageManager.GET_SIGNING_CERTIFICATES); + if (packageInfo == null || packageInfo.signingInfo == null) { + return null; + } + if (packageInfo.signingInfo.hasMultipleSigners()){ + return signatureDigestList(packageInfo.signingInfo.getApkContentsSigners()); + } + else{ + return signatureDigestList(packageInfo.signingInfo.getSigningCertificateHistory()); + } + } + else { + @SuppressLint("PackageManagerGetSignatures") + final PackageInfo packageInfo = packageManager.getPackageInfo( + packageName, PackageManager.GET_SIGNATURES); + return signatureDigestList(packageInfo.signatures); + } + + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + + private static String signatureDigest(final Signature signature) { + if (signature == null) { + return null; + } + + try { + //return toHex( + //MessageDigest.getInstance("SHA1").digest(signature.toByteArray())); + final byte[] signatureByteArray = signature.toByteArray(); + final MessageDigest md = MessageDigest.getInstance("SHA1"); + final byte[] digest = md.digest(signatureByteArray); + final String hex = toHex(digest); + return hex.toLowerCase(); + //return BaseEncoding.base16().lowerCase().encode(digest); + } catch (final NoSuchAlgorithmException e) { + return null; + } + } + private static String signatureDigestList(final Signature[] sigList) { + for (final Signature signature: sigList) { + return signatureDigest(signature); + } + return null; + } + + public static String toHex(final byte[] bytes) { + return String.format("%0" + (bytes.length << 1) + "X", + new BigInteger(1, bytes)); + } + + // endregion +} diff --git a/Adjust/test-library/src/main/java/com/adjust/test/TestCommand.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/TestCommand.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/TestCommand.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/TestCommand.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/TestLibrary.java similarity index 72% rename from Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/TestLibrary.java index 5a85c0c81..535febb73 100644 --- a/Adjust/test-library/src/main/java/com/adjust/test/TestLibrary.java +++ b/Adjust/tests/test-library/src/main/java/com/adjust/test/TestLibrary.java @@ -1,5 +1,6 @@ package com.adjust.test; +import android.content.Context; import android.os.SystemClock; import com.adjust.test.ws.ControlWebSocketClient; @@ -24,7 +25,6 @@ import static com.adjust.test.Constants.WAIT_FOR_SLEEP; import static com.adjust.test.Utils.debug; import static com.adjust.test.Utils.error; -import static com.adjust.test.UtilsNetworking.sendPostI; /** @@ -32,8 +32,53 @@ */ public class TestLibrary { - static String baseUrl; - static String controlUrl; + private static final class StartTestSessionRunnable implements Runnable { + private final TestLibrary testLibrary; + private final String clientSdk; + + private StartTestSessionRunnable(TestLibrary testLibrary, String clientSdk) { + this.testLibrary = testLibrary; + this.clientSdk = clientSdk; + } + + @Override + public void run() { + testLibrary.startTestSessionI(clientSdk); + } + } + + private static final class CancelTestAndGetNextRunnable implements Runnable { + private final TestLibrary testLibrary; + + private CancelTestAndGetNextRunnable(TestLibrary testLibrary) { + this.testLibrary = testLibrary; + } + + @Override + public void run() { + testLibrary.readResponseI(testLibrary.networking.sendPost("/end_test_read_next", testLibrary.currentBasePath)); + } + } + + private static final class SendInfoToServerRunnable implements Runnable { + private final TestLibrary testLibrary; + private final String basePath; + private final Map infoSnapshot; + + private SendInfoToServerRunnable(TestLibrary testLibrary, String basePath, Map infoSnapshot) { + this.testLibrary = testLibrary; + this.basePath = basePath; + this.infoSnapshot = infoSnapshot; + } + + @Override + public void run() { + testLibrary.sendInfoToServerI(basePath, infoSnapshot); + } + } + + private String controlUrl; + private Networking networking; private Gson gson = new Gson(); private BlockingQueue waitControlQueue; private ControlWebSocketClient controlClient; @@ -49,24 +94,24 @@ public class TestLibrary { private StringBuilder currentTestNames = new StringBuilder(); private boolean exitAfterEnd = true; - public TestLibrary(String baseUrl, String controlUrl, ICommandRawJsonListener commandRawJsonListener) { - this(baseUrl, controlUrl); + public TestLibrary(String baseUrl, String controlUrl, Context context, ICommandRawJsonListener commandRawJsonListener) { + this(baseUrl, controlUrl, context); this.commandRawJsonListener = commandRawJsonListener; } - public TestLibrary(String baseUrl, String controlUrl, ICommandJsonListener commandJsonListener) { - this(baseUrl, controlUrl); + public TestLibrary(String baseUrl, String controlUrl, Context context, ICommandJsonListener commandJsonListener) { + this(baseUrl, controlUrl, context); this.commandJsonListener = commandJsonListener; } - public TestLibrary(String baseUrl, String controlUrl, ICommandListener commandListener) { - this(baseUrl, controlUrl); + public TestLibrary(String baseUrl, String controlUrl, Context context, ICommandListener commandListener) { + this(baseUrl, controlUrl, context); this.commandListener = commandListener; } - private TestLibrary(String baseUrl, String controlUrl) { - this.baseUrl = baseUrl; + private TestLibrary(String baseUrl, String controlUrl, Context context) { this.controlUrl = controlUrl; + this.networking = new Networking(baseUrl, context); debug("> base url: \t%s", baseUrl); debug("> control url: \t%s", controlUrl); this.initializeWebSocket(controlUrl); @@ -115,17 +160,12 @@ public void startTestSession(final String clientSdk) { // reconnect web socket client if disconnected if (!this.controlClient.isOpen()) { debug("reconnecting web socket client ..."); - this.initializeWebSocket(controlUrl); + this.initializeWebSocket(this.controlUrl); // wait for WS to reconnect SystemClock.sleep(ONE_SECOND); } - executor.submit(new Runnable() { - @Override - public void run() { - startTestSessionI(clientSdk); - } - }); + executor.submit(new StartTestSessionRunnable(this, clientSdk)); } public void setOnExitListener(IOnExitListener onExitListener) { @@ -138,51 +178,59 @@ public void signalEndWait(String reason) { public void cancelTestAndGetNext() { resetTestLibrary(); - executor.submit(new Runnable() { - @Override - public void run() { - UtilsNetworking.HttpResponse httpResponse = sendPostI(Utils.appendBasePath(currentBasePath, "/end_test_read_next")); - readResponseI(httpResponse); - } - }); + executor.submit(new CancelTestAndGetNextRunnable(this)); } public void addInfoToSend(String key, String value) { - if (infoToServer == null) { - infoToServer = new HashMap(); + synchronized (this) { + if (infoToServer == null) { + infoToServer = new HashMap(); + } + infoToServer.put(key, value); } - infoToServer.put(key, value); } public void setInfoToSend(Map info) { - infoToServer = info; + synchronized (this) { + infoToServer = info; + } } public void sendInfoToServer(final String basePath) { - executor.submit(new Runnable() { - @Override - public void run() { - sendInfoToServerI(basePath); + // Create a snapshot of the current infoToServer map to avoid race conditions + // when multiple callbacks execute concurrently + final Map infoSnapshot; + synchronized (this) { + if (infoToServer == null || infoToServer.isEmpty()) { + infoSnapshot = new HashMap(); + } else { + infoSnapshot = new HashMap(infoToServer); } - }); + // Clear the shared map immediately so next callback starts fresh + infoToServer = null; + } + + executor.submit(new SendInfoToServerRunnable(this, basePath, infoSnapshot)); } private void startTestSessionI(String clientSdk) { - UtilsNetworking.HttpResponse httpResponse = sendPostI("/init_session", clientSdk, currentTestNames.toString()); - this.testSessionId = httpResponse.headerFields.get(TEST_SESSION_ID_HEADER).get(0); + networking.clientSdk = clientSdk; + networking.testNames = currentTestNames.toString(); + Networking.Response response = networking.sendPost("/init_session"); + + this.testSessionId = response.headerFields.get(TEST_SESSION_ID_HEADER).get(0); // set test session ID on the web socket object in Test Server, so it can be uniquely identified this.controlClient.sendInitTestSessionSignal(this.testSessionId); debug("starting new test session with ID: " + this.testSessionId); - readResponseI(httpResponse); + readResponseI(response); } - private void sendInfoToServerI(String basePath) { - UtilsNetworking.HttpResponse httpResponse = sendPostI(Utils.appendBasePath(basePath, "/test_info"), null, infoToServer); - infoToServer = null; - readResponseI(httpResponse); + private void sendInfoToServerI(String basePath, Map infoToSend) { + Networking.Response response = networking.sendPost("/test_info", basePath, infoToSend); + readResponseI(response); } - public void readResponseI(UtilsNetworking.HttpResponse httpResponse) { + public void readResponseI(Networking.Response httpResponse) { if (httpResponse == null) { debug("httpResponse is null"); return; @@ -298,8 +346,7 @@ private void resetTestI(Map> params) { } private void endTestReadNextI() { - UtilsNetworking.HttpResponse httpResponse = sendPostI(Utils.appendBasePath(currentBasePath, "/end_test_read_next")); - readResponseI(httpResponse); + readResponseI(networking.sendPost("/end_test_read_next", currentBasePath)); } private void endTestSessionI() { diff --git a/Adjust/test-library/src/main/java/com/adjust/test/Utils.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/Utils.java similarity index 84% rename from Adjust/test-library/src/main/java/com/adjust/test/Utils.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/Utils.java index 050697581..7cd004f49 100644 --- a/Adjust/test-library/src/main/java/com/adjust/test/Utils.java +++ b/Adjust/tests/test-library/src/main/java/com/adjust/test/Utils.java @@ -1,18 +1,17 @@ package com.adjust.test; +import static com.adjust.test.Constants.LOGTAG; + import android.util.Log; import java.util.Arrays; import java.util.Locale; -import static com.adjust.test.Constants.LOGTAG; - /** * 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)); @@ -30,11 +29,4 @@ public static void error(String message, Object... parameters) { , message, Arrays.toString(parameters))); } } - - public static String appendBasePath(String basePath, String path) { - if (basePath == null) { - return path; - } - return basePath + path; - } } diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ws/ControlSignal.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ws/ControlSignal.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ws/ControlSignal.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ws/ControlSignal.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ws/ControlWebSocketClient.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ws/ControlWebSocketClient.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ws/ControlWebSocketClient.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ws/ControlWebSocketClient.java diff --git a/Adjust/test-library/src/main/java/com/adjust/test/ws/SignalType.java b/Adjust/tests/test-library/src/main/java/com/adjust/test/ws/SignalType.java similarity index 100% rename from Adjust/test-library/src/main/java/com/adjust/test/ws/SignalType.java rename to Adjust/tests/test-library/src/main/java/com/adjust/test/ws/SignalType.java diff --git a/Adjust/test-library/src/main/res/values/strings.xml b/Adjust/tests/test-library/src/main/res/values/strings.xml similarity index 100% rename from Adjust/test-library/src/main/res/values/strings.xml rename to Adjust/tests/test-library/src/main/res/values/strings.xml diff --git a/Adjust/tests/test-options/.gitignore b/Adjust/tests/test-options/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Adjust/tests/test-options/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Adjust/test-options/build.gradle b/Adjust/tests/test-options/build.gradle similarity index 77% rename from Adjust/test-options/build.gradle rename to Adjust/tests/test-options/build.gradle index d1a07df46..0b3e5599c 100644 --- a/Adjust/test-options/build.gradle +++ b/Adjust/tests/test-options/build.gradle @@ -3,11 +3,11 @@ plugins { } android { - compileSdk 34 + compileSdk 37 defaultConfig { - minSdkVersion 9 - targetSdkVersion 34 + minSdkVersion 21 + targetSdkVersion 37 } namespace 'com.adjust.test_options' } diff --git a/Adjust/test-options/consumer-rules.pro b/Adjust/tests/test-options/consumer-rules.pro similarity index 100% rename from Adjust/test-options/consumer-rules.pro rename to Adjust/tests/test-options/consumer-rules.pro diff --git a/Adjust/test-options/proguard-rules.pro b/Adjust/tests/test-options/proguard-rules.pro similarity index 100% rename from Adjust/test-options/proguard-rules.pro rename to Adjust/tests/test-options/proguard-rules.pro diff --git a/Adjust/test-options/src/main/AndroidManifest.xml b/Adjust/tests/test-options/src/main/AndroidManifest.xml similarity index 100% rename from Adjust/test-options/src/main/AndroidManifest.xml rename to Adjust/tests/test-options/src/main/AndroidManifest.xml diff --git a/Adjust/test-options/src/main/java/com/adjust/test_options/TLSSocketFactory.java b/Adjust/tests/test-options/src/main/java/com/adjust/test_options/TLSSocketFactory.java similarity index 100% rename from Adjust/test-options/src/main/java/com/adjust/test_options/TLSSocketFactory.java rename to Adjust/tests/test-options/src/main/java/com/adjust/test_options/TLSSocketFactory.java diff --git a/Adjust/tests/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java b/Adjust/tests/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java new file mode 100644 index 000000000..0c3d4bb45 --- /dev/null +++ b/Adjust/tests/test-options/src/main/java/com/adjust/test_options/TestConnectionOptions.java @@ -0,0 +1,73 @@ +package com.adjust.test_options; + +import android.util.Log; + +import com.adjust.sdk.AdjustFactory; +import com.adjust.sdk.network.UtilNetworking; + +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 TestConnectionOptions { + public static void setTestConnectionOptions() { + AdjustFactory.setConnectionOptions(new UtilNetworking.IConnectionOptions() { + @Override + public void applyConnectionOptions(HttpsURLConnection connection, String clientSdk, int timeout) { + UtilNetworking.IConnectionOptions defaultConnectionOption = + UtilNetworking.createDefaultConnectionOptions(); + defaultConnectionOption.applyConnectionOptions(connection, clientSdk, timeout); + + try { + // create modern SSLContext that supports TLS 1.2+ + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init( + null, + TestConnectionOptions.generateTrustAllCerts(), + new java.security.SecureRandom()); + + // use the modern SSL socket factory instead of TLSSocketFactory + // this avoids the TLS 1.1 limitation + connection.setSSLSocketFactory(sslContext.getSocketFactory()); + connection.setHostnameVerifier(TestConnectionOptions.generateHostnameVerifier()); + } catch (Exception e) { + Log.e("TestOptions","connectionOptions error " + e.getMessage()); + } + } + }); + } + + private static TrustManager[] generateTrustAllCerts() { + return new TrustManager[] { + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + Log.d("TestApp", "getAcceptedIssuers"); + return null; + } + + public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, + final String authType) { + Log.d("TestApp", "checkClientTrusted"); + } + + public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, + final String authType) { + Log.d("TestApp", "checkServerTrusted"); + } + } + }; + } + + private static HostnameVerifier generateHostnameVerifier() { + return new HostnameVerifier() { + @Override + public boolean verify(final String hostname, final SSLSession session) { + Log.d("TestApp", "HostnameVerifier verify"); + return true; + } + }; + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0827cfb8e..23d86d953 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,153 @@ +### Version 5.8.0 (7th August 2026) +#### Added +- Added support for Samsung MAPS (Mobile Application Preload System). +- Added `disableDeviceIdsReading` method to `AdjustConfig` as an umbrella method alternative to invoking individual device ID disabling methods. + +#### Changed +- Updated the Adjust Signature library version to 5.0.0. + +--- + +### Version 5.7.0 (12th May 2026) +#### Added +- Added `getThirdPartySharingSettingsWithTimeout` to the `Adjust` API and `setOnThirdPartySharingSettingsChangedListener` to `AdjustConfig` for reading current third-party-sharing settings from the Adjust backend. +- Added support for sending parameters that identify preinstalled Android system apps. + +--- + +### Version 5.6.1 (16th April 2026) +#### Changed +- Updated the Adjust Signature library version to 3.67.0. + +--- + +### Version 5.6.0 (30th March 2026) +#### Added +- Added `setOnRemoteTriggerListener` method to `AdjustConfig` to allow receiving remote trigger updates sent by Adjust backend. + +--- + +### Version 5.5.1 (4th March 2026) +#### Fixed +- Improved web bridge input validation to address a potential UXSS risk. +- Hardened object deserialization handling for improved security. + +--- + +### Version 5.5.0 (5th December 2025) +#### Added +- Added `getAdidWithTimeout` method to the `Adjust` API to allow retrieving the ADID with a specified timeout. If the value is not obtained in time, null is returned. +- Added `getAttributionWithTimeout` method to the `Adjust` API to allow retrieving the current attribution information with a specified timeout. If the value is not obtained in time, null is returned. +- Added `disableAppSetIdReading` method to `AdjustConfig` to allow disabling the SDK’s reading of the app set ID. + +#### Changed +- Updated the Adjust Signature library version to 3.62.0. + +--- + +### Version 5.4.6 (7th November 2025) +#### Changed +- Refactored LVL plugin to use direct `Binder` interface instead of `AIDL`. + +--- + +### Version 5.4.5 (23rd October 2025) +#### Changed +- Updated the Adjust Signature library version to 3.61.0. +- Updated link resolution logic to include new Adjust domains where link resolution ends. + +--- + +### Version 5.4.4 (18th September 2025) +#### Added +- Added support for Google License Verification (LVL). For more details about this feature, refer to the [official documentation](https://dev.adjust.com/en/sdk/android/plugins/google-lvl-plugin). + +--- + +### Version 5.4.3 (25th August 2025) +#### Added +- Added support for processing deferred deep links in session responses. + +--- + +### Version 5.4.2 (7th August 2025) +#### Changed +- Updated purchase verification handler (internal changes). + +--- + +### Version 5.4.1 (23rd June 2025) +#### Added +- Optimized the logic behind the `processAndResolveDeeplink` method to immediately return links that have already been resolved. + +#### Changed +- Updated the Adjust Signature library version to 3.47.0. + +--- + +### Version 5.4.0 (2nd May 2025) +#### Added +- Added support for configuring store information via the `AdjustStoreInfo` object. You can now specify the store name and store app ID using `setStoreInfo` method on your `AdjustConfig` instance. This enables the SDK to record the intended app store source during initialization. + +--- + +### Version 5.3.0 (16th April 2025) +#### Added +- Added ability to initialize the SDK for the first session in delayed mode. You can start the SDK in the delayed mode by calling the `enableFirstSessionDelay` method on your `AdjustConfig` instance. To end the delay, make sure to call `endFirstSessionDelay` method of `Adjust` instance. For more details about this feature, refer to the [official documentation](https://dev.adjust.com/en/sdk/android/features/first-session-delay). + +--- + +### Version 5.2.0 (24th March 2025) +#### Added +- Added ability to send organic search referrer together with deep link. + +--- + +### Version 5.1.0 (28th January 2025) +#### Added +- Added `jsonResponse` field (JSON string) to `AdjustAttribution` where every key-value pair sent by the backend as part of the attribution response can be found. Equivalently, one can also find `jsonResponse` field being part of the attribution instance in the web bridge API. + +#### Fixed +- Fixed occasional NPE occurrences when app was entering background (https://github.com/adjust/android_sdk/issues/630). + +#### Changed +- Updated Gradle version to 8.8.0. +- Updated the Adjust Signature library version to 3.35.2. +- Updated `isEnabled` listener to be invoked from the main thread. + +--- + +### Version 5.0.2 (5th December 2024) +#### Changed +- Switched to depending on a specific version of the signature library. + +--- + +### Version 5.0.1 (18th September 2024) +#### Fixed +- Fixed ANR while reading install referrer from Shared Preferences during SDK initialization. +- Fixed typo in `SUPPRESS` log level constant and renamed it from `SUPRESS to SUPPRESS` (https://github.com/adjust/android_sdk/issues/613). + +#### Changed +- Added validation when passing callback / partner parameters and third party sharing granular options / partner sharing setting parameters in web bridge. +- Updated some log messages to add more clarity. + +--- + +### Version 5.0.0 (2nd August 2024) + +We're excited to release our major new SDK version (v5). Among many internal improvements, our spoofing protection solution is now included out of the box, reinforcing our commitment to accurate, actionable, and fraud-free data. + +To try out SDK v5 in your app, you can follow our new v4 to v5 [migration guide](https://dev.adjust.com/en/sdk/android/migration/v4-to-v5). + +On [our Signature releases page](https://github.com/adjust/adjust_signature_sdk/releases), you can find the latest version of the Signature library to integrate into your app. + +If you are a current Adjust client and have questions about SDK v5, please email [sdk-v5@adjust.com](mailto:sdk-v5@adjust.com). + +In case you were using beta version of the SDK v5, please switch to the official v5 release. + +--- + ### Version 4.38.5 (2nd July 2024) #### Fixed - Fixed occasional crash while invoking deeplink resolution callback. diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..242e5d555 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012-Present Adjust GmbH, http://www.adjust.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 4c66bfdae..28b4a5ddb 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is the [Adjust](https://adjust.com)™ SDK for Android. Documentation is a ## License -Distributed under the [MIT license](https://opensource.org/licenses/MIT). See [`MIT-LICENSE`](MIT-LICENSE) for the full text. +Distributed under the [MIT license](https://opensource.org/licenses/MIT). See [`LICENSE`](LICENSE) for the full text. [en-helpcenter]: https://help.adjust.com/en/developer/android-sdk-documentation [zh-helpcenter]: https://help.adjust.com/zh/developer/android-sdk-documentation diff --git a/VERSION b/VERSION index 8f4005428..11d9efa3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.38.5 +5.8.0