diff --git a/.github/workflows/build_and_test_sdk.yml b/.github/workflows/build_and_test_sdk.yml index 337a514f4..739552e61 100644 --- a/.github/workflows/build_and_test_sdk.yml +++ b/.github/workflows/build_and_test_sdk.yml @@ -2,7 +2,7 @@ name: The Countly Android SDK Unit Test env: EMULATOR_REPO: us-docker.pkg.dev/android-emulator-268719/images/28-playstore-x64:30.1.2 - JAVA_V: 11 + JAVA_V: 17 JAVA_DIST: corretto permissions: @@ -25,7 +25,7 @@ jobs: steps: - name: Install Docker to the Runner - run: sudo apt-get install docker + run: sudo apt-get install containerd.io - name: Pull Emulator from the Repo run: docker pull ${{ env.EMULATOR_REPO }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f1245b8d..faa57365e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,68 @@ +## 25.4.5 +* Added a new config flag `setUseSerialExecutor(boolean useSerial)` for selecting immediate request executor type. +* Added a new config option `setWebviewDisplayOption(WebViewDisplayOption)` to control how Content and Feedback Widgets are displayed. + * `IMMERSIVE` mode (default): Full-screen display (except cutouts). + * `SAFE_AREA` mode: Omits status bar, navigation bar and cutouts when displaying webviews. +* Added a new config option `disableGradualRequestCleaner()` to change request queue overflow behavior. When enabled, all overflowing requests are removed at once instead of in batches. +* Added a new method `requestQueue().addCustomNetworkRequestHeaders(Map)` for providing or overriding custom headers after init . + +* Mitigated a potential issue where Remote Config calls could have blocked the main UI thread processes. + +* Immediate requests now will be run by parallel executor instead of serial by default. + +## 25.4.4 +* Improved disk size calculation in crash reports. + +* Added a new function "recordMetrics(metricsOverride)" to send a device metrics request, accessible through the requestQueue interface. +* Added a new Consent option "metrics" for controlling "recordMetrics" method. (This has no effect on Session metrics.) +* Added "setRequestTimeoutDuration(requestTimeoutDuration)" init config method to change request timeout duration in seconds. + +* Mitigated an issue displaying Content on API level 35 and above. + +## 25.4.3 +* Improved Health Check metric information. +* Improved Content display mechanics. + +* Mitigated an issue that could have happened when navigating back from a Content. +* Mitigated a persistency issue with configuration provided SBS and its initial state. +* Mitigated an issue where SBS could have been fetched twice. + +## 25.4.2 +* Mitigated an issue where latest fetched behavior settings were replacing the current settings instead of merging. + +## 25.4.1 +* Improved request queue handling with a built-in backoff mechanism which is enabled by default. +* Added "disableBackoffMechanism()" init config method to disable backoff behavior. +* Added "disableSDKBehaviorSettingsUpdates()" init config method to disable server config updates. +* Added fullscreen support for feedback widgets. +* Extended the notification button URL handler to allow custom handling of URLs when notification buttons are clicked in the background. + +* Deprecated "presentFeedbackWidget(widgetInfo, context, closeButtonText, devCallback)", replaced with "presentFeedbackWidget(widgetInfo, context, devCallback)" in the feedbacks. + +## 25.4.0 +* ! Minor breaking change ! Removed Secure.ANDROID_ID usage in device id generation. The SDK now exclusively uses random UUIDs for device id generation. +* ! Minor breaking change ! Server Configuration is now enabled by default. Changes made on SDK Manager > SDK Configuration on your server will affect SDK behavior directly. + +* Added a Content feature method "refreshContentZone" that does a manual refresh. +* Extended server configuration capabilities of the SDK. +* Added a config method to provide server config in the initialization "setSDKBehaviorSettings(String)". +* Added a new interface "CountlyNotificationButtonURLHandler" to allow custom handling of URLs when notification buttons are clicked. Could be set by "CountlyConfigPush.setNotificationButtonURLHandler" + +* Mitigated an issue that caused PN message data collision if two message with same ID was received. + +* Removed the deprecated function "CountlyConfig.setIdMode(idMode)" + +* Deprecated the experimental configuration function enableServerConfiguration. + +## 25.1.1 +* Mitigated an issue where after closing a content, they were not being fetched again. + +## 25.1.0 +* Improved content size management of content blocks. + +* Mitigated an issue where, the action bar was overlapping with the content display. +* Improved the custom CertificateTrustManager to handle domain-specific configurations by supporting hostname-aware checkServerTrusted calls. + ## 24.7.8 * Added a config option to content (setZoneTimerInterval) to set content zone timer. (Experimental!) @@ -7,7 +72,6 @@ ## 24.7.6 * Added support for localization of content blocks. - * Mitigated an issue where visibility could have been wrongly assigned if a view was closed while going to background. (Experimental!) * Fixed a bug where passing the global content callback was not possible. * Mitigated an issue related to content actions navigation. diff --git a/app-kotlin/build.gradle b/app-kotlin/build.gradle index b03df5321..607dfabb3 100644 --- a/app-kotlin/build.gradle +++ b/app-kotlin/build.gradle @@ -6,6 +6,7 @@ plugins { } android { + namespace "ly.count.android.demo.kotlin" compileSdkVersion 35 defaultConfig { diff --git a/app-kotlin/src/main/AndroidManifest.xml b/app-kotlin/src/main/AndroidManifest.xml index 55a1d536e..050bfce8a 100644 --- a/app-kotlin/src/main/AndroidManifest.xml +++ b/app-kotlin/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + diff --git a/app-native/build.gradle b/app-native/build.gradle index d9c97f63e..da6f05d7d 100644 --- a/app-native/build.gradle +++ b/app-native/build.gradle @@ -4,6 +4,7 @@ apply plugin: 'com.android.application' // apply plugin: ly.count.android.plugins.UploadSymbolsPlugin android { + namespace "ly.count.android.demo.crash" compileSdkVersion 35 defaultConfig { diff --git a/app-native/src/main/AndroidManifest.xml b/app-native/src/main/AndroidManifest.xml index 2ee131fb8..41a2aecba 100644 --- a/app-native/src/main/AndroidManifest.xml +++ b/app-native/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + - + @@ -101,6 +100,11 @@ android:label="@string/activity_name_feedback" android:configChanges="orientation|screenSize"/> + + diff --git a/app/src/main/java/ly/count/android/demo/ActivityExampleContentZone.java b/app/src/main/java/ly/count/android/demo/ActivityExampleContentZone.java new file mode 100644 index 000000000..7d728f672 --- /dev/null +++ b/app/src/main/java/ly/count/android/demo/ActivityExampleContentZone.java @@ -0,0 +1,42 @@ +package ly.count.android.demo; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import androidx.appcompat.app.AppCompatActivity; +import java.util.UUID; +import ly.count.android.sdk.Countly; + +public class ActivityExampleContentZone extends AppCompatActivity { + + Activity activity; + EditText deviceIdEditText; + + @Override + public void onCreate(Bundle savedInstanceState) { + activity = this; + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_example_content_zone); + deviceIdEditText = findViewById(R.id.editTextDeviceIdContentZone); + } + + public void onClickEnterContentZone(View v) { + Countly.sharedInstance().contents().enterContentZone(); + } + + public void onClickExitContentZone(View v) { + Countly.sharedInstance().contents().exitContentZone(); + } + + public void onClickRefreshContentZone(View v) { + Countly.sharedInstance().contents().refreshContentZone(); + } + + public void onClickChangeDeviceIdContentZone(View v) { + String deviceId = deviceIdEditText.getText().toString(); + String newDeviceId = deviceId.isEmpty() ? UUID.randomUUID().toString() : deviceId; + + Countly.sharedInstance().deviceId().setID(newDeviceId); + } +} diff --git a/app/src/main/java/ly/count/android/demo/ActivityExampleOthers.java b/app/src/main/java/ly/count/android/demo/ActivityExampleOthers.java index a50b1938c..4cbccbe72 100644 --- a/app/src/main/java/ly/count/android/demo/ActivityExampleOthers.java +++ b/app/src/main/java/ly/count/android/demo/ActivityExampleOthers.java @@ -137,12 +137,4 @@ public void onClickUpdateSession(View v) { public void onClickEndSession(View v) { Countly.sharedInstance().sessions().endSession(); } - - public void onClickFetchContents(View v) { - Countly.sharedInstance().contents().enterContentZone(); - } - - public void onClickExitContents(View v) { - Countly.sharedInstance().contents().exitContentZone(); - } } diff --git a/app/src/main/java/ly/count/android/demo/App.java b/app/src/main/java/ly/count/android/demo/App.java index 42f90d236..fe0ef9a6c 100644 --- a/app/src/main/java/ly/count/android/demo/App.java +++ b/app/src/main/java/ly/count/android/demo/App.java @@ -28,6 +28,7 @@ import ly.count.android.sdk.CrashData; import ly.count.android.sdk.GlobalCrashFilterCallback; import ly.count.android.sdk.ModuleLog; +import ly.count.android.sdk.WebViewDisplayOption; import ly.count.android.sdk.messaging.CountlyConfigPush; import ly.count.android.sdk.messaging.CountlyPush; @@ -146,7 +147,8 @@ public void onCreate() { Map customUserProperties = new ConcurrentHashMap<>(); customUserProperties.put("A", 1); - CountlyConfig config = new CountlyConfig(this, COUNTLY_APP_KEY, COUNTLY_SERVER_URL)//.setDeviceId("67567") + CountlyConfig config = new CountlyConfig(this, COUNTLY_APP_KEY, COUNTLY_SERVER_URL) + // .setDeviceId("a" + applicationStartTimestamp ) .setLoggingEnabled(true) .setLogListener(new ModuleLog.LogCallback() { @Override public void LogHappened(String logMessage, ModuleLog.LogLevel logLevel) { @@ -173,42 +175,30 @@ public void onCreate() { } }) .enableAutomaticViewTracking() - // uncomment the line below to enable auto enrolling the user to AB experiments when downloading RC data //.enrollABOnRCDownload() - // .setMaxRequestQueueSize(5) + //.setMaxRequestQueueSize(5) .enableAutomaticViewShortNames() .setGlobalViewSegmentation(automaticViewSegmentation) .setAutomaticViewTrackingExclusions(new Class[] { ActivityExampleCustomEvents.class }) - .setPushIntentAddMetadata(true) - .setLocation("us", "Böston 墨尔本", "-23.8043604,-46.6718331", "10.2.33.12") //.setDisableLocation() - //.enableManualSessionControl() //.enableManualSessionControlHybridMode() - //.enableTemporaryDeviceIdMode() - .setRequiresConsent(true) - - //for giving all consent values .giveAllConsents() - - //in case you want to control what consent is given during init //.setConsentEnabled(new String[] { // Countly.CountlyFeatureNames.push, Countly.CountlyFeatureNames.sessions, Countly.CountlyFeatureNames.location, // Countly.CountlyFeatureNames.attribution, Countly.CountlyFeatureNames.crashes, Countly.CountlyFeatureNames.events, // Countly.CountlyFeatureNames.starRating, Countly.CountlyFeatureNames.users, Countly.CountlyFeatureNames.views, // Countly.CountlyFeatureNames.apm, Countly.CountlyFeatureNames.remoteConfig, Countly.CountlyFeatureNames.feedback //}) - .setHttpPostForced(false) .setParameterTamperingProtectionSalt("test-salt-checksum") .addCustomNetworkRequestHeaders(customHeaderValues) //.enableCertificatePinning(certificates) //.enablePublicKeyPinning(certificates) - .RemoteConfigRegisterGlobalCallback((downloadResult, error, fullValueUpdate, downloadedValues) -> { if (error == null) { Log.d(Countly.TAG, "Automatic remote config download has completed. " + Countly.sharedInstance().remoteConfig().getValues()); @@ -216,14 +206,13 @@ public void onCreate() { Log.d(Countly.TAG, "Automatic remote config download encountered a problem, " + error); } }) - .setTrackOrientationChanges(true) //.setMetricOverride(metricOverride) - + .setWebviewDisplayOption(WebViewDisplayOption.IMMERSIVE) //.enableServerConfiguration() - .setUserProperties(customUserProperties); + // crash configuration config.crashes .enableCrashReporting() .enableRecordAllThreadsWithCrash() @@ -234,13 +223,16 @@ public void onCreate() { } }); + // APM configuration config.apm.enableAppStartTimeTracking() .enableForegroundBackgroundTracking() .setAppStartTimestampOverride(applicationStartTimestamp); + Countly.sharedInstance().init(config); //Log.i(demoTag, "After calling init. This should return 'true', the value is:" + Countly.sharedInstance().isInitialized()); + //--- PUSH NOTIFICATIONS SETUP ----// List allowedClassNames = new ArrayList<>(); allowedClassNames.add("MainActivity"); List allowedPackageNames = new ArrayList<>(); diff --git a/app/src/main/java/ly/count/android/demo/MainActivity.java b/app/src/main/java/ly/count/android/demo/MainActivity.java index 307e1a668..4b3cd2e78 100644 --- a/app/src/main/java/ly/count/android/demo/MainActivity.java +++ b/app/src/main/java/ly/count/android/demo/MainActivity.java @@ -141,4 +141,8 @@ public void onClickButtonDeviceId(View v) { public void onClickButtonRatings(View v) { startActivity(new Intent(this, ActivityExampleFeedback.class)); } + + public void onClickContentZone(View v) { + startActivity(new Intent(this, ActivityExampleContentZone.class)); + } } diff --git a/app/src/main/res/layout/activity_example_content_zone.xml b/app/src/main/res/layout/activity_example_content_zone.xml new file mode 100644 index 000000000..27adc9c76 --- /dev/null +++ b/app/src/main/res/layout/activity_example_content_zone.xml @@ -0,0 +1,56 @@ + + + + + + + + +