From dcb93933d2da464dd7eec1bc530b251c3ffd7e34 Mon Sep 17 00:00:00 2001 From: Pouria Amini <64161548+PouriaAmini@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:20:49 -0400 Subject: [PATCH] feat: add autocapture in configs (#207) * feat: add autocapture options and deprecate default tracking * feat: track target hierarchy * fix: fix lint * fix: fix a bug that occurs when default tracking options are set after configuration is created * fix: refactor default tracking deprecation * fix: handle changes to defaultTrackingOptions after being assigned to Configuration * fix: fix lint * fix: attach autocapture option to defaultTracking to monitor changes to defaultTracking * fix: remove redundant code * refactor: refactor code to reduce object creation * feat: set autocapture configs as a mutable set of options * fix: fix lint * refactor: refactor to use simple remove and add instead of augmented assignment * refactor: remove redundant code * feat: add experimental annotation to element interactions option * fix: fix failing test * fix: fix failing test * fix: fix failing test * feat: make autocapture options immutable and discard changes to defaultTracking options * fix: fix lint * test: add test for deprecated parameter. * Revert "fix: fix lint" This reverts commit afad03449738d9b451936295495669915be66d4d. * feat: make changes to defaultTracking and trackingSessionEvents effective for autocapture * fix: add a secondary constructor for Configuration to deprecate defaultTracking * fix: fix the bug when a new DefaultTrackingOptions is passed to the Configuration * test: add test for deprecation logic * test: add test for deprecation logic * fix: changes to the default tracking options replace the recent autocapture options entirely. * fix: fix lint --- .../amplitude/android/AutocaptureOptions.kt | 66 ++++++++++ .../com/amplitude/android/Configuration.kt | 113 +++++++++++++++++- .../android/DefaultTrackingOptions.kt | 71 ++++++++--- .../android/ExperimentalAmplitudeFeature.kt | 1 - .../java/com/amplitude/android/Timeline.kt | 4 +- .../amplitude/android/internal/ViewTarget.kt | 1 + .../gestures/AutocaptureGestureListener.kt | 24 ++-- .../locators/AndroidViewTargetLocator.kt | 16 ++- .../locators/ComposeViewTargetLocator.java | 2 +- .../android/plugins/AndroidLifecyclePlugin.kt | 18 +-- .../android/utilities/DefaultEventUtils.kt | 15 ++- .../amplitude/android/AmplitudeSessionTest.kt | 31 ++++- .../com/amplitude/android/AmplitudeTest.kt | 2 +- .../amplitude/android/ConfigurationTest.kt | 107 +++++++++++++++-- .../android/IdentifyInterceptorTest.kt | 1 + .../amplitude/android/ResponseHandlerTest.kt | 2 +- .../AutocaptureGestureListenerClickTest.kt | 38 +++--- .../plugins/AndroidLifecyclePluginTest.kt | 105 +++++++++++++--- ...oidNetworkConnectivityCheckerPluginTest.kt | 2 +- .../android/sample/MainApplication.kt | 9 +- 20 files changed, 524 insertions(+), 104 deletions(-) create mode 100644 android/src/main/java/com/amplitude/android/AutocaptureOptions.kt diff --git a/android/src/main/java/com/amplitude/android/AutocaptureOptions.kt b/android/src/main/java/com/amplitude/android/AutocaptureOptions.kt new file mode 100644 index 00000000..694c498d --- /dev/null +++ b/android/src/main/java/com/amplitude/android/AutocaptureOptions.kt @@ -0,0 +1,66 @@ +package com.amplitude.android + +/** + * Autocapture options to enable or disable specific types of autocapture events. + */ +enum class AutocaptureOption { + /** + * Enable session tracking. + */ + SESSIONS, + /** + * Enable app lifecycle tracking. + */ + APP_LIFECYCLES, + /** + * Enable deep link tracking. + */ + DEEP_LINKS, + /** + * Enable screen view tracking. + */ + SCREEN_VIEWS, + /** + * Enable element interaction tracking. + */ + @ExperimentalAmplitudeFeature + ELEMENT_INTERACTIONS +} + +class AutocaptureOptionsBuilder { + private val options = mutableSetOf() + + operator fun AutocaptureOption.unaryPlus() { + options.add(this) + } + + val sessions = AutocaptureOption.SESSIONS + val appLifecycles = AutocaptureOption.APP_LIFECYCLES + val deepLinks = AutocaptureOption.DEEP_LINKS + val screenViews = AutocaptureOption.SCREEN_VIEWS + @ExperimentalAmplitudeFeature + val elementInteractions = AutocaptureOption.ELEMENT_INTERACTIONS + + fun build(): Set = options.toSet() +} + +/** + * Helper function to create a set of autocapture options. + * + * Example usage: + * ``` + * val options = autocaptureOptions { + * +sessions + * +appLifecycles + * +deepLinks + * +screenViews + * +elementInteractions + * } + * ``` + * + * @param init Function to build the set of autocapture options. + * @return Set of autocapture options. + */ +fun autocaptureOptions(init: AutocaptureOptionsBuilder.() -> Unit): Set { + return AutocaptureOptionsBuilder().apply(init).build() +} diff --git a/android/src/main/java/com/amplitude/android/Configuration.kt b/android/src/main/java/com/amplitude/android/Configuration.kt index dccdf6fe..0e71a02a 100644 --- a/android/src/main/java/com/amplitude/android/Configuration.kt +++ b/android/src/main/java/com/amplitude/android/Configuration.kt @@ -13,7 +13,7 @@ import com.amplitude.core.events.Plan import com.amplitude.id.FileIdentityStorageProvider import com.amplitude.id.IdentityStorageProvider -open class Configuration @JvmOverloads constructor( +open class Configuration( apiKey: String, val context: Context, override var flushQueueSize: Int = FLUSH_QUEUE_SIZE, @@ -39,9 +39,7 @@ open class Configuration @JvmOverloads constructor( var locationListening: Boolean = true, var flushEventsOnClose: Boolean = true, var minTimeBetweenSessionsMillis: Long = MIN_TIME_BETWEEN_SESSIONS_MILLIS, - @Deprecated("Please use 'defaultTracking.sessions' instead.", ReplaceWith("defaultTracking.sessions")) - var trackingSessionEvents: Boolean = true, - var defaultTracking: DefaultTrackingOptions = DefaultTrackingOptions(), + autocapture: Set = setOf(AutocaptureOption.SESSIONS), override var identifyBatchIntervalMillis: Long = IDENTIFY_BATCH_INTERVAL_MILLIS, override var identifyInterceptStorageProvider: StorageProvider = AndroidStorageProvider(), override var identityStorageProvider: IdentityStorageProvider = FileIdentityStorageProvider(), @@ -76,4 +74,111 @@ open class Configuration @JvmOverloads constructor( companion object { const val MIN_TIME_BETWEEN_SESSIONS_MILLIS: Long = 300000 } + + @Deprecated("Please use the 'autocapture' parameter instead.") + @JvmOverloads + constructor( + apiKey: String, + context: Context, + flushQueueSize: Int = FLUSH_QUEUE_SIZE, + flushIntervalMillis: Int = FLUSH_INTERVAL_MILLIS, + instanceName: String = DEFAULT_INSTANCE, + optOut: Boolean = false, + storageProvider: StorageProvider = AndroidStorageProvider(), + loggerProvider: LoggerProvider = AndroidLoggerProvider(), + minIdLength: Int? = null, + partnerId: String? = null, + callback: EventCallBack? = null, + flushMaxRetries: Int = FLUSH_MAX_RETRIES, + useBatch: Boolean = false, + serverZone: ServerZone = ServerZone.US, + serverUrl: String? = null, + plan: Plan? = null, + ingestionMetadata: IngestionMetadata? = null, + useAdvertisingIdForDeviceId: Boolean = false, + useAppSetIdForDeviceId: Boolean = false, + newDeviceIdPerInstall: Boolean = false, + trackingOptions: TrackingOptions = TrackingOptions(), + enableCoppaControl: Boolean = false, + locationListening: Boolean = true, + flushEventsOnClose: Boolean = true, + minTimeBetweenSessionsMillis: Long = MIN_TIME_BETWEEN_SESSIONS_MILLIS, + trackingSessionEvents: Boolean = true, + @Suppress("DEPRECATION") defaultTracking: DefaultTrackingOptions = DefaultTrackingOptions(), + identifyBatchIntervalMillis: Long = IDENTIFY_BATCH_INTERVAL_MILLIS, + identifyInterceptStorageProvider: StorageProvider = AndroidStorageProvider(), + identityStorageProvider: IdentityStorageProvider = FileIdentityStorageProvider(), + migrateLegacyData: Boolean = true, + offline: Boolean? = false, + deviceId: String? = null, + sessionId: Long? = null, + ) : this( + apiKey, + context, + flushQueueSize, + flushIntervalMillis, + instanceName, + optOut, + storageProvider, + loggerProvider, + minIdLength, + partnerId, + callback, + flushMaxRetries, + useBatch, + serverZone, + serverUrl, + plan, + ingestionMetadata, + useAdvertisingIdForDeviceId, + useAppSetIdForDeviceId, + newDeviceIdPerInstall, + trackingOptions, + enableCoppaControl, + locationListening, + flushEventsOnClose, + minTimeBetweenSessionsMillis, + defaultTracking.autocaptureOptions, + identifyBatchIntervalMillis, + identifyInterceptStorageProvider, + identityStorageProvider, + migrateLegacyData, + offline, + deviceId, + sessionId, + ) { + if (!trackingSessionEvents) { + defaultTracking.sessions = false + } + @Suppress("DEPRECATION") + this.defaultTracking = defaultTracking + } + + // A backing property to store the autocapture options. Any changes to `trackingSessionEvents` + // or the `defaultTracking` options will be reflected in this property. + private var _autocapture: MutableSet = autocapture.toMutableSet() + val autocapture: Set get() = _autocapture + + @Deprecated("Please use 'autocapture' instead and set 'AutocaptureOptions.SESSIONS' to enable the option.") + var trackingSessionEvents: Boolean + get() = AutocaptureOption.SESSIONS in _autocapture + set(value) { + if (value) _autocapture.add(AutocaptureOption.SESSIONS) + else _autocapture.remove(AutocaptureOption.SESSIONS) + } + + @Suppress("DEPRECATION") + @Deprecated("Please use 'autocapture' instead", ReplaceWith("autocapture")) + // Any changes to the default tracking options replace the recent autocapture options entirely. + var defaultTracking: DefaultTrackingOptions = DefaultTrackingOptions { updateAutocaptureOnPropertyChange() } + set(value) { + field = value + _autocapture = value.autocaptureOptions + value.addPropertyChangeListener { updateAutocaptureOnPropertyChange() } + } + + @Suppress("DEPRECATION") + private fun DefaultTrackingOptions.updateAutocaptureOnPropertyChange() { + _autocapture = autocaptureOptions + } } diff --git a/android/src/main/java/com/amplitude/android/DefaultTrackingOptions.kt b/android/src/main/java/com/amplitude/android/DefaultTrackingOptions.kt index 297b2209..fca77901 100644 --- a/android/src/main/java/com/amplitude/android/DefaultTrackingOptions.kt +++ b/android/src/main/java/com/amplitude/android/DefaultTrackingOptions.kt @@ -1,20 +1,19 @@ package com.amplitude.android +@Suppress("DEPRECATION") +@Deprecated("Use AutocaptureOption instead") open class DefaultTrackingOptions @JvmOverloads constructor( - var sessions: Boolean = true, - var appLifecycles: Boolean = false, - var deepLinks: Boolean = false, - var screenViews: Boolean = false, + sessions: Boolean = true, + appLifecycles: Boolean = false, + deepLinks: Boolean = false, + screenViews: Boolean = false, ) { - var userInteractions = false - @ExperimentalAmplitudeFeature - set - // Prebuilt options for easier usage companion object { @JvmField + @Deprecated("Use AutocaptureOption instead.") val ALL = DefaultTrackingOptions( sessions = true, @@ -24,6 +23,7 @@ constructor( ) @JvmField + @Deprecated("Use AutocaptureOption instead.") val NONE = DefaultTrackingOptions( sessions = false, @@ -33,14 +33,51 @@ constructor( ) } - @ExperimentalAmplitudeFeature - constructor( - sessions: Boolean = true, - appLifecycles: Boolean = false, - deepLinks: Boolean = false, - screenViews: Boolean = false, - userInteractions: Boolean = false, - ) : this(sessions, appLifecycles, deepLinks, screenViews) { - this.userInteractions = userInteractions + var sessions: Boolean = sessions + set(value) { + field = value + notifyChanged() + } + + var appLifecycles: Boolean = appLifecycles + set(value) { + field = value + notifyChanged() + } + + var deepLinks: Boolean = deepLinks + set(value) { + field = value + notifyChanged() + } + + var screenViews: Boolean = screenViews + set(value) { + field = value + notifyChanged() + } + + private val propertyChangeListeners: MutableList Unit> = mutableListOf() + + internal val autocaptureOptions: MutableSet + get() = mutableSetOf().apply { + if (sessions) add(AutocaptureOption.SESSIONS) + if (appLifecycles) add(AutocaptureOption.APP_LIFECYCLES) + if (deepLinks) add(AutocaptureOption.DEEP_LINKS) + if (screenViews) add(AutocaptureOption.SCREEN_VIEWS) + } + + private fun notifyChanged() { + for (listener in propertyChangeListeners) { + this.listener() + } + } + + internal constructor(listener: (DefaultTrackingOptions.() -> Unit)) : this() { + propertyChangeListeners.add(listener) + } + + internal fun addPropertyChangeListener(listener: DefaultTrackingOptions.() -> Unit) { + propertyChangeListeners.add(listener) } } diff --git a/android/src/main/java/com/amplitude/android/ExperimentalAmplitudeFeature.kt b/android/src/main/java/com/amplitude/android/ExperimentalAmplitudeFeature.kt index 5c4333ac..7b8d31c9 100644 --- a/android/src/main/java/com/amplitude/android/ExperimentalAmplitudeFeature.kt +++ b/android/src/main/java/com/amplitude/android/ExperimentalAmplitudeFeature.kt @@ -5,5 +5,4 @@ package com.amplitude.android "This feature is experimental, and may change or break at any time. Use with caution.", ) @Retention(AnnotationRetention.BINARY) -@Target(AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.CONSTRUCTOR) annotation class ExperimentalAmplitudeFeature diff --git a/android/src/main/java/com/amplitude/android/Timeline.kt b/android/src/main/java/com/amplitude/android/Timeline.kt index 51d80c06..6b50aab9 100644 --- a/android/src/main/java/com/amplitude/android/Timeline.kt +++ b/android/src/main/java/com/amplitude/android/Timeline.kt @@ -137,9 +137,7 @@ class Timeline( private suspend fun startNewSession(timestamp: Long): Iterable { val sessionEvents = mutableListOf() val configuration = amplitude.configuration as Configuration - // If any trackingSessionEvents is false (default value is true), means it is manually set - @Suppress("DEPRECATION") - val trackingSessionEvents = configuration.trackingSessionEvents && configuration.defaultTracking.sessions + val trackingSessionEvents = AutocaptureOption.SESSIONS in configuration.autocapture // end previous session if (trackingSessionEvents && inSession()) { diff --git a/android/src/main/java/com/amplitude/android/internal/ViewTarget.kt b/android/src/main/java/com/amplitude/android/internal/ViewTarget.kt index 05d5ce18..1029b237 100644 --- a/android/src/main/java/com/amplitude/android/internal/ViewTarget.kt +++ b/android/src/main/java/com/amplitude/android/internal/ViewTarget.kt @@ -15,6 +15,7 @@ data class ViewTarget( val resourceName: String?, val tag: String?, val source: String, + val hierarchy: String?, ) { private val viewRef: WeakReference = WeakReference(_view) diff --git a/android/src/main/java/com/amplitude/android/internal/gestures/AutocaptureGestureListener.kt b/android/src/main/java/com/amplitude/android/internal/gestures/AutocaptureGestureListener.kt index 0731cc52..ee8f2b2f 100644 --- a/android/src/main/java/com/amplitude/android/internal/gestures/AutocaptureGestureListener.kt +++ b/android/src/main/java/com/amplitude/android/internal/gestures/AutocaptureGestureListener.kt @@ -7,11 +7,13 @@ import androidx.annotation.VisibleForTesting import com.amplitude.android.internal.ViewHierarchyScanner.findTarget import com.amplitude.android.internal.ViewTarget import com.amplitude.android.internal.locators.ViewTargetLocator -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_CLASS -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_RESOURCE -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_SOURCE -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_TAG -import com.amplitude.android.utilities.DefaultEventUtils.EventTypes.ELEMENT_CLICKED +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ACTION +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.HIERARCHY +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.TARGET_CLASS +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.TARGET_RESOURCE +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.TARGET_SOURCE +import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.TARGET_TAG +import com.amplitude.android.utilities.DefaultEventUtils.EventTypes.ELEMENT_INTERACTED import com.amplitude.common.Logger import java.lang.ref.WeakReference @@ -43,15 +45,17 @@ class AutocaptureGestureListener( ) ?: logger.warn("Unable to find click target. No event captured.").let { return false } mapOf( - ELEMENT_CLASS to target.className, - ELEMENT_RESOURCE to target.resourceName, - ELEMENT_TAG to target.tag, - ELEMENT_SOURCE to + ACTION to "touch", + TARGET_CLASS to target.className, + TARGET_RESOURCE to target.resourceName, + TARGET_TAG to target.tag, + TARGET_SOURCE to target.source .replace("_", " ") .split(" ") .joinToString(" ") { it.replaceFirstChar { c -> c.uppercase() } }, - ).let { track(ELEMENT_CLICKED, it) } + HIERARCHY to target.hierarchy, + ).let { track(ELEMENT_INTERACTED, it) } return false } diff --git a/android/src/main/java/com/amplitude/android/internal/locators/AndroidViewTargetLocator.kt b/android/src/main/java/com/amplitude/android/internal/locators/AndroidViewTargetLocator.kt index ced9b056..460504e8 100644 --- a/android/src/main/java/com/amplitude/android/internal/locators/AndroidViewTargetLocator.kt +++ b/android/src/main/java/com/amplitude/android/internal/locators/AndroidViewTargetLocator.kt @@ -9,6 +9,8 @@ internal class AndroidViewTargetLocator : ViewTargetLocator { private val coordinates = IntArray(2) companion object { + private const val HIERARCHY_DELIMITER = " → " + private const val SOURCE = "android_view" } @@ -24,7 +26,8 @@ internal class AndroidViewTargetLocator : ViewTargetLocator { private fun View.createViewTarget(): ViewTarget { val className = javaClass.canonicalName ?: javaClass.simpleName ?: null val resourceName = resourceIdWithFallback - return ViewTarget(this, className, resourceName, null, SOURCE) + val hierarchy = hierarchy + return ViewTarget(this, className, resourceName, null, SOURCE, hierarchy) } private fun View.touchWithinBounds(position: Pair): Boolean { @@ -43,4 +46,15 @@ internal class AndroidViewTargetLocator : ViewTargetLocator { private fun View.isViewTappable(): Boolean { return isClickable && visibility == View.VISIBLE } + + private val View.hierarchy: String + get() { + val hierarchy = mutableListOf() + var currentView: View? = this + while (currentView != null) { + hierarchy.add(currentView.javaClass.simpleName) + currentView = currentView.parent as? View + } + return hierarchy.joinToString(separator = HIERARCHY_DELIMITER) + } } diff --git a/android/src/main/java/com/amplitude/android/internal/locators/ComposeViewTargetLocator.java b/android/src/main/java/com/amplitude/android/internal/locators/ComposeViewTargetLocator.java index 6e6fcb72..750f6be7 100644 --- a/android/src/main/java/com/amplitude/android/internal/locators/ComposeViewTargetLocator.java +++ b/android/src/main/java/com/amplitude/android/internal/locators/ComposeViewTargetLocator.java @@ -107,7 +107,7 @@ public ViewTarget locate( if (targetTag == null) { return null; } else { - return new ViewTarget(null, null, null, targetTag, SOURCE); + return new ViewTarget(null, null, null, targetTag, SOURCE, null); } } diff --git a/android/src/main/java/com/amplitude/android/plugins/AndroidLifecyclePlugin.kt b/android/src/main/java/com/amplitude/android/plugins/AndroidLifecyclePlugin.kt index ea8e6125..2797f2ec 100644 --- a/android/src/main/java/com/amplitude/android/plugins/AndroidLifecyclePlugin.kt +++ b/android/src/main/java/com/amplitude/android/plugins/AndroidLifecyclePlugin.kt @@ -5,7 +5,9 @@ import android.app.Application import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Bundle +import com.amplitude.android.AutocaptureOption import com.amplitude.android.Configuration +import com.amplitude.android.ExperimentalAmplitudeFeature import com.amplitude.android.utilities.DefaultEventUtils import com.amplitude.core.Amplitude import com.amplitude.core.platform.Plugin @@ -41,18 +43,18 @@ class AndroidLifecyclePlugin : Application.ActivityLifecycleCallbacks, Plugin { } override fun onActivityCreated(activity: Activity, bundle: Bundle?) { - if (!hasTrackedApplicationLifecycleEvents.getAndSet(true) && androidConfiguration.defaultTracking.appLifecycles) { + if (!hasTrackedApplicationLifecycleEvents.getAndSet(true) && AutocaptureOption.APP_LIFECYCLES in androidConfiguration.autocapture) { numberOfActivities.set(0) isFirstLaunch.set(true) DefaultEventUtils(androidAmplitude).trackAppUpdatedInstalledEvent(packageInfo) } - if (androidConfiguration.defaultTracking.deepLinks) { + if (AutocaptureOption.DEEP_LINKS in androidConfiguration.autocapture) { DefaultEventUtils(androidAmplitude).trackDeepLinkOpenedEvent(activity) } } override fun onActivityStarted(activity: Activity) { - if (androidConfiguration.defaultTracking.screenViews) { + if (AutocaptureOption.SCREEN_VIEWS in androidConfiguration.autocapture) { DefaultEventUtils(androidAmplitude).trackScreenViewedEvent(activity) } } @@ -61,25 +63,27 @@ class AndroidLifecyclePlugin : Application.ActivityLifecycleCallbacks, Plugin { androidAmplitude.onEnterForeground(getCurrentTimeMillis()) // numberOfActivities makes sure it only fires after activity creation or activity stopped - if (androidConfiguration.defaultTracking.appLifecycles && numberOfActivities.incrementAndGet() == 1) { + if (AutocaptureOption.APP_LIFECYCLES in androidConfiguration.autocapture && numberOfActivities.incrementAndGet() == 1) { val isFromBackground = !isFirstLaunch.getAndSet(false) DefaultEventUtils(androidAmplitude).trackAppOpenedEvent(packageInfo, isFromBackground) } - if (androidConfiguration.defaultTracking.userInteractions) { + @OptIn(ExperimentalAmplitudeFeature::class) + if (AutocaptureOption.ELEMENT_INTERACTIONS in androidConfiguration.autocapture) { DefaultEventUtils(androidAmplitude).startUserInteractionEventTracking(activity) } } override fun onActivityPaused(activity: Activity) { androidAmplitude.onExitForeground(getCurrentTimeMillis()) - if (androidConfiguration.defaultTracking.userInteractions) { + @OptIn(ExperimentalAmplitudeFeature::class) + if (AutocaptureOption.ELEMENT_INTERACTIONS in androidConfiguration.autocapture) { DefaultEventUtils(androidAmplitude).stopUserInteractionEventTracking(activity) } } override fun onActivityStopped(activity: Activity) { // numberOfActivities makes sure it only fires after setup or activity resumed - if (androidConfiguration.defaultTracking.appLifecycles && numberOfActivities.decrementAndGet() == 0) { + if (AutocaptureOption.APP_LIFECYCLES in androidConfiguration.autocapture && numberOfActivities.decrementAndGet() == 0) { DefaultEventUtils(androidAmplitude).trackAppBackgroundedEvent() } } diff --git a/android/src/main/java/com/amplitude/android/utilities/DefaultEventUtils.kt b/android/src/main/java/com/amplitude/android/utilities/DefaultEventUtils.kt index d96dcc39..f2222cf4 100644 --- a/android/src/main/java/com/amplitude/android/utilities/DefaultEventUtils.kt +++ b/android/src/main/java/com/amplitude/android/utilities/DefaultEventUtils.kt @@ -22,9 +22,7 @@ class DefaultEventUtils(private val amplitude: Amplitude) { const val APPLICATION_BACKGROUNDED = "[Amplitude] Application Backgrounded" const val DEEP_LINK_OPENED = "[Amplitude] Deep Link Opened" const val SCREEN_VIEWED = "[Amplitude] Screen Viewed" - const val ELEMENT_CLICKED = "[Amplitude] Element Clicked" - const val ELEMENT_SCROLLED = "[Amplitude] Element Scrolled" - const val ELEMENT_SWIPED = "[Amplitude] Element Swiped" + const val ELEMENT_INTERACTED = "[Amplitude] Element Interacted" } object EventProperties { @@ -36,11 +34,12 @@ class DefaultEventUtils(private val amplitude: Amplitude) { const val LINK_URL = "[Amplitude] Link URL" const val LINK_REFERRER = "[Amplitude] Link Referrer" const val SCREEN_NAME = "[Amplitude] Screen Name" - const val ELEMENT_CLASS = "[Amplitude] Element Class" - const val ELEMENT_RESOURCE = "[Amplitude] Element Resource" - const val ELEMENT_TAG = "[Amplitude] Element Tag" - const val ELEMENT_SOURCE = "[Amplitude] Element Source" - const val DIRECTION = "[Amplitude] Direction" + const val ACTION = "[Amplitude] Action" + const val TARGET_CLASS = "[Amplitude] Target Class" + const val TARGET_RESOURCE = "[Amplitude] Target Resource" + const val TARGET_TAG = "[Amplitude] Target Tag" + const val TARGET_SOURCE = "[Amplitude] Target Source" + const val HIERARCHY = "[Amplitude] Hierarchy" } fun trackAppUpdatedInstalledEvent(packageInfo: PackageInfo) { diff --git a/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt b/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt index 9e066ccf..967b4d54 100644 --- a/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt +++ b/android/src/test/java/com/amplitude/android/AmplitudeSessionTest.kt @@ -64,7 +64,7 @@ class AmplitudeSessionTest { amplitudeDispatcherField.set(amplitude, dispatcher) } - private fun createConfiguration(storageProvider: StorageProvider? = null): Configuration { + private fun createConfiguration(storageProvider: StorageProvider? = null, shouldTrackSessions: Boolean = true): Configuration { val context = mockk(relaxed = true) var connectivityManager = mockk(relaxed = true) every { context!!.getSystemService(Context.CONNECTIVITY_SERVICE) } returns connectivityManager @@ -75,7 +75,7 @@ class AmplitudeSessionTest { instanceName = "testInstance", minTimeBetweenSessionsMillis = 100, storageProvider = storageProvider ?: InMemoryStorageProvider(), - trackingSessionEvents = true, + autocapture = autocaptureOptions { if (shouldTrackSessions) { +sessions } }, loggerProvider = ConsoleLoggerProvider(), identifyInterceptStorageProvider = InMemoryStorageProvider(), identityStorageProvider = IMIdentityStorageProvider() @@ -553,8 +553,8 @@ class AmplitudeSessionTest { Assertions.assertEquals(1100, event.timestamp) } - @Suppress("DEPRECATION") @Test + @Suppress("DEPRECATION") fun amplitude_noSessionEventsWhenDisabledWithTrackingSessionEvents() = runTest { val configuration = createConfiguration() configuration.trackingSessionEvents = false @@ -580,6 +580,7 @@ class AmplitudeSessionTest { } @Test + @Suppress("DEPRECATION") fun amplitude_noSessionEventsWhenDisabledWithDefaultTrackingOptions() = runTest { val configuration = createConfiguration() configuration.defaultTracking.sessions = false @@ -604,6 +605,30 @@ class AmplitudeSessionTest { Assertions.assertEquals(1, tracks.count()) } + @Test + fun amplitude_noSessionEventsWhenDisabledWithAutocaptureOptions() = runTest { + val configuration = createConfiguration(shouldTrackSessions = false) + val amplitude = Amplitude(configuration) + setDispatcher(amplitude, testScheduler) + + val mockedPlugin = spyk(StubPlugin()) + amplitude.add(mockedPlugin) + + amplitude.isBuilt.await() + + amplitude.track(createEvent(1000, "test event")) + + advanceUntilIdle() + Thread.sleep(100) + + val tracks = mutableListOf() + + verify { + mockedPlugin.track(capture(tracks)) + } + Assertions.assertEquals(1, tracks.count()) + } + private fun createEvent(timestamp: Long, eventType: String, sessionId: Long? = null): BaseEvent { val event = BaseEvent() event.userId = "user" diff --git a/android/src/test/java/com/amplitude/android/AmplitudeTest.kt b/android/src/test/java/com/amplitude/android/AmplitudeTest.kt index 151a8b64..dd72a8c0 100644 --- a/android/src/test/java/com/amplitude/android/AmplitudeTest.kt +++ b/android/src/test/java/com/amplitude/android/AmplitudeTest.kt @@ -88,7 +88,7 @@ class AmplitudeTest { context = context!!, instanceName = instanceName, storageProvider = storageProvider, - trackingSessionEvents = minTimeBetweenSessionsMillis != null, + autocapture = if (minTimeBetweenSessionsMillis != null) setOf(AutocaptureOption.SESSIONS) else setOf(), loggerProvider = ConsoleLoggerProvider(), identifyInterceptStorageProvider = InMemoryStorageProvider(), identityStorageProvider = IMIdentityStorageProvider(), diff --git a/android/src/test/java/com/amplitude/android/ConfigurationTest.kt b/android/src/test/java/com/amplitude/android/ConfigurationTest.kt index 177971af..01fb79d9 100644 --- a/android/src/test/java/com/amplitude/android/ConfigurationTest.kt +++ b/android/src/test/java/com/amplitude/android/ConfigurationTest.kt @@ -33,34 +33,121 @@ class ConfigurationTest { Assertions.assertFalse(configuration.defaultTracking.appLifecycles) Assertions.assertFalse(configuration.defaultTracking.deepLinks) Assertions.assertFalse(configuration.defaultTracking.screenViews) + configuration.trackingSessionEvents = false configuration.defaultTracking.sessions = false configuration.defaultTracking.appLifecycles = true configuration.defaultTracking.deepLinks = true configuration.defaultTracking.screenViews = true + Assertions.assertFalse(configuration.trackingSessionEvents) Assertions.assertFalse(configuration.defaultTracking.sessions) Assertions.assertTrue(configuration.defaultTracking.appLifecycles) Assertions.assertTrue(configuration.defaultTracking.deepLinks) Assertions.assertTrue(configuration.defaultTracking.screenViews) + + Assertions.assertFalse(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) } @Test + @OptIn(ExperimentalAmplitudeFeature::class) fun configuration_defaultTracking_quick_update() { val configuration = Configuration( "test-apikey", context!!, - defaultTracking = DefaultTrackingOptions.ALL + autocapture = autocaptureOptions { + +sessions + +appLifecycles + +deepLinks + +screenViews + +elementInteractions + } ) - Assertions.assertTrue(configuration.defaultTracking.sessions) - Assertions.assertTrue(configuration.defaultTracking.appLifecycles) - Assertions.assertTrue(configuration.defaultTracking.deepLinks) - Assertions.assertTrue(configuration.defaultTracking.screenViews) + Assertions.assertTrue(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.ELEMENT_INTERACTIONS in configuration.autocapture) + } - configuration.defaultTracking = DefaultTrackingOptions.NONE - Assertions.assertFalse(configuration.defaultTracking.sessions) - Assertions.assertFalse(configuration.defaultTracking.appLifecycles) - Assertions.assertFalse(configuration.defaultTracking.deepLinks) - Assertions.assertFalse(configuration.defaultTracking.screenViews) + @Suppress("DEPRECATION") + @Test + fun configuration_defaultTracking_replace_instance() { + val configuration = Configuration( + "test-apikey", + context!!, + autocapture = autocaptureOptions { + +sessions + +appLifecycles + +deepLinks + +screenViews + } + ) + configuration.defaultTracking = DefaultTrackingOptions( + sessions = false, + appLifecycles = true, + deepLinks = false, + screenViews = true + ) + Assertions.assertFalse(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) + } + + @Suppress("DEPRECATION") + @Test + fun configuration_defaultTracking_configuration() { + val configuration = Configuration( + "test-apikey", + context!!, + defaultTracking = DefaultTrackingOptions( + sessions = false, + appLifecycles = true, + deepLinks = false, + screenViews = true + ) + ) + Assertions.assertFalse(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) + } + + @Suppress("DEPRECATION") + @Test + fun configuration_trackingSessionEvents_configuration() { + val configuration = Configuration( + "test-apikey", + context!!, + trackingSessionEvents = false, + ) + Assertions.assertFalse(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) + } + + @Suppress("DEPRECATION") + @Test + fun configuration_defaultTracking_replaces_autocapture_entirely_configuration() { + val configuration = Configuration( + "test-apikey", + context!!, + autocapture = autocaptureOptions { + +sessions + +appLifecycles + +deepLinks + +screenViews + } + ) + configuration.defaultTracking.deepLinks = true + Assertions.assertTrue(AutocaptureOption.SESSIONS in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.APP_LIFECYCLES in configuration.autocapture) + Assertions.assertTrue(AutocaptureOption.DEEP_LINKS in configuration.autocapture) + Assertions.assertFalse(AutocaptureOption.SCREEN_VIEWS in configuration.autocapture) } } diff --git a/android/src/test/java/com/amplitude/android/IdentifyInterceptorTest.kt b/android/src/test/java/com/amplitude/android/IdentifyInterceptorTest.kt index 4f5992d4..cd41f4c1 100644 --- a/android/src/test/java/com/amplitude/android/IdentifyInterceptorTest.kt +++ b/android/src/test/java/com/amplitude/android/IdentifyInterceptorTest.kt @@ -48,6 +48,7 @@ class IdentifyInterceptorTest { val apiKey = "test-api-key" amplitude = Amplitude(apiKey, context) { this.serverUrl = server.url("/").toString() + @Suppress("DEPRECATION") this.trackingSessionEvents = false this.flushIntervalMillis = 1000 this.identifyBatchIntervalMillis = 1000 diff --git a/android/src/test/java/com/amplitude/android/ResponseHandlerTest.kt b/android/src/test/java/com/amplitude/android/ResponseHandlerTest.kt index d65de000..3f5d4643 100644 --- a/android/src/test/java/com/amplitude/android/ResponseHandlerTest.kt +++ b/android/src/test/java/com/amplitude/android/ResponseHandlerTest.kt @@ -45,7 +45,7 @@ class ResponseHandlerTest { apiKey = apiKey, context = context, serverUrl = server.url("/").toString(), - trackingSessionEvents = false, + autocapture = setOf(), flushIntervalMillis = 150, identifyBatchIntervalMillis = 1000, flushMaxRetries = 3, diff --git a/android/src/test/java/com/amplitude/android/internal/gestures/AutocaptureGestureListenerClickTest.kt b/android/src/test/java/com/amplitude/android/internal/gestures/AutocaptureGestureListenerClickTest.kt index 579af01d..e327eb74 100644 --- a/android/src/test/java/com/amplitude/android/internal/gestures/AutocaptureGestureListenerClickTest.kt +++ b/android/src/test/java/com/amplitude/android/internal/gestures/AutocaptureGestureListenerClickTest.kt @@ -10,8 +10,6 @@ import android.view.Window import android.widget.CheckBox import android.widget.RadioButton import com.amplitude.android.internal.locators.AndroidViewTargetLocator -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_CLASS -import com.amplitude.android.utilities.DefaultEventUtils.EventProperties.ELEMENT_RESOURCE import com.amplitude.common.Logger import io.mockk.every import io.mockk.mockk @@ -142,12 +140,14 @@ class AutocaptureGestureListenerClickTest { verify(exactly = 1) { fixture.track( - "[Amplitude] Element Clicked", + "[Amplitude] Element Interacted", mapOf( - "[Amplitude] Element Class" to "android.view.View", - "[Amplitude] Element Resource" to "test_button", - "[Amplitude] Element Tag" to null, - "[Amplitude] Element Source" to "Android View", + "[Amplitude] Action" to "touch", + "[Amplitude] Target Class" to "android.view.View", + "[Amplitude] Target Resource" to "test_button", + "[Amplitude] Target Tag" to null, + "[Amplitude] Target Source" to "Android View", + "[Amplitude] Hierarchy" to "View", ), ) } @@ -168,10 +168,10 @@ class AutocaptureGestureListenerClickTest { verify { fixture.track( - "[Amplitude] Element Clicked", + "[Amplitude] Element Interacted", match { - it["[Amplitude] Element Class"] == "android.widget.RadioButton" && - it["[Amplitude] Element Resource"] == "radio_button" + it["[Amplitude] Target Class"] == "android.widget.RadioButton" && + it["[Amplitude] Target Resource"] == "radio_button" }, ) } @@ -192,10 +192,10 @@ class AutocaptureGestureListenerClickTest { verify { fixture.track( - "[Amplitude] Element Clicked", + "[Amplitude] Element Interacted", match { - it["[Amplitude] Element Class"] == "android.widget.CheckBox" && - it["[Amplitude] Element Resource"] == "check_box" + it["[Amplitude] Target Class"] == "android.widget.CheckBox" && + it["[Amplitude] Target Resource"] == "check_box" }, ) } @@ -242,10 +242,10 @@ class AutocaptureGestureListenerClickTest { verify { fixture.track( - "[Amplitude] Element Clicked", + "[Amplitude] Element Interacted", match { - it["[Amplitude] Element Class"] == decorView.javaClass.canonicalName && - it["[Amplitude] Element Resource"] == "decor_view" + it["[Amplitude] Target Class"] == decorView.javaClass.canonicalName && + it["[Amplitude] Target Resource"] == "decor_view" }, ) } @@ -289,10 +289,10 @@ class AutocaptureGestureListenerClickTest { verify { fixture.track( - "[Amplitude] Element Clicked", + "[Amplitude] Element Interacted", match { - it[ELEMENT_CLASS] == fixture.target.javaClass.simpleName && - it[ELEMENT_RESOURCE] == "test_button" + it["[Amplitude] Target Class"] == fixture.target.javaClass.simpleName && + it["[Amplitude] Target Resource"] == "test_button" }, ) } diff --git a/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt b/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt index 052ebbf3..e80faa44 100644 --- a/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt +++ b/android/src/test/java/com/amplitude/android/plugins/AndroidLifecyclePluginTest.kt @@ -11,6 +11,7 @@ import android.net.ConnectivityManager import android.net.Uri import android.os.Bundle import com.amplitude.android.Amplitude +import com.amplitude.android.AutocaptureOption import com.amplitude.android.Configuration import com.amplitude.android.StubPlugin import com.amplitude.android.utilities.DefaultEventUtils @@ -95,15 +96,25 @@ class AndroidLifecyclePluginTest { loggerProvider = ConsoleLoggerProvider(), identifyInterceptStorageProvider = InMemoryStorageProvider(), identityStorageProvider = IMIdentityStorageProvider(), - trackingSessionEvents = false, + autocapture = setOf() ) amplitude = Amplitude(configuration) } @Test fun `test application installed event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.APP_LIFECYCLES) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -131,7 +142,6 @@ class AndroidLifecyclePluginTest { @Test fun `test application installed event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -152,8 +162,18 @@ class AndroidLifecyclePluginTest { @Test fun `test application updated event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.APP_LIFECYCLES) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -187,7 +207,6 @@ class AndroidLifecyclePluginTest { @Test fun `test application updated event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -212,8 +231,18 @@ class AndroidLifecyclePluginTest { @Test fun `test application opened event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.APP_LIFECYCLES) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -247,7 +276,6 @@ class AndroidLifecyclePluginTest { @Test fun `test application opened event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -270,8 +298,18 @@ class AndroidLifecyclePluginTest { @Test fun `test application backgrounded event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.APP_LIFECYCLES) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.appLifecycles = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -298,7 +336,6 @@ class AndroidLifecyclePluginTest { @Test fun `test application backgrounded event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - (amplitude.configuration as Configuration).defaultTracking.appLifecycles = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -320,8 +357,18 @@ class AndroidLifecyclePluginTest { @Test fun `test screen viewed event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.SCREEN_VIEWS) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.screenViews = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -354,7 +401,6 @@ class AndroidLifecyclePluginTest { @Test fun `test screen viewed event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - configuration.defaultTracking.screenViews = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -381,8 +427,18 @@ class AndroidLifecyclePluginTest { @Test fun `test deep link opened event is tracked`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.DEEP_LINKS) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.deepLinks = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -414,8 +470,18 @@ class AndroidLifecyclePluginTest { @Config(sdk = [21]) @Test fun `test deep link opened event is tracked when using sdk is between 17 and 21`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.DEEP_LINKS) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.deepLinks = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -447,7 +513,6 @@ class AndroidLifecyclePluginTest { @Test fun `test deep link opened event is not tracked when disabled`() = runTest { setDispatcher(testScheduler) - configuration.defaultTracking.deepLinks = false amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) @@ -472,8 +537,18 @@ class AndroidLifecyclePluginTest { @Test fun `test deep link opened event is not tracked when URL is missing`() = runTest { + configuration = Configuration( + apiKey = "api-key", + context = mockedContext, + storageProvider = InMemoryStorageProvider(), + loggerProvider = ConsoleLoggerProvider(), + identifyInterceptStorageProvider = InMemoryStorageProvider(), + identityStorageProvider = IMIdentityStorageProvider(), + autocapture = setOf(AutocaptureOption.DEEP_LINKS) + ) + amplitude = Amplitude(configuration) + setDispatcher(testScheduler) - configuration.defaultTracking.deepLinks = true amplitude.add(androidLifecyclePlugin) val mockedPlugin = spyk(StubPlugin()) diff --git a/android/src/test/java/com/amplitude/android/plugins/AndroidNetworkConnectivityCheckerPluginTest.kt b/android/src/test/java/com/amplitude/android/plugins/AndroidNetworkConnectivityCheckerPluginTest.kt index f7df5d5d..d5c1e1af 100644 --- a/android/src/test/java/com/amplitude/android/plugins/AndroidNetworkConnectivityCheckerPluginTest.kt +++ b/android/src/test/java/com/amplitude/android/plugins/AndroidNetworkConnectivityCheckerPluginTest.kt @@ -31,7 +31,7 @@ class AndroidNetworkConnectivityCheckerPluginTest { loggerProvider = ConsoleLoggerProvider(), identifyInterceptStorageProvider = InMemoryStorageProvider(), identityStorageProvider = IMIdentityStorageProvider(), - trackingSessionEvents = false, + autocapture = setOf() ) ) plugin = AndroidNetworkConnectivityCheckerPlugin() diff --git a/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/MainApplication.kt b/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/MainApplication.kt index 7d318495..4f740235 100644 --- a/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/MainApplication.kt +++ b/samples/kotlin-android-app/src/main/java/com/amplitude/android/sample/MainApplication.kt @@ -3,7 +3,7 @@ package com.amplitude.android.sample import android.app.Application import com.amplitude.android.Amplitude import com.amplitude.android.Configuration -import com.amplitude.android.DefaultTrackingOptions +import com.amplitude.android.autocaptureOptions import com.amplitude.common.Logger import com.amplitude.core.events.BaseEvent import com.amplitude.core.platform.Plugin @@ -25,7 +25,12 @@ class MainApplication : Application() { Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext, - defaultTracking = DefaultTrackingOptions.ALL + autocapture = autocaptureOptions { + +sessions + +appLifecycles + +deepLinks + +screenViews + } ) )