Skip to main content

Overview

The Synheart Behavior Kotlin/Android SDK provides real-time behavioral signal inference from digital interactions for native Android applications.

Installation

Add to your build.gradle:
dependencies {
    implementation 'ai.synheart:behavior:0.2.0'
}

Requirements

  • Android API 21+ (Android 5.0+)
  • Kotlin 1.9.0+
  • Gradle 8.0+

Quick Start

Basic Usage

import ai.synheart.behavior.*
import android.app.Application
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MyApplication : Application() {
    lateinit var behavior: SynheartBehavior
        private set

    override fun onCreate() {
        super.onCreate()

        val config = BehaviorConfig(
            enableInputSignals = true,
            enableAttentionSignals = true,
            enableMotionLite = true, // Enable motion state inference (LAYING, MOVING, SITTING, STANDING)
        )

        behavior = SynheartBehavior.create(this, config)
        behavior.initialize()
    }
}

class MainActivity : AppCompatActivity() {
    private val behavior by lazy { (application as MyApplication).behavior }
    private var currentSession: BehaviorSession? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Attach to views for gesture tracking
        behavior.attachToView(findViewById(android.R.id.content))

        // Start a session
        startSession()
    }

    private fun startSession() {
        try {
            currentSession = behavior.startSession()
            android.util.Log.d("Behavior", "Session started: ${currentSession?.sessionId}")
        } catch (e: Exception) {
            android.util.Log.e("Behavior", "Failed to start session: $e")
        }
    }
}

Real-Time Event Tracking

// Using callback handler
behavior.setEventHandler { event ->
    android.util.Log.d("Behavior", "Event: ${event.eventType} at ${event.timestamp}")
    android.util.Log.d("Behavior", "Metrics: ${event.metrics}")

    // Handle different event types
    when (event.eventType) {
        BehaviorEventType.SCROLL -> {
            val velocity = event.metrics["velocity"] as? Double
            android.util.Log.d("Behavior", "Scroll velocity: $velocity px/s")
        }
        BehaviorEventType.TAP -> {
            val duration = event.metrics["tap_duration_ms"] as? Int
            android.util.Log.d("Behavior", "Tap duration: $duration ms")
        }
        BehaviorEventType.SWIPE -> {
            val direction = event.metrics["direction"] as? String
            android.util.Log.d("Behavior", "Swipe direction: $direction")
        }
        BehaviorEventType.TYPING -> {
            val speed = event.metrics["typing_speed"] as? Double
            val tapCount = event.metrics["typing_tap_count"] as? Int
            android.util.Log.d("Behavior", "Typing speed: $speed, tap count: $tapCount")
        }
        else -> {}
    }
}

// Or using Kotlin Flow (reactive approach)
import kotlinx.coroutines.flow.collect
import androidx.lifecycle.lifecycleScope

lifecycleScope.launch {
    behavior.onEvent.collect { event ->
        when (event.eventType) {
            BehaviorEventType.SCROLL -> {
                // Handle scroll event
            }
            BehaviorEventType.TYPING -> {
                // Handle typing event
            }
            // ... handle other event types
            else -> {}
        }
    }
}

Session Management

// Start a session
val session = behavior.startSession()
android.util.Log.d("Behavior", "Session started: ${session.sessionId}")

// ... user interacts with app ...

// End session and get summary
val summary = behavior.endSession(session.sessionId)
android.util.Log.d("Behavior", "Session duration: ${summary.durationMs}ms")
android.util.Log.d("Behavior", "Total events: ${summary.activitySummary.totalEvents}")
android.util.Log.d("Behavior", "Focus hint: ${summary.behavioralMetrics.focusHint}")
android.util.Log.d("Behavior", "Distraction score: ${summary.behavioralMetrics.behavioralDistractionScore}")

On-Demand Metrics Calculation

Calculate behavioral metrics for a custom time range within a session:
// Calculate metrics for a specific time range
val metrics = behavior.calculateMetricsForTimeRange(
    startTimestampSeconds = 1767688063,  // Unix timestamp in seconds
    endTimestampSeconds = 1767688130,     // Unix timestamp in seconds
    sessionId = "SESS-1767688063415"      // Optional: uses current session if not provided
)

// Access the calculated metrics
val activitySummary = metrics["activity_summary"] as Map<*, *>
android.util.Log.d("Behavior", "Total events: ${activitySummary["total_events"]}")
android.util.Log.d("Behavior", "App switches: ${activitySummary["app_switch_count"]}")

val behavioralMetrics = metrics["behavioral_metrics"] as Map<*, *>
android.util.Log.d("Behavior", "Interaction intensity: ${behavioralMetrics["interaction_intensity"]}")
android.util.Log.d("Behavior", "Distraction score: ${behavioralMetrics["behavioral_distraction_score"]}")
android.util.Log.d("Behavior", "Focus hint: ${behavioralMetrics["focus_hint"]}")

// Motion state (if motion data is available)
(metrics["motion_state"] as? Map<*, *>)?.let { motionState ->
    android.util.Log.d("Behavior", "Motion state: ${motionState["major_state"]}")
    android.util.Log.d("Behavior", "Confidence: ${motionState["confidence"]}")
}

// Device context
val deviceContext = metrics["device_context"] as Map<*, *>
android.util.Log.d("Behavior", "Screen brightness: ${deviceContext["avg_screen_brightness"]}")
android.util.Log.d("Behavior", "Orientation: ${deviceContext["start_orientation"]}")

// System state
val systemState = metrics["system_state"] as Map<*, *>
android.util.Log.d("Behavior", "Internet: ${systemState["internet_state"]}")
android.util.Log.d("Behavior", "Do not disturb: ${systemState["do_not_disturb"]}")
Note: The time range must be within the session’s start and end times. The SDK automatically validates this and will throw an error if the range is out of bounds.

API Reference

SynheartBehavior

Main Methods:
MethodDescriptionReturns
create(context, config)Create SDK instanceSynheartBehavior
initialize()Initialize SDKvoid
attachToView(view)Attach to view for gesture trackingvoid
startSession({sessionId})Start a new sessionBehaviorSession
endSession(sessionId)End session and get summaryBehaviorSessionSummary
calculateMetricsForTimeRange(...)Calculate metrics for custom time rangeMap<String, Any>
getCurrentStats()Get current statisticsBehaviorStats
setEventHandler(callback)Set callback for eventsvoid
sendEvent(event)Manually send an eventvoid
dispose()Clean up resourcesvoid

calculateMetricsForTimeRange()

Calculate behavioral metrics for a custom time range within a session. Parameters:
ParameterTypeRequiredDescription
startTimestampSecondsLongYesStart time as Unix timestamp in seconds
endTimestampSecondsLongYesEnd time as Unix timestamp in seconds
sessionIdString?NoSession ID (uses current session if not provided)
Returns: Map<String, Any> - Map containing all behavioral metrics for the specified time range Throws: Exception if time range is out of session bounds or session not found Example:
val now = System.currentTimeMillis() / 1000
val fiveMinutesAgo = now - 300

val metrics = behavior.calculateMetricsForTimeRange(
    startTimestampSeconds = fiveMinutesAgo,
    endTimestampSeconds = now
)

// Access metrics
val totalEvents = (metrics["activity_summary"] as Map<*, *>)["total_events"] as Int
val intensity = (metrics["behavioral_metrics"] as Map<*, *>)["interaction_intensity"] as Double
Properties:
PropertyTypeDescription
isInitializedBooleanWhether SDK is initialized
currentSessionIdString?Current active session ID
onEventFlow<BehaviorEvent>Flow of behavioral events

BehaviorConfig

Parameters:
ParameterTypeDefaultDescription
enableInputSignalsBooleantrueEnable scroll, tap, swipe, typing tracking
enableAttentionSignalsBooleantrueEnable app switching, idle gaps
enableMotionLiteBooleanfalseEnable motion state inference
sessionIdPrefixString"SESS"Prefix for session IDs
userIdString?nullOptional user identifier
deviceIdString?nullOptional device identifier
eventBatchSizeInt10Events per batch
maxIdleGapSecondsDouble10.0Max idle time before task drop
behaviorVersionString?nullSDK version for HSI payloads
consentBehaviorBooleantrueBehavior tracking consent

