From 7f82a091bc1bb853827501a6e3a4e0c1a0731efc Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Wed, 5 May 2021 09:54:25 +0300 Subject: [PATCH 01/10] Started investigation track visit with source --- sdk/build.gradle | 2 + .../java/cloud/mindbox/mobile_sdk/Mindbox.kt | 21 ++++++-- .../mobile_sdk/managers/LifecycleManager.kt | 52 ++++++++++++++++--- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 88428f93c..f2da050aa 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -140,4 +140,6 @@ dependencies { // dex implementation "androidx.multidex:multidex:2.0.1" + implementation "androidx.lifecycle:lifecycle-process:2.3.1" + } \ No newline at end of file diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index ffdbd8dc8..4596745a9 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -2,6 +2,7 @@ package cloud.mindbox.mobile_sdk import android.app.Application import android.content.Context +import androidx.lifecycle.ProcessLifecycleOwner import cloud.mindbox.mobile_sdk.logger.Level import cloud.mindbox.mobile_sdk.logger.MindboxLogger import cloud.mindbox.mobile_sdk.managers.* @@ -24,6 +25,7 @@ object Mindbox { private val mindboxScope = CoroutineScope(Default + mindboxJob) private val deviceUuidCallbacks = ConcurrentHashMap Unit>() private val fmsTokenCallbacks = ConcurrentHashMap Unit>() + private lateinit var lifecycleManager: LifecycleManager /** * Subscribe to gets token of Firebase Messaging Service used by SDK @@ -190,13 +192,22 @@ object Mindbox { MindboxEventManager.sendEventsIfExist(context) } sendTrackVisitEvent(context, configuration.endpointId) + } - // Handle back app in foreground - val lifecycleManager = LifecycleManager { - sendTrackVisitEvent(context, configuration.endpointId) + // Handle back app in foreground + (context.applicationContext as? Application)?.apply { + if (!Mindbox::lifecycleManager.isInitialized) { + lifecycleManager = LifecycleManager { + sendTrackVisitEvent(context, configuration.endpointId) + } + } else { + unregisterComponentCallbacks(lifecycleManager) + unregisterActivityLifecycleCallbacks(lifecycleManager) + ProcessLifecycleOwner.get().lifecycle.removeObserver(lifecycleManager) } - (context.applicationContext as? Application) - ?.registerActivityLifecycleCallbacks(lifecycleManager) + registerComponentCallbacks(lifecycleManager) + registerActivityLifecycleCallbacks(lifecycleManager) + ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleManager) } }.returnOnException { } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 5ce3d9641..731b667e6 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -2,23 +2,37 @@ package cloud.mindbox.mobile_sdk.managers import android.app.Activity import android.app.Application +import android.content.ComponentCallbacks2 +import android.content.res.Configuration import android.os.Bundle +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.OnLifecycleEvent internal class LifecycleManager( private val onAppStarted: () -> Unit -) : Application.ActivityLifecycleCallbacks { +) : Application.ActivityLifecycleCallbacks, ComponentCallbacks2, LifecycleObserver { - private var currentActivity: Activity? = null + var currentActivity: Activity? = null - override fun onActivityCreated(activity: Activity, p1: Bundle?) { + private var isConfigurationChanged = false + override fun onActivityCreated(activity: Activity, p1: Bundle?) { + Log.d("______", "created cur $currentActivity act $activity") } override fun onActivityStarted(activity: Activity) { - if (currentActivity?.javaClass?.name == activity.javaClass.name) { - onAppStarted() - } else { - currentActivity = activity + Log.d("______", "cur $currentActivity act $activity action ${activity.intent.action} extas ${activity.intent.extras} data ${activity.intent.data} cat ${activity.intent.categories} schema ${activity.intent.scheme}") +activity.intent.scheme + + when { + isConfigurationChanged -> isConfigurationChanged = false + currentActivity?.javaClass?.name == activity.javaClass.name -> { + Log.d("______", "app started") + onAppStarted() + } + else -> currentActivity = activity } } @@ -34,6 +48,7 @@ internal class LifecycleManager( if (currentActivity == null) { currentActivity = activity } + Log.d("______", "stopped cur $currentActivity act $activity action ${activity.intent.action} extas ${activity.intent.extras} data ${activity.intent.data} cat ${activity.intent.categories}") } override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) { @@ -44,4 +59,27 @@ internal class LifecycleManager( } + override fun onConfigurationChanged(newConfig: Configuration) { + Log.d("______", "onConfigurationChanged") + isConfigurationChanged = true + } + + override fun onLowMemory() { + + } + + override fun onTrimMemory(level: Int) { + + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + fun onAppMovedToBackground() { + Log.d("_______", "App in background $currentActivity action ${currentActivity?.intent?.action} extas ${currentActivity?.intent?.extras} data ${currentActivity?.intent?.data} cat ${currentActivity?.intent?.categories}") + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + fun onAppMovedToForeground() { + Log.d("_______", "App in foreground $currentActivity action ${currentActivity?.intent?.action} extas ${currentActivity?.intent?.extras} data ${currentActivity?.intent?.data} cat ${currentActivity?.intent?.categories}") + } + } From af884b5a70bfb60a5661b69e94a2a10006e5f41c Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Tue, 11 May 2021 18:35:38 +0300 Subject: [PATCH 02/10] Started trackvisit p2 implementation --- .../java/cloud/mindbox/mobile_sdk/Mindbox.kt | 32 +++++--- .../mobile_sdk/managers/LifecycleManager.kt | 73 +++++++++++++------ .../mindbox/mobile_sdk/models/InitData.kt | 13 +++- 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index 4596745a9..8e3eb7219 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -1,5 +1,6 @@ package cloud.mindbox.mobile_sdk +import android.app.Activity import android.app.Application import android.content.Context import androidx.lifecycle.ProcessLifecycleOwner @@ -19,6 +20,11 @@ import java.util.concurrent.TimeUnit object Mindbox { + /** + * Used for determination app open from push + */ + const val IS_OPENED_FROM_PUSH_BUNDLE_KEY = "isOpenedFromPush" + private const val OPERATION_NAME_REGEX = "^[A-Za-z0-9-\\.]{1,249}\$" private val mindboxJob = Job() @@ -162,6 +168,8 @@ object Mindbox { * * @param context used to initialize the main tools * @param configuration contains the data that is needed to connect to the Mindbox + * + * @throws IllegalStateException */ fun init( context: Context, @@ -191,15 +199,12 @@ object Mindbox { updateAppInfo(context) MindboxEventManager.sendEventsIfExist(context) } - sendTrackVisitEvent(context, configuration.endpointId) } // Handle back app in foreground (context.applicationContext as? Application)?.apply { if (!Mindbox::lifecycleManager.isInitialized) { - lifecycleManager = LifecycleManager { - sendTrackVisitEvent(context, configuration.endpointId) - } + lifecycleManager = LifecycleManager(context as? Activity) } else { unregisterComponentCallbacks(lifecycleManager) unregisterActivityLifecycleCallbacks(lifecycleManager) @@ -321,14 +326,22 @@ object Mindbox { }.logOnException() } - private fun sendTrackVisitEvent(context: Context, endpointId: String) { + internal fun sendTrackVisitEvent( + context: Context, + @TrackVisitSource source: String? = null, + requestUrl: String? = null + ) = runCatching { + val applicationContext = context.applicationContext + val endpointId = DbManager.getConfigurations()?.endpointId ?: return val trackVisitData = TrackVisitData( ianaTimeZone = TimeZone.getDefault().id, - endpointId = endpointId + endpointId = endpointId, + source = source, + requestUrl = requestUrl ) - MindboxEventManager.appStarted(context, trackVisitData) - } + MindboxEventManager.appStarted(applicationContext, trackVisitData) + }.logOnException() private fun deliverDeviceUuid(deviceUuid: String) { Executors.newSingleThreadScheduledExecutor().schedule({ @@ -347,4 +360,5 @@ object Mindbox { } }, 1, TimeUnit.SECONDS) } -} \ No newline at end of file + +} diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 731b667e6..74c863bcd 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -3,37 +3,45 @@ package cloud.mindbox.mobile_sdk.managers import android.app.Activity import android.app.Application import android.content.ComponentCallbacks2 +import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.util.Log import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent +import cloud.mindbox.mobile_sdk.Mindbox +import cloud.mindbox.mobile_sdk.Mindbox.IS_OPENED_FROM_PUSH_BUNDLE_KEY +import cloud.mindbox.mobile_sdk.models.DIRECT +import cloud.mindbox.mobile_sdk.models.LINK +import cloud.mindbox.mobile_sdk.models.PUSH internal class LifecycleManager( - private val onAppStarted: () -> Unit + private var currentActivity: Activity? ) : Application.ActivityLifecycleCallbacks, ComponentCallbacks2, LifecycleObserver { - var currentActivity: Activity? = null + companion object { + + private const val SCHEMA_HTTP = "http" + private const val SCHEMA_HTTPS = "https" + + } private var isConfigurationChanged = false + private var isAppInBackground = true override fun onActivityCreated(activity: Activity, p1: Bundle?) { - Log.d("______", "created cur $currentActivity act $activity") + setActivityIfNeeded(activity) } override fun onActivityStarted(activity: Activity) { - Log.d("______", "cur $currentActivity act $activity action ${activity.intent.action} extas ${activity.intent.extras} data ${activity.intent.data} cat ${activity.intent.categories} schema ${activity.intent.scheme}") -activity.intent.scheme - - when { - isConfigurationChanged -> isConfigurationChanged = false - currentActivity?.javaClass?.name == activity.javaClass.name -> { - Log.d("______", "app started") - onAppStarted() - } - else -> currentActivity = activity + if (isConfigurationChanged || isAppInBackground) { + isConfigurationChanged = false + isAppInBackground = false + return } + + sendTrackVisit(activity) + currentActivity = activity } override fun onActivityResumed(activity: Activity) { @@ -45,10 +53,7 @@ activity.intent.scheme } override fun onActivityStopped(activity: Activity) { - if (currentActivity == null) { - currentActivity = activity - } - Log.d("______", "stopped cur $currentActivity act $activity action ${activity.intent.action} extas ${activity.intent.extras} data ${activity.intent.data} cat ${activity.intent.categories}") + setActivityIfNeeded(activity) } override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) { @@ -60,7 +65,6 @@ activity.intent.scheme } override fun onConfigurationChanged(newConfig: Configuration) { - Log.d("______", "onConfigurationChanged") isConfigurationChanged = true } @@ -73,13 +77,36 @@ activity.intent.scheme } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) - fun onAppMovedToBackground() { - Log.d("_______", "App in background $currentActivity action ${currentActivity?.intent?.action} extas ${currentActivity?.intent?.extras} data ${currentActivity?.intent?.data} cat ${currentActivity?.intent?.categories}") + private fun onAppMovedToBackground() { + isConfigurationChanged = false + isAppInBackground = true } @OnLifecycleEvent(Lifecycle.Event.ON_START) - fun onAppMovedToForeground() { - Log.d("_______", "App in foreground $currentActivity action ${currentActivity?.intent?.action} extas ${currentActivity?.intent?.extras} data ${currentActivity?.intent?.data} cat ${currentActivity?.intent?.categories}") + private fun onAppMovedToForeground() { + currentActivity?.let(::sendTrackVisit) + } + + private fun setActivityIfNeeded(activity: Activity) { + if (currentActivity == null) { + currentActivity = activity + } + } + + private fun sendTrackVisit(activity: Activity) { + val intent = activity.intent + val source = source(intent) + val requestUrl = if (source == LINK) intent?.data?.toString() else null + + if (currentActivity?.javaClass?.name == activity.javaClass.name || source != DIRECT) { + Mindbox.sendTrackVisitEvent(activity, source, requestUrl) + } + } + + private fun source(intent: Intent?) = when { + intent?.scheme == SCHEMA_HTTP || intent?.scheme == SCHEMA_HTTPS -> LINK + intent?.extras?.getBoolean(IS_OPENED_FROM_PUSH_BUNDLE_KEY) == true -> PUSH + else -> DIRECT } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/models/InitData.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/models/InitData.kt index 17d8e5c5d..7cdf1f63f 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/models/InitData.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/models/InitData.kt @@ -1,7 +1,13 @@ package cloud.mindbox.mobile_sdk.models +import androidx.annotation.StringDef + private const val INIT_DATA_VERSION = 0 +internal const val DIRECT = "direct" +internal const val LINK = "link" +internal const val PUSH = "push" + internal data class InitData( val token: String, val isTokenAvailable: Boolean, @@ -28,5 +34,10 @@ internal data class TrackClickData( internal data class TrackVisitData( val ianaTimeZone: String, - val endpointId: String + val endpointId: String, + @TrackVisitSource val source: String? = null, + val requestUrl: String? = null ) + +@StringDef(DIRECT, LINK, PUSH) +internal annotation class TrackVisitSource From 061056b686c6da5d44f0567889fd394891b0ade7 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Wed, 12 May 2021 14:45:01 +0300 Subject: [PATCH 03/10] Implemented showing error for incorrect context, handling back to activity and improvements logic for source determination --- sdk/build.gradle | 1 + .../java/cloud/mindbox/mobile_sdk/Mindbox.kt | 55 ++++++++----- .../mobile_sdk/managers/LifecycleManager.kt | 82 ++++++++++--------- .../managers/MindboxEventManager.kt | 12 ++- 4 files changed, 85 insertions(+), 65 deletions(-) diff --git a/sdk/build.gradle b/sdk/build.gradle index 940caa1f5..e91771119 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -142,6 +142,7 @@ dependencies { // dex implementation "androidx.multidex:multidex:2.0.1" + // Handle app lifecycle implementation "androidx.lifecycle:lifecycle-process:2.3.1" } \ No newline at end of file diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index 7f65b09fd..b4dfa469a 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -3,6 +3,7 @@ package cloud.mindbox.mobile_sdk import android.app.Activity import android.app.Application import android.content.Context +import androidx.lifecycle.Lifecycle.State.RESUMED import androidx.lifecycle.ProcessLifecycleOwner import cloud.mindbox.mobile_sdk.logger.Level import cloud.mindbox.mobile_sdk.logger.MindboxLogger @@ -169,8 +170,6 @@ object Mindbox { * * @param context used to initialize the main tools * @param configuration contains the data that is needed to connect to the Mindbox - * - * @throws IllegalStateException */ fun init( context: Context, @@ -196,6 +195,7 @@ object Mindbox { mindboxScope.launch { if (MindboxPreferences.isFirstInitialize) { firstInitialization(context, configuration) + sendTrackVisitEvent(context) } else { updateAppInfo(context) MindboxEventManager.sendEventsIfExist(context) @@ -204,16 +204,33 @@ object Mindbox { // Handle back app in foreground (context.applicationContext as? Application)?.apply { + val applicationLifecycle = ProcessLifecycleOwner.get().lifecycle + if (!Mindbox::lifecycleManager.isInitialized) { - lifecycleManager = LifecycleManager(context as? Activity) + val activity = context as? Activity + if (applicationLifecycle.currentState == RESUMED && activity == null) { + MindboxLogger.e( + this@Mindbox, + "Incorrect context type for calling init in this place" + ) + } + + lifecycleManager = LifecycleManager( + currentActivityName = activity?.javaClass?.name, + currentIntent = activity?.intent, + onTrackVisitReady = { source, requestUrl -> + runBlocking(Dispatchers.IO) { + sendTrackVisitEvent(context, source, requestUrl) + } + } + ) } else { - unregisterComponentCallbacks(lifecycleManager) unregisterActivityLifecycleCallbacks(lifecycleManager) - ProcessLifecycleOwner.get().lifecycle.removeObserver(lifecycleManager) + applicationLifecycle.removeObserver(lifecycleManager) } - registerComponentCallbacks(lifecycleManager) + registerActivityLifecycleCallbacks(lifecycleManager) - ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleManager) + applicationLifecycle.addObserver(lifecycleManager) } }.returnOnException { } } @@ -328,23 +345,21 @@ object Mindbox { }.logOnException() } - internal fun sendTrackVisitEvent( + private fun sendTrackVisitEvent( context: Context, @TrackVisitSource source: String? = null, requestUrl: String? = null ) = runCatching { - runBlocking(Dispatchers.IO) { - val applicationContext = context.applicationContext - val endpointId = DbManager.getConfigurations()?.endpointId ?: return@runBlocking - val trackVisitData = TrackVisitData( - ianaTimeZone = TimeZone.getDefault().id, - endpointId = endpointId, - source = source, - requestUrl = requestUrl - ) - - MindboxEventManager.appStarted(applicationContext, trackVisitData) - } + val applicationContext = context.applicationContext + val endpointId = DbManager.getConfigurations()?.endpointId ?: return + val trackVisitData = TrackVisitData( + ianaTimeZone = TimeZone.getDefault().id, + endpointId = endpointId, + source = source, + requestUrl = requestUrl + ) + + MindboxEventManager.appStarted(applicationContext, trackVisitData) }.logOnException() private fun deliverDeviceUuid(deviceUuid: String) { diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 74c863bcd..ee28ecab9 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -2,46 +2,55 @@ package cloud.mindbox.mobile_sdk.managers import android.app.Activity import android.app.Application -import android.content.ComponentCallbacks2 import android.content.Intent -import android.content.res.Configuration import android.os.Bundle import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent -import cloud.mindbox.mobile_sdk.Mindbox import cloud.mindbox.mobile_sdk.Mindbox.IS_OPENED_FROM_PUSH_BUNDLE_KEY +import cloud.mindbox.mobile_sdk.logger.MindboxLogger import cloud.mindbox.mobile_sdk.models.DIRECT import cloud.mindbox.mobile_sdk.models.LINK import cloud.mindbox.mobile_sdk.models.PUSH internal class LifecycleManager( - private var currentActivity: Activity? -) : Application.ActivityLifecycleCallbacks, ComponentCallbacks2, LifecycleObserver { + private var currentActivityName: String?, + private var currentIntent: Intent?, + private var onTrackVisitReady: (source: String, requestUrl: String?) -> Unit +) : Application.ActivityLifecycleCallbacks, LifecycleObserver { companion object { private const val SCHEMA_HTTP = "http" private const val SCHEMA_HTTPS = "https" + private const val MAX_INTENT_HASHES_SIZE = 50 } - private var isConfigurationChanged = false private var isAppInBackground = true + private var isIntentChanged = true + private val intentHashes = mutableListOf() override fun onActivityCreated(activity: Activity, p1: Bundle?) { - setActivityIfNeeded(activity) + } override fun onActivityStarted(activity: Activity) { - if (isConfigurationChanged || isAppInBackground) { - isConfigurationChanged = false + val areActivitiesEqual = currentActivityName == activity.javaClass.name + val intent = activity.intent + isIntentChanged = if (currentIntent != intent) { + updateActivityParameters(activity) + intent?.hashCode()?.let(::updateHashesList) ?: true + } else { + false + } + + if (isAppInBackground || !isIntentChanged) { isAppInBackground = false return } - sendTrackVisit(activity) - currentActivity = activity + sendTrackVisit(activity.intent, areActivitiesEqual) } override fun onActivityResumed(activity: Activity) { @@ -53,7 +62,9 @@ internal class LifecycleManager( } override fun onActivityStopped(activity: Activity) { - setActivityIfNeeded(activity) + if (currentIntent == null || currentActivityName == null) { + updateActivityParameters(activity) + } } override fun onActivitySaveInstanceState(activity: Activity, p1: Bundle) { @@ -64,42 +75,27 @@ internal class LifecycleManager( } - override fun onConfigurationChanged(newConfig: Configuration) { - isConfigurationChanged = true - } - - override fun onLowMemory() { - - } - - override fun onTrimMemory(level: Int) { - - } - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) private fun onAppMovedToBackground() { - isConfigurationChanged = false isAppInBackground = true } @OnLifecycleEvent(Lifecycle.Event.ON_START) - private fun onAppMovedToForeground() { - currentActivity?.let(::sendTrackVisit) - } + private fun onAppMovedToForeground() = currentIntent?.let(::sendTrackVisit) - private fun setActivityIfNeeded(activity: Activity) { - if (currentActivity == null) { - currentActivity = activity - } + private fun updateActivityParameters(activity: Activity) { + currentActivityName = activity.javaClass.name + currentIntent = activity.intent } - private fun sendTrackVisit(activity: Activity) { - val intent = activity.intent - val source = source(intent) - val requestUrl = if (source == LINK) intent?.data?.toString() else null + private fun sendTrackVisit(intent: Intent, areActivitiesEqual: Boolean = true) { + val source = if (isIntentChanged) source(intent) else DIRECT + + if (areActivitiesEqual || source != DIRECT) { + val requestUrl = if (source == LINK) intent.data?.toString() else null + onTrackVisitReady.invoke(source, requestUrl) - if (currentActivity?.javaClass?.name == activity.javaClass.name || source != DIRECT) { - Mindbox.sendTrackVisitEvent(activity, source, requestUrl) + MindboxLogger.d(this, "Track visit event with source $source and url $requestUrl") } } @@ -109,4 +105,14 @@ internal class LifecycleManager( else -> DIRECT } + private fun updateHashesList(code: Int) = if (!intentHashes.contains(code)) { + if (intentHashes.size >= MAX_INTENT_HASHES_SIZE) { + intentHashes.removeAt(0) + } + intentHashes.add(code) + true + } else { + false + } + } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MindboxEventManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MindboxEventManager.kt index 7687c2485..e781df537 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MindboxEventManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/MindboxEventManager.kt @@ -68,14 +68,12 @@ internal object MindboxEventManager { fun appStarted(context: Context, trackVisitData: TrackVisitData) { runCatching { - runBlocking(Dispatchers.IO) { - DbManager.addEventToQueue( - context, Event( - eventType = EventType.TrackVisit, - body = gson.toJson(trackVisitData) - ) + DbManager.addEventToQueue( + context, Event( + eventType = EventType.TrackVisit, + body = gson.toJson(trackVisitData) ) - } + ) }.logOnException() } From f6852e727c0f460f363d8d3bb7026e3340e8fc70 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Thu, 13 May 2021 17:01:43 +0300 Subject: [PATCH 04/10] Implemented timer --- .../mobile_sdk/managers/LifecycleManager.kt | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index ee28ecab9..a879de2f3 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -8,27 +8,33 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import cloud.mindbox.mobile_sdk.Mindbox.IS_OPENED_FROM_PUSH_BUNDLE_KEY +import cloud.mindbox.mobile_sdk.logOnException import cloud.mindbox.mobile_sdk.logger.MindboxLogger import cloud.mindbox.mobile_sdk.models.DIRECT import cloud.mindbox.mobile_sdk.models.LINK import cloud.mindbox.mobile_sdk.models.PUSH +import java.util.* +import kotlin.concurrent.timer internal class LifecycleManager( - private var currentActivityName: String?, - private var currentIntent: Intent?, - private var onTrackVisitReady: (source: String, requestUrl: String?) -> Unit + private var currentActivityName: String?, + private var currentIntent: Intent?, + private var onTrackVisitReady: (source: String?, requestUrl: String?) -> Unit ) : Application.ActivityLifecycleCallbacks, LifecycleObserver { companion object { private const val SCHEMA_HTTP = "http" private const val SCHEMA_HTTPS = "https" + + private const val TIMER_PERIOD = 60000L//1200000L private const val MAX_INTENT_HASHES_SIZE = 50 } private var isAppInBackground = true private var isIntentChanged = true + private var timer: Timer? = null private val intentHashes = mutableListOf() override fun onActivityCreated(activity: Activity, p1: Bundle?) { @@ -78,10 +84,13 @@ internal class LifecycleManager( @OnLifecycleEvent(Lifecycle.Event.ON_STOP) private fun onAppMovedToBackground() { isAppInBackground = true + cancelKeepAliveTimer() } @OnLifecycleEvent(Lifecycle.Event.ON_START) - private fun onAppMovedToForeground() = currentIntent?.let(::sendTrackVisit) + private fun onAppMovedToForeground() { + currentIntent?.let(::sendTrackVisit) + } private fun updateActivityParameters(activity: Activity) { currentActivityName = activity.javaClass.name @@ -94,6 +103,7 @@ internal class LifecycleManager( if (areActivitiesEqual || source != DIRECT) { val requestUrl = if (source == LINK) intent.data?.toString() else null onTrackVisitReady.invoke(source, requestUrl) + startKeepAliveTimer() MindboxLogger.d(this, "Track visit event with source $source and url $requestUrl") } @@ -115,4 +125,18 @@ internal class LifecycleManager( false } + private fun startKeepAliveTimer() = runCatching { + cancelKeepAliveTimer() + timer = timer( + initialDelay = TIMER_PERIOD, + period = TIMER_PERIOD, + action = { onTrackVisitReady.invoke(null, null) } + ) + }.logOnException() + + private fun cancelKeepAliveTimer() = runCatching { + timer?.cancel() + timer = null + }.logOnException() + } From d6d99c30614272fff0f4816db4c0b2be7163ff95 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Thu, 13 May 2021 18:08:25 +0300 Subject: [PATCH 05/10] Added runCatching --- .../java/cloud/mindbox/mobile_sdk/Mindbox.kt | 6 +- .../mobile_sdk/managers/LifecycleManager.kt | 76 ++++++++++--------- .../managers/SharedPreferencesManager.kt | 24 ++++-- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index b4dfa469a..87ffc2806 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -64,9 +64,9 @@ object Mindbox { /** * Returns date of FMS token saving */ - fun getFmsTokenSaveDate(): String = - runCatching { return MindboxPreferences.firebaseTokenSaveDate } - .returnOnException { "" } + fun getFmsTokenSaveDate(): String = runCatching { + return MindboxPreferences.firebaseTokenSaveDate + }.returnOnException { "" } /** * Returns SDK version diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index ee28ecab9..224eb1f74 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -8,15 +8,17 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import cloud.mindbox.mobile_sdk.Mindbox.IS_OPENED_FROM_PUSH_BUNDLE_KEY +import cloud.mindbox.mobile_sdk.logOnException import cloud.mindbox.mobile_sdk.logger.MindboxLogger import cloud.mindbox.mobile_sdk.models.DIRECT import cloud.mindbox.mobile_sdk.models.LINK import cloud.mindbox.mobile_sdk.models.PUSH +import cloud.mindbox.mobile_sdk.returnOnException internal class LifecycleManager( private var currentActivityName: String?, private var currentIntent: Intent?, - private var onTrackVisitReady: (source: String, requestUrl: String?) -> Unit + private var onTrackVisitReady: (source: String?, requestUrl: String?) -> Unit ) : Application.ActivityLifecycleCallbacks, LifecycleObserver { companion object { @@ -36,21 +38,23 @@ internal class LifecycleManager( } override fun onActivityStarted(activity: Activity) { - val areActivitiesEqual = currentActivityName == activity.javaClass.name - val intent = activity.intent - isIntentChanged = if (currentIntent != intent) { - updateActivityParameters(activity) - intent?.hashCode()?.let(::updateHashesList) ?: true - } else { - false - } - - if (isAppInBackground || !isIntentChanged) { - isAppInBackground = false - return - } - - sendTrackVisit(activity.intent, areActivitiesEqual) + runCatching { + val areActivitiesEqual = currentActivityName == activity.javaClass.name + val intent = activity.intent + isIntentChanged = if (currentIntent != intent) { + updateActivityParameters(activity) + intent?.hashCode()?.let(::updateHashesList) ?: true + } else { + false + } + + if (isAppInBackground || !isIntentChanged) { + isAppInBackground = false + return + } + + sendTrackVisit(activity.intent, areActivitiesEqual) + }.logOnException() } override fun onActivityResumed(activity: Activity) { @@ -83,12 +87,12 @@ internal class LifecycleManager( @OnLifecycleEvent(Lifecycle.Event.ON_START) private fun onAppMovedToForeground() = currentIntent?.let(::sendTrackVisit) - private fun updateActivityParameters(activity: Activity) { + private fun updateActivityParameters(activity: Activity) = runCatching { currentActivityName = activity.javaClass.name currentIntent = activity.intent - } + }.logOnException() - private fun sendTrackVisit(intent: Intent, areActivitiesEqual: Boolean = true) { + private fun sendTrackVisit(intent: Intent, areActivitiesEqual: Boolean = true) = runCatching { val source = if (isIntentChanged) source(intent) else DIRECT if (areActivitiesEqual || source != DIRECT) { @@ -97,22 +101,26 @@ internal class LifecycleManager( MindboxLogger.d(this, "Track visit event with source $source and url $requestUrl") } - } - - private fun source(intent: Intent?) = when { - intent?.scheme == SCHEMA_HTTP || intent?.scheme == SCHEMA_HTTPS -> LINK - intent?.extras?.getBoolean(IS_OPENED_FROM_PUSH_BUNDLE_KEY) == true -> PUSH - else -> DIRECT - } + }.logOnException() - private fun updateHashesList(code: Int) = if (!intentHashes.contains(code)) { - if (intentHashes.size >= MAX_INTENT_HASHES_SIZE) { - intentHashes.removeAt(0) + private fun source(intent: Intent?) = runCatching { + when { + intent?.scheme == SCHEMA_HTTP || intent?.scheme == SCHEMA_HTTPS -> LINK + intent?.extras?.getBoolean(IS_OPENED_FROM_PUSH_BUNDLE_KEY) == true -> PUSH + else -> DIRECT } - intentHashes.add(code) - true - } else { - false - } + }.returnOnException { null } + + private fun updateHashesList(code: Int) = runCatching { + if (!intentHashes.contains(code)) { + if (intentHashes.size >= MAX_INTENT_HASHES_SIZE) { + intentHashes.removeAt(0) + } + intentHashes.add(code) + true + } else { + false + } + }.returnOnException { true } } diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/SharedPreferencesManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/SharedPreferencesManager.kt index dd5b20d94..8061ea2ff 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/SharedPreferencesManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/SharedPreferencesManager.kt @@ -3,6 +3,8 @@ package cloud.mindbox.mobile_sdk.managers import android.app.Application import android.content.Context import android.content.SharedPreferences +import cloud.mindbox.mobile_sdk.logOnException +import cloud.mindbox.mobile_sdk.returnOnException internal object SharedPreferencesManager { @@ -39,7 +41,7 @@ internal object SharedPreferencesManager { fun put( key: String, value: String? - ) = preferences.edit().putString(key, value).apply() + ) = runCatching { preferences.edit().putString(key, value).apply() }.logOnException() /** * Saves [Boolean] into the Preferences. @@ -50,7 +52,7 @@ internal object SharedPreferencesManager { fun put( key: String, value: Boolean - ) = preferences.edit().putBoolean(key, value).apply() + ) = runCatching { preferences.edit().putBoolean(key, value).apply() }.logOnException() /** * Saves [Int] into the Preferences. @@ -61,7 +63,7 @@ internal object SharedPreferencesManager { fun put( key: String, value: Int - ) = preferences.edit().putInt(key, value).apply() + ) = runCatching { preferences.edit().putInt(key, value).apply() }.logOnException() /** * Used to retrieve [String] object from the Preferences. @@ -73,7 +75,9 @@ internal object SharedPreferencesManager { fun getString( key: String, defaultValue: String? = null - ): String? = preferences.getString(key, defaultValue) + ): String? = runCatching { + preferences.getString(key, defaultValue) + }.returnOnException { defaultValue } /** * Used to retrieve [Boolean] object from the Preferences. @@ -85,7 +89,9 @@ internal object SharedPreferencesManager { fun getBoolean( key: String, defaultValue: Boolean = false - ): Boolean = preferences.getBoolean(key, defaultValue) + ): Boolean = runCatching { + preferences.getBoolean(key, defaultValue) + }.returnOnException { defaultValue } /** * Used to retrieve [Int] object from the Preferences. @@ -97,8 +103,12 @@ internal object SharedPreferencesManager { fun getInt( key: String, defaultValue: Int = DEFAULT_INT_VALUE - ): Int = preferences.getInt(key, defaultValue) + ): Int = runCatching { + preferences.getInt(key, defaultValue) + }.returnOnException { defaultValue } - internal fun deleteAll() = preferences.edit().clear().apply() + internal fun deleteAll() = runCatching { + preferences.edit().clear().apply() + }.exceptionOrNull() } From ff4d5931416a518351410cd9b6a41fe27fb742f9 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Thu, 13 May 2021 18:13:48 +0300 Subject: [PATCH 06/10] Corrected timer time --- .../java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 97f266437..c2b67912c 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -28,7 +28,7 @@ internal class LifecycleManager( private const val SCHEMA_HTTP = "http" private const val SCHEMA_HTTPS = "https" - private const val TIMER_PERIOD = 60000L//1200000L + private const val TIMER_PERIOD = 1200000L private const val MAX_INTENT_HASHES_SIZE = 50 } From d1945477603cf9e07391faff7467705e988b6221 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Thu, 10 Jun 2021 22:06:41 +0300 Subject: [PATCH 07/10] Improved trackvisit logic and added lock screen visibility --- .../java/cloud/mindbox/mobile_sdk/Mindbox.kt | 11 ++++++++-- .../mobile_sdk/managers/LifecycleManager.kt | 21 +++++++++++++++---- .../managers/PushNotificationManager.kt | 3 +++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index 12ee42e1f..8952c5a5e 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -198,7 +198,11 @@ object Mindbox { mindboxScope.launch { if (MindboxPreferences.isFirstInitialize) { firstInitialization(context, configuration) - sendTrackVisitEvent(context) + val isTrackVisitNotSent = Mindbox::lifecycleManager.isInitialized + && !lifecycleManager.isTrackVisitSent() + if (isTrackVisitNotSent) { + sendTrackVisitEvent(context, DIRECT) + } } else { updateAppInfo(context) MindboxEventManager.sendEventsIfExist(context) @@ -211,7 +215,8 @@ object Mindbox { if (!Mindbox::lifecycleManager.isInitialized) { val activity = context as? Activity - if (applicationLifecycle.currentState == RESUMED && activity == null) { + val isApplicationResumed = applicationLifecycle.currentState == RESUMED + if (isApplicationResumed && activity == null) { MindboxLogger.e( this@Mindbox, "Incorrect context type for calling init in this place" @@ -221,6 +226,7 @@ object Mindbox { lifecycleManager = LifecycleManager( currentActivityName = activity?.javaClass?.name, currentIntent = activity?.intent, + isAppInBackground = !isApplicationResumed, onTrackVisitReady = { source, requestUrl -> runBlocking(Dispatchers.IO) { sendTrackVisitEvent(context, source, requestUrl) @@ -230,6 +236,7 @@ object Mindbox { } else { unregisterActivityLifecycleCallbacks(lifecycleManager) applicationLifecycle.removeObserver(lifecycleManager) + lifecycleManager.wasReinitialized() } registerActivityLifecycleCallbacks(lifecycleManager) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index c2b67912c..e4b20eb87 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -13,14 +13,15 @@ import cloud.mindbox.mobile_sdk.logger.MindboxLogger import cloud.mindbox.mobile_sdk.models.DIRECT import cloud.mindbox.mobile_sdk.models.LINK import cloud.mindbox.mobile_sdk.models.PUSH +import cloud.mindbox.mobile_sdk.returnOnException import java.util.* import kotlin.concurrent.timer -import cloud.mindbox.mobile_sdk.returnOnException internal class LifecycleManager( private var currentActivityName: String?, private var currentIntent: Intent?, - private var onTrackVisitReady: (source: String?, requestUrl: String?) -> Unit + private var onTrackVisitReady: (source: String?, requestUrl: String?) -> Unit, + private var isAppInBackground: Boolean ) : Application.ActivityLifecycleCallbacks, LifecycleObserver { companion object { @@ -33,11 +34,12 @@ internal class LifecycleManager( } - private var isAppInBackground = true private var isIntentChanged = true private var timer: Timer? = null private val intentHashes = mutableListOf() + private var wasReinitialized = false + override fun onActivityCreated(activity: Activity, p1: Bundle?) { } @@ -84,6 +86,15 @@ internal class LifecycleManager( } + fun isTrackVisitSent(): Boolean { + currentIntent?.let(::sendTrackVisit) + return currentIntent != null + } + + fun wasReinitialized() { + wasReinitialized = true + } + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) private fun onAppMovedToBackground() { isAppInBackground = true @@ -91,8 +102,10 @@ internal class LifecycleManager( } @OnLifecycleEvent(Lifecycle.Event.ON_START) - private fun onAppMovedToForeground() { + private fun onAppMovedToForeground() = if (!wasReinitialized) { currentIntent?.let(::sendTrackVisit) + } else { + wasReinitialized = false } private fun updateActivityParameters(activity: Activity) = runCatching { diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/PushNotificationManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/PushNotificationManager.kt index 641796b4e..786a7fa3c 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/PushNotificationManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/PushNotificationManager.kt @@ -1,6 +1,7 @@ package cloud.mindbox.mobile_sdk.managers import android.app.Notification.DEFAULT_ALL +import android.app.Notification.VISIBILITY_PRIVATE import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent @@ -59,6 +60,7 @@ internal object PushNotificationManager { .setPriority(NotificationCompat.PRIORITY_HIGH) .setDefaults(DEFAULT_ALL) .setAutoCancel(true) + .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) .handlePushClick(context, notificationId, uniqueKey) .handleActions(context, notificationId, uniqueKey, pushActions) .handleImageByUrl(data[DATA_IMAGE_URL], title, description) @@ -82,6 +84,7 @@ internal object PushNotificationManager { val importance = NotificationManager.IMPORTANCE_HIGH val channel = NotificationChannel(channelId, channelName, importance).apply { channelDescription.let { description = it } + lockscreenVisibility = VISIBILITY_PRIVATE } notificationManager.createNotificationChannel(channel) From f89a632fe3351b6ea5bbf1941742984f9a493f17 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Fri, 25 Jun 2021 15:39:30 +0300 Subject: [PATCH 08/10] Added onNewIntent method --- .../main/java/cloud/mindbox/mobile_sdk/Mindbox.kt | 15 +++++++++++++++ .../mobile_sdk/managers/LifecycleManager.kt | 14 ++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt index 8952c5a5e..d44bee451 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/Mindbox.kt @@ -3,6 +3,7 @@ package cloud.mindbox.mobile_sdk import android.app.Activity import android.app.Application import android.content.Context +import android.content.Intent import androidx.lifecycle.Lifecycle.State.RESUMED import androidx.lifecycle.ProcessLifecycleOwner import androidx.annotation.DrawableRes @@ -245,6 +246,20 @@ object Mindbox { }.returnOnException { } } + /** + * Send track visit event after link or push was clicked for [Activity] with launchMode equals + * "singleTop" or "singleTask" or if a client used the [Intent.FLAG_ACTIVITY_SINGLE_TOP] or + * [Intent.FLAG_ACTIVITY_NEW_TASK] + * flag when calling {@link #startActivity}. + * + * @param intent new intent for activity, which was received in [Activity.onNewIntent] method + */ + fun onNewIntent(intent: Intent?) = runCatching { + if (Mindbox::lifecycleManager.isInitialized) { + lifecycleManager.onNewIntent(intent) + } + }.logOnException() + /** * Specifies log level for Mindbox * diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index e4b20eb87..7eee68755 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -38,7 +38,7 @@ internal class LifecycleManager( private var timer: Timer? = null private val intentHashes = mutableListOf() - private var wasReinitialized = false + private var skipSendingTrackVisit = false override fun onActivityCreated(activity: Activity, p1: Bundle?) { @@ -92,7 +92,13 @@ internal class LifecycleManager( } fun wasReinitialized() { - wasReinitialized = true + skipSendingTrackVisit = true + } + + fun onNewIntent(newIntent: Intent?) = newIntent?.let { intent -> + isIntentChanged = true + sendTrackVisit(intent) + skipSendingTrackVisit = true } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) @@ -102,10 +108,10 @@ internal class LifecycleManager( } @OnLifecycleEvent(Lifecycle.Event.ON_START) - private fun onAppMovedToForeground() = if (!wasReinitialized) { + private fun onAppMovedToForeground() = if (!skipSendingTrackVisit) { currentIntent?.let(::sendTrackVisit) } else { - wasReinitialized = false + skipSendingTrackVisit = false } private fun updateActivityParameters(activity: Activity) = runCatching { From 3de857cb47fd1e73a423c09c1b68b47450f663f1 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Tue, 29 Jun 2021 09:36:15 +0300 Subject: [PATCH 09/10] Improved logic for sending trackVisit from onNewIntent --- .../mobile_sdk/managers/LifecycleManager.kt | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 7eee68755..941855b0c 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -96,9 +96,13 @@ internal class LifecycleManager( } fun onNewIntent(newIntent: Intent?) = newIntent?.let { intent -> - isIntentChanged = true - sendTrackVisit(intent) - skipSendingTrackVisit = true + if (currentIntent?.data != intent.data + || !areBundlesEqual(currentIntent?.extras, intent.extras) + ) { + isIntentChanged = updateHashesList(intent.hashCode()) + sendTrackVisit(intent) + skipSendingTrackVisit = true + } } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) @@ -165,4 +169,23 @@ internal class LifecycleManager( timer = null }.logOnException() + private fun areBundlesEqual( + first: Bundle?, + second: Bundle? + ): Boolean = if (first == null || second == null) { + first == second + } else { + first.size() == second.size() && first.keySet().containsAll(second.keySet()) + && first.keySet().all { key -> areItemsEqual(first.get(key), second.get(key)) } + } + + private fun areItemsEqual( + first: Any?, + second: Any? + ) = if (first is Bundle && second is Bundle) { + areBundlesEqual(first, second) + } else { + first == second + } + } From 94a1a5a441e7a2cfd3e5690d7b48d18a2aea0e53 Mon Sep 17 00:00:00 2001 From: Elizaveta Nevostrueva Date: Tue, 29 Jun 2021 15:02:26 +0300 Subject: [PATCH 10/10] Improved logic for sending trackVisit from onNewIntent --- .../mobile_sdk/managers/LifecycleManager.kt | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt index 941855b0c..9fe8a6148 100644 --- a/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt +++ b/sdk/src/main/java/cloud/mindbox/mobile_sdk/managers/LifecycleManager.kt @@ -96,12 +96,10 @@ internal class LifecycleManager( } fun onNewIntent(newIntent: Intent?) = newIntent?.let { intent -> - if (currentIntent?.data != intent.data - || !areBundlesEqual(currentIntent?.extras, intent.extras) - ) { + if (intent.data != null || intent.extras?.get(IS_OPENED_FROM_PUSH_BUNDLE_KEY) == true) { isIntentChanged = updateHashesList(intent.hashCode()) sendTrackVisit(intent) - skipSendingTrackVisit = true + skipSendingTrackVisit = isAppInBackground } } @@ -169,23 +167,4 @@ internal class LifecycleManager( timer = null }.logOnException() - private fun areBundlesEqual( - first: Bundle?, - second: Bundle? - ): Boolean = if (first == null || second == null) { - first == second - } else { - first.size() == second.size() && first.keySet().containsAll(second.keySet()) - && first.keySet().all { key -> areItemsEqual(first.get(key), second.get(key)) } - } - - private fun areItemsEqual( - first: Any?, - second: Any? - ) = if (first is Bundle && second is Bundle) { - areBundlesEqual(first, second) - } else { - first == second - } - }