> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Synheart Behavior - Kotlin/Android SDK

> On-device behavioral signal inference for Android applications

## 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`:

```gradle theme={null}
dependencies {
    implementation 'ai.synheart:behavior:0.4.1'
}
```

### Requirements

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

## Quick Start

### Basic Usage

```kotlin theme={null}
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

```kotlin theme={null}
// 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

```kotlin theme={null}
// 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:

```kotlin theme={null}
// 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:**

| Method                              | Description                             | Returns                  |
| ----------------------------------- | --------------------------------------- | ------------------------ |
| `create(context, config)`           | Create SDK instance                     | `SynheartBehavior`       |
| `initialize()`                      | Initialize SDK                          | `void`                   |
| `attachToView(view)`                | Attach to view for gesture tracking     | `void`                   |
| `startSession({sessionId})`         | Start a new session                     | `BehaviorSession`        |
| `endSession(sessionId)`             | End session and get summary             | `BehaviorSessionSummary` |
| `calculateMetricsForTimeRange(...)` | Calculate metrics for custom time range | `Map<String, Any>`       |
| `getCurrentStats()`                 | Get current statistics                  | `BehaviorStats`          |
| `setEventHandler(callback)`         | Set callback for events                 | `void`                   |
| `sendEvent(event)`                  | Manually send an event                  | `void`                   |
| `dispose()`                         | Clean up resources                      | `void`                   |

#### `calculateMetricsForTimeRange()`

Calculate behavioral metrics for a custom time range within a session.

**Parameters:**

| Parameter               | Type      | Required | Description                                       |
| ----------------------- | --------- | -------- | ------------------------------------------------- |
| `startTimestampSeconds` | `Long`    | Yes      | Start time as Unix timestamp in seconds           |
| `endTimestampSeconds`   | `Long`    | Yes      | End time as Unix timestamp in seconds             |
| `sessionId`             | `String?` | No       | Session 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:**

```kotlin theme={null}
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:**

| Property           | Type                  | Description                |
| ------------------ | --------------------- | -------------------------- |
| `isInitialized`    | `Boolean`             | Whether SDK is initialized |
| `currentSessionId` | `String?`             | Current active session ID  |
| `onEvent`          | `Flow<BehaviorEvent>` | Flow of behavioral events  |

### `BehaviorConfig`

**Parameters:**

| Parameter                | Type      | Default | Description                                    |
| ------------------------ | --------- | ------- | ---------------------------------------------- |
| `enableInputSignals`     | `Boolean` | `true`  | Enable scroll, tap, swipe, typing tracking     |
| `enableAttentionSignals` | `Boolean` | `true`  | Enable app switching, idle gaps                |
| `enableMotionLite`       | `Boolean` | `false` | Enable motion state inference                  |
| `sessionIdPrefix`        | `String?` | `null`  | Prefix for session IDs (null = auto-generated) |
| `userId`                 | `String?` | `null`  | Optional user identifier                       |
| `deviceId`               | `String?` | `null`  | Optional device identifier                     |
| `eventBatchSize`         | `Int`     | `10`    | Events per batch                               |
| `maxIdleGapSeconds`      | `Double`  | `10.0`  | Max idle time before task drop                 |
| `behaviorVersion`        | `String?` | `null`  | SDK version for HSI payloads                   |
| `consentBehavior`        | `Boolean` | `true`  | Behavior tracking consent                      |

### `BehaviorEvent`

**Properties:**

| Property    | Type                | Description             |
| ----------- | ------------------- | ----------------------- |
| `eventId`   | `String`            | Unique event identifier |
| `sessionId` | `String`            | Associated session ID   |
| `timestamp` | `String`            | ISO 8601 timestamp      |
| `eventType` | `BehaviorEventType` | Type of event           |
| `metrics`   | `Map<String, Any>`  | Event-specific metrics  |

**Event Types:**

* `BehaviorEventType.SCROLL` - Scroll interactions
* `BehaviorEventType.TAP` - Tap interactions
* `BehaviorEventType.SWIPE` - Swipe interactions
* `BehaviorEventType.APP_SWITCH` - Foreground / background app-switch events
* `BehaviorEventType.NOTIFICATION` - Notification events
* `BehaviorEventType.CALL` - Call events
* `BehaviorEventType.TYPING` - Typing session events (timing only — never characters)
* `BehaviorEventType.CLIPBOARD` - Clipboard activity (copy / paste / cut counts only — never content)

### `BehaviorSession`

**Properties:**

| Property    | Type     | Description        |
| ----------- | -------- | ------------------ |
| `sessionId` | `String` | Session identifier |

### `BehaviorSessionSummary`

**Properties:**

| Property               | Type                     | Description                                 |
| ---------------------- | ------------------------ | ------------------------------------------- |
| `sessionId`            | `String`                 | Session identifier                          |
| `startAt`              | `String`                 | ISO 8601 session start time                 |
| `endAt`                | `String`                 | ISO 8601 session end time                   |
| `durationMs`           | `Long`                   | Session duration in milliseconds            |
| `behavioralMetrics`    | `BehavioralMetrics`      | Behavioral metrics                          |
| `activitySummary`      | `ActivitySummary`        | Activity summary                            |
| `notificationSummary`  | `NotificationSummary`    | Notification summary                        |
| `motionState`          | `MotionState?`           | Motion state (if enabled)                   |
| `typingSessionSummary` | `TypingSessionSummary?`  | Typing session summary (if typing occurred) |
| `motionData`           | `List<MotionDataPoint>?` | Raw motion data points (if enabled)         |

### `BehavioralMetrics`

**Properties:**

| Property                     | Type                   | Description                                  |
| ---------------------------- | ---------------------- | -------------------------------------------- |
| `interactionIntensity`       | `Double`               | Overall interaction rate (0-1)               |
| `behavioralDistractionScore` | `Double`               | Distraction proxy (0-1)                      |
| `focusHint`                  | `Double`               | Focus quality proxy (0-1)                    |
| `deepFocusBlocks`            | `List<DeepFocusBlock>` | Sustained focus periods                      |
| `taskSwitchRate`             | `Double`               | App switching frequency                      |
| `idleRatio`                  | `Double`               | Proportion of idle time                      |
| `fragmentedIdleRatio`        | `Double`               | Fragmented vs continuous idle                |
| `burstiness`                 | `Double`               | Temporal clustering of events                |
| `notificationLoad`           | `Double`               | Notification pressure                        |
| `scrollJitterRate`           | `Double`               | Scroll pattern irregularity                  |
| `typingSpeed`                | `Double`               | Average typing speed (taps per second)       |
| `typingCadenceStability`     | `Double`               | Consistency of typing rhythm (0-1)           |
| `typingCadenceVariability`   | `Double`               | Variability in timing between taps           |
| `typingActivityRatio`        | `Double`               | Fraction of session with active typing (0-1) |
| `typingGapRatio`             | `Double`               | Proportion of intervals that are gaps (0-1)  |
| `typingBurstiness`           | `Double`               | Temporal clustering of typing events         |
| `typingInteractionIntensity` | `Double`               | Overall typing engagement (0-1)              |
| `clipboardActivityRate`      | `Double`               | (copy+paste+cut)/(typing+clipboard)          |
| `correctionRate`             | `Double`               | (backspace+delete)/(typing+backspace+delete) |

### Typing: clipboard and correction rates

The typing session summary includes `clipboardActivityRate` and `correctionRate`, derived from backspace/copy/paste/cut event counts on the SDK. Use **BehaviorEditText** (or wire copy/paste/cut callbacks) so copy/paste/cut are reported. Cut is not counted as backspace.

## Permissions

### Notification Permission

```kotlin theme={null}
// 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

```kotlin theme={null}
// 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

```kotlin theme={null}
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:

```kotlin theme={null}
// 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

* **JitPack**: [synheart-behavior-kotlin](https://jitpack.io/#synheart-ai/synheart-behavior-kotlin)
* **Repository**: [synheart-behavior-kotlin](https://github.com/synheart-ai/synheart-behavior-kotlin)
* **Full README**: [View on GitHub](https://github.com/synheart-ai/synheart-behavior-kotlin#readme)

For comprehensive documentation, see the [full README on GitHub](https://github.com/synheart-ai/synheart-behavior-kotlin#readme).