BehaviorEvent

Properties:
PropertyTypeDescription
eventIdStringUnique event identifier
sessionIdStringAssociated session ID
timestampStringISO 8601 timestamp
eventTypeBehaviorEventTypeType of event
metricsMap<String, Any>Event-specific metrics
Event Types:
  • BehaviorEventType.SCROLL - Scroll interactions
  • BehaviorEventType.TAP - Tap interactions
  • BehaviorEventType.SWIPE - Swipe interactions
  • BehaviorEventType.TYPING - Typing session events
  • BehaviorEventType.NOTIFICATION - Notification events
  • BehaviorEventType.CALL - Call events

BehaviorSession

Properties:
PropertyTypeDescription
sessionIdStringSession identifier

BehaviorSessionSummary

Properties:
PropertyTypeDescription
sessionIdStringSession identifier
startAtStringISO 8601 session start time
endAtStringISO 8601 session end time
durationMsLongSession duration in milliseconds
behavioralMetricsBehavioralMetricsBehavioral metrics
activitySummaryActivitySummaryActivity summary
notificationSummaryNotificationSummaryNotification summary
motionStateMotionState?Motion state (if enabled)
typingSessionSummaryTypingSessionSummary?Typing session summary (if typing occurred)
motionDataList<MotionDataPoint>?Raw motion data points (if enabled)

BehavioralMetrics

Properties:
PropertyTypeDescription
interactionIntensityDoubleOverall interaction rate (0-1)
behavioralDistractionScoreDoubleDistraction proxy (0-1)
focusHintDoubleFocus quality proxy (0-1)
deepFocusBlocksList<DeepFocusBlock>Sustained focus periods
taskSwitchRateDoubleApp switching frequency
idleRatioDoubleProportion of idle time
fragmentedIdleRatioDoubleFragmented vs continuous idle
burstinessDoubleTemporal clustering of events
notificationLoadDoubleNotification pressure
scrollJitterRateDoubleScroll pattern irregularity
typingSpeedDoubleAverage typing speed (taps per second)
typingCadenceStabilityDoubleConsistency of typing rhythm (0-1)
typingCadenceVariabilityDoubleVariability in timing between taps
typingActivityRatioDoubleFraction of session with active typing (0-1)
typingGapRatioDoubleProportion of intervals that are gaps (0-1)
typingBurstinessDoubleTemporal clustering of typing events
typingInteractionIntensityDoubleOverall typing engagement (0-1)

Permissions

Notification Permission

// Check if notification listener is enabled
val isEnabled = behavior.checkNotificationListenerEnabled()

if (!isEnabled) {
    // Open system settings to enable notification access
    behavior.requestNotificationListenerAccess()
}

// Check if notification permission is granted (Android 13+)
val hasPermission = behavior.checkNotificationPermission()

if (!hasPermission) {
    // Request permission using Activity.requestPermissions() or ActivityResultContracts
    // After permission is granted, call:
    behavior.hotRestartCollectors()
}

Call Permission

// Check if permission is granted
val hasPermission = behavior.checkCallPermission()

if (!hasPermission) {
    // Request permission using Activity.requestPermissions() or ActivityResultContracts
    // After permission is granted, call:
    behavior.reinitializePhoneStateListener()
}

Configuration

Update Configuration at Runtime

behavior.updateConfig(BehaviorConfig(
    enableInputSignals = true,
    enableAttentionSignals = true,
    enableMotionLite = true,
))
Note: Configuration can only be updated when no session is active.

View Attachment

To track gestures on specific views, attach the SDK to them:
// Attach to a ScrollView
behavior.attachToView(scrollView)

// Attach to a RecyclerView
behavior.attachToView(recyclerView)

// Attach to an Activity's root view
behavior.attachToView(findViewById(android.R.id.content))

Automatic Session Ending

Sessions are automatically ended after 1 minute if the app stays in the background. This prevents sessions from running indefinitely when users switch away from your app.

Resources

For comprehensive documentation, see the full README on GitHub.
Author: Yoseph Gebeyehu